/* * Copyright 2013 Guidewire Software, Inc. */ package gw.internal.gosu.parser; import java.util.HashMap; import java.util.Map; import gw.lang.GosuShop; import gw.lang.parser.ISymbolTable; import gw.lang.parser.StandardSymbolTable; import gw.lang.parser.ThreadSafeSymbolTable; import gw.lang.reflect.TypeSystem; import gw.lang.reflect.TypeSystemShutdownListener; import gw.lang.reflect.gs.ICompilableType; import gw.util.Stack; import gw.util.concurrent.LockingLazyVar; /** * */ public class CompiledGosuClassSymbolTable extends ThreadSafeSymbolTable { private static final LockingLazyVar<CompiledGosuClassSymbolTable> INSTANCE = new LockingLazyVar<CompiledGosuClassSymbolTable>() { protected CompiledGosuClassSymbolTable init() { return new CompiledGosuClassSymbolTable(); } }; private static final ThreadLocal<Stack> SYM_TABLE_STACK = new ThreadLocal<Stack>(); private static final ThreadLocal<Stack> SYM_TABLE_TRACE_STACK = new ThreadLocal<Stack>(); private static final ThreadLocal<Map<ICompilableType, ISymbolTable>> MAP_SYM_TABLE_BY_TYPE = new ThreadLocal<Map<ICompilableType, ISymbolTable>>(); private static final boolean DEBUG = false; //enables collection of sym stack push traces static { TypeSystem.addShutdownListener(new TypeSystemShutdownListener() { public void shutdown() { INSTANCE.clear(); GosuShop.clearThreadLocal(SYM_TABLE_STACK); GosuShop.clearThreadLocal(SYM_TABLE_TRACE_STACK); GosuShop.clearThreadLocal(MAP_SYM_TABLE_BY_TYPE); } }); } public static CompiledGosuClassSymbolTable instance() { return INSTANCE.get(); } CompiledGosuClassSymbolTable() { super( true ); } public static ISymbolTable getSymTableCtx() { Stack stack = getSymbolTableStack(); if( stack.size() > 0 ) { return (ISymbolTable)stack.peek(); } return null; } public static void pushSymTableCtx( ISymbolTable ctx ) { Stack stack = getSymbolTableStack(); stack.push( ctx ); if( DEBUG ) { Stack traceStack = getSymbolTableTraceStack(); traceStack.push( new RuntimeException( "MARKER" ) ); } } public static ISymbolTable popSymTableCtx() { Stack stack = getSymbolTableStack(); ISymbolTable symTable = (ISymbolTable)stack.pop(); assert stack.size() > 0 : "Must always be at least one thread local symbol table"; if( DEBUG ) { getSymbolTableTraceStack().pop(); } return symTable; } public ISymbolTable getSymbolTableForCompilingClass( ICompilableType gsClass ) { return getClassMap().get( gsClass ); } public void pushCompileTimeSymbolTable( ICompilableType gsClass ) { pushCompileTimeSymbolTable( gsClass, instance() ); } public void pushCompileTimeSymbolTable( ICompilableType gsClass, ISymbolTable symTable ) { TypeSystem.pushModule( gsClass.getTypeLoader().getModule() ); pushCompileTimeSymbolTable( symTable ); if( getClassMap().containsKey( gsClass ) ) { throw new IllegalStateException( "Already compiling class " + gsClass.getName() ); } getClassMap().put( gsClass, (ISymbolTable)getSymbolTableStack().peek() ); } public void pushCompileTimeSymbolTable() { pushCompileTimeSymbolTable( new StandardSymbolTable( true ) ); } public void pushCompileTimeSymbolTable( ISymbolTable symTable ) { // push on a clean symbol table for parsing pushSymTableCtx( symTable == this ? new StandardSymbolTable( true ) : symTable ); } public void popCompileTimeSymbolTable( ICompilableType gsClass ) { popCompileTimeSymbolTable(); TypeSystem.popModule( gsClass.getTypeLoader().getModule() ); } public void popCompileTimeSymbolTable() { ISymbolTable symTable = popSymTableCtx(); Map<ICompilableType, ISymbolTable> map = getClassMap(); for( ICompilableType gsClass : map.keySet() ) { if( map.get( gsClass ) == symTable ) { map.remove( gsClass ); break; } } } protected ISymbolTable getThreadLocalSymbolTable() { ISymbolTable symTableCtx = getSymTableCtx(); if( symTableCtx == this ) { return null; } else { return symTableCtx; } } private static Stack getSymbolTableStack() { Stack stack = SYM_TABLE_STACK.get(); if( stack == null ) { stack = new Stack(); stack.push( new StandardSymbolTable( true ) ); SYM_TABLE_STACK.set( stack ); } return stack; } private static Map<ICompilableType, ISymbolTable> getClassMap() { Map<ICompilableType, ISymbolTable> map = MAP_SYM_TABLE_BY_TYPE.get(); if( map == null ) { map = new HashMap<ICompilableType, ISymbolTable>( 8 ); MAP_SYM_TABLE_BY_TYPE.set( map ); } return map; } public static Stack getSymbolTableTraceStack() { Stack stack = SYM_TABLE_TRACE_STACK.get(); if( stack == null ) { stack = new Stack(); SYM_TABLE_TRACE_STACK.set( stack ); } return stack; } }