diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java index 7cf0202..9f43261 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/Compiler.java @@ -60,7 +60,7 @@ public class Compiler { // Mapping from a type name to a Type. The string name matches // `type.str()` call. No TypeMemPtrs are in here, because Simple does not // have C-style '*ptr' references. - public static HashMap TYPES = new HashMap<>(); + private final HashMap types = new HashMap<>(); private ArrayList ctorStack = new ArrayList<>(); @@ -70,10 +70,9 @@ public Compiler(CodeGen codeGen, TypeInteger arg) { public void parse() { this.typeDictionary = createAST(_code._src); - Map types = new HashMap<>(); + types.clear(); populateDefaultTypes(types); populateTypes(types); - TYPES.putAll(types); ZERO = con(TypeInteger.ZERO).keep(); NIL = con(Type.NIL).keep(); XCTRL= new XCtrlNode().peephole().keep(); @@ -269,7 +268,7 @@ private void defineScopedVars(Scope scope, ScopeNode scopeNode, FunNode fun) { for (Symbol symbol: scope.getLocalSymbols()) { if (symbol instanceof Symbol.VarSymbol varSymbol) { varSymbol.regNumber = REGNUM++; - Type sonType = TYPES.get(varSymbol.type.name()); + Type sonType = types.get(varSymbol.type.name()); if (sonType == null) throw new CompilerException("Unknown SON Type "+varSymbol.type.name()); Node init = null; @@ -290,7 +289,7 @@ private void generateFunction(Symbol.FunctionTypeSymbol functionTypeSymbol) { ctrl(XCTRL); _scope.mem(new MemMergeNode(false)); - var funType = (TypeFunPtr) TYPES.get(functionTypeSymbol.name); + var funType = (TypeFunPtr) types.get(functionTypeSymbol.name); if (funType == null) throw new CompilerException("Function " + functionTypeSymbol.name + " not found"); // Parse whole program, as-if function header "{ int arg -> body }" @@ -612,11 +611,11 @@ private Node newStruct(TypeStruct obj, Node size) { private Node compileNewExpr(AST.NewExpr newExpr) { EZType type = newExpr.type; if (type instanceof EZType.EZTypeArray typeArray) { - TypeMemPtr tarray = (TypeMemPtr) TYPES.get(typeArray.name()); + TypeMemPtr tarray = (TypeMemPtr) types.get(typeArray.name()); return newArray(tarray._obj,newExpr.len==null?ZERO:compileExpr(newExpr.len)); } else if (type instanceof EZType.EZTypeStruct typeStruct) { - TypeMemPtr tptr = (TypeMemPtr) TYPES.get(typeStruct.name()); + TypeMemPtr tptr = (TypeMemPtr) types.get(typeStruct.name()); return newStruct(tptr._obj,con(tptr._obj.offset(tptr._obj._fields.length))); } else @@ -703,7 +702,7 @@ else if (constantExpr.type instanceof EZType.EZTypeNull) private Node compileSymbolExpr(AST.NameExpr symbolExpr) { if (symbolExpr.type instanceof EZType.EZTypeFunction functionType) - return con(TYPES.get(functionType.name)); + return con(types.get(functionType.name)); else { Symbol.VarSymbol varSymbol = (Symbol.VarSymbol) symbolExpr.symbol; Var v = _scope.lookup(makeVarName(varSymbol)); diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/Var.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/Var.java index 4f1bf8b..f48b8f1 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/Var.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/Var.java @@ -2,7 +2,6 @@ import com.compilerprogramming.ezlang.compiler.type.*; - /** * The tracked fields are now complex enough to deserve a array-of-structs layout */ @@ -27,10 +26,8 @@ public Var(int idx, String name, Type type, boolean xfinal, boolean fref) { _fref = fref; } public Type type() { - if( !_type.isFRef() ) return _type; - // Update self to no longer use the forward ref type - Type def = Compiler.TYPES.get(((TypeMemPtr)_type)._obj._name); - return (_type=_type.meet(def)); + assert !_type.isFRef(); + return _type; } // Forward reference variables (not types) must be BOTTOM and diff --git a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/CodeGen.java b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/CodeGen.java index b00aaf6..b0b4ac7 100644 --- a/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/CodeGen.java +++ b/seaofnodes/src/main/java/com/compilerprogramming/ezlang/compiler/codegen/CodeGen.java @@ -43,6 +43,7 @@ public enum Phase { // --------------------------- public CodeGen( String src ) { this(src, TypeInteger.BOT, 123L ); } public CodeGen( String src, TypeInteger arg, long workListSeed ) { + Type.resetInternTable(); CODE = this; _phase = null; _callingConv = null; @@ -51,6 +52,7 @@ public CodeGen( String src, TypeInteger arg, long workListSeed ) { _src = src; _arg = arg; _iter = new IterPeeps(workListSeed); + _main = makeFun(TypeTuple.MAIN, Type.BOTTOM); P = new Compiler(this,arg); } @@ -141,7 +143,7 @@ public TypeFunPtr makeFun2(TypeTuple sig, Type ret ) { return new TypeFunPtr((byte)2,sig,ret, 1L< INTERN_BASELINE; + + /** + * Call this at the start of each front-end compilation + * run to reset the intern table to core types that the SoN backend + * needs. The reset drops any types added by a previous + * compile run. + */ + public static void resetInternTable() { + if( INTERN_BASELINE == null ) { + gather(); + INTERN_BASELINE = new HashMap<>(INTERN); + } else { + INTERN.clear(); + INTERN.putAll(INTERN_BASELINE); + } + } + // Is high or on the lattice centerline. public boolean isHigh () { return _type==TTOP || _type==TXCTRL || _type==TXNIL; } public boolean isHighOrConst() { return isHigh() || isConstant(); } diff --git a/seaofnodes/src/test/java/com/compilerprogramming/ezlang/compiler/TestSONTypes.java b/seaofnodes/src/test/java/com/compilerprogramming/ezlang/compiler/TestSONTypes.java index 131f5ec..b2166ae 100644 --- a/seaofnodes/src/test/java/com/compilerprogramming/ezlang/compiler/TestSONTypes.java +++ b/seaofnodes/src/test/java/com/compilerprogramming/ezlang/compiler/TestSONTypes.java @@ -170,6 +170,24 @@ func foo()->Int { compileSrc(src); } + @Test + public void testStructLayoutsDoNotLeakAcrossCompilations() { + compileSrc(""" +struct Point { var x: Int } +func foo()->Int { + var p = new Point { x = 1 } + return p.x +} +"""); + compileSrc(""" +struct Point { var y: Int } +func foo()->Int { + var p = new Point { y = 2 } + return p.y +} +"""); + } + @Ignore("Bug in backend") @Test public void testArrayLoadNullCheckNarrowsNullableElement() {