diff options
Diffstat (limited to 'chapter16/src/main/java/com/seaofnodes')
7 files changed, 43 insertions, 33 deletions
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/Parser.java b/chapter16/src/main/java/com/seaofnodes/simple/Parser.java index 626f7749..b22bcab7 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/Parser.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/Parser.java @@ -873,8 +873,14 @@ public class Parser { // Sanity check expr for being a reference if( !(expr._type instanceof TypeMemPtr ptr) ) throw error("Expected reference but got " + expr._type.str()); - if( ptr == TypeMemPtr.TOP ) throw error("Accessing field '" + name + "' from null"); - if( ptr._obj == null ) throw error("Accessing unknown field '" + name + "' from '" + ptr.str() + "'"); + + // Happens when parsing known dead code, which often has other typing + // issues. Since the code is dead, possibly due to inlining, lets not + // spoil the user experience with error messages. + if( ctrl()._type==Type.XCONTROL ) + // Exit out via parsing the trailing expression + return matchOpx('=','=') ? parseExpression() : parsePostfix(con(Type.TOP)); + // Sanity check field name for existing TypeMemPtr tmp = (TypeMemPtr)TYPES.get(ptr._obj._name); if( tmp == null ) throw error("Accessing unknown field '" + name + "' from '" + ptr.str() + "'"); @@ -884,31 +890,25 @@ public class Parser { // Get field type and layout offset from base type and field index fidx Field f = base._fields[fidx]; // Field from field index - Node off; - if( name.equals("[]") ) { // If field is an array body - // Array index math - Node idx = require(parseExpression(),"]"); - off = new AddNode(con(base.aryBase()),new ShlNode(idx,con(base.aryScale())).peephole()).peephole(); - } else { // Else normal struct field - // Hardwired field offset - off = con(base.offset(fidx)); - } - if( match("=") ) { - // Disambiguate "obj.fld==x" boolean test from "obj.fld=x" field assignment - if( peek('=') ) _lexer._position--; - else { - Node val = parseExpression(); - // Auto-truncate when storing to narrow fields - val = zsMask(val,f._type); - Node st = new StoreNode(name, f._alias, f._type, memAlias(f._alias), expr, off, val, false); - // Arrays include control, as a proxy for a safety range check. - // Structs don't need this; they only need a NPE check which is - // done via the type system. - if( base.isAry() ) st.setDef(0,ctrl()); - memAlias(f._alias, st.peephole()); - return val; // "obj.a = expr" returns the expression while updating memory - } + Node off = name.equals("[]") // If field is an array body + // Array index math + ? new AddNode(con(base.aryBase()),new ShlNode(require(parseExpression(),"]"),con(base.aryScale())).peephole()).peephole() + // Struct field offsets are hardwired + : con(base.offset(fidx)); + + // Disambiguate "obj.fld==x" boolean test from "obj.fld=x" field assignment + if( matchOpx('=','=') ) { + Node val = parseExpression(); + // Auto-truncate when storing to narrow fields + val = zsMask(val,f._type); + Node st = new StoreNode(name, f._alias, f._type, memAlias(f._alias), expr, off, val, false); + // Arrays include control, as a proxy for a safety range check. + // Structs don't need this; they only need a NPE check which is + // done via the type system. + if( base.isAry() ) st.setDef(0,ctrl()); + memAlias(f._alias, st.peephole()); + return val; // "obj.a = expr" returns the expression while updating memory } Node load = new LoadNode(name, f._alias, f._type.glb(), memAlias(f._alias), expr, off); @@ -959,6 +959,7 @@ public class Parser { private boolean match (String syntax) { return _lexer.match (syntax); } // Match must be "exact", not be followed by more id letters private boolean matchx(String syntax) { return _lexer.matchx(syntax); } + private boolean matchOpx(char c0, char c1) { return _lexer.matchOpx(c0,c1); } // Return true and do NOT skip if 'ch' is next private boolean peek(char ch) { return _lexer.peek(ch); } private boolean peekIsId() { return _lexer.peekIsId(); } @@ -1078,6 +1079,13 @@ public class Parser { _position -= syntax.length(); return false; } + boolean matchOpx(char c0, char c1) { + skipWhiteSpace(); + if( _position+1 >= _input.length || _input[_position]!=c0 || _input[_position+1]==c1 ) + return false; + _position++; + return true; + } private boolean peek(char ch) { skipWhiteSpace(); diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/IfNode.java index 5457ac6e..3cce89ab 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/node/IfNode.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/node/IfNode.java @@ -41,8 +41,8 @@ public class IfNode extends CFGNode implements MultiNode { return TypeTuple.IF_NEITHER; // If constant is 0 then false branch is reachable // Else true branch is reachable - if (t instanceof TypeInteger ti && ti.isConstant()) - return ti==TypeInteger.ZERO ? TypeTuple.IF_FALSE : TypeTuple.IF_TRUE; + if( t.isConstant() ) + return t.makeInit()==t ? TypeTuple.IF_FALSE : TypeTuple.IF_TRUE; return TypeTuple.IF_BOTH; } diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/LoadNode.java index c4abed12..d15d4f83 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/node/LoadNode.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/node/LoadNode.java @@ -74,8 +74,8 @@ public class LoadNode extends MemOpNode { // Pointers cannot overlap mem = st.mem(); // Proved never equal break; - case PhiNode phi: - break outer; // Assume related + case PhiNode phi: break outer; // Assume related + case ConstantNode top: break outer; // Assume shortly dead case ProjNode mproj: if( mproj.in(0) instanceof NewNode nnn1 ) { if( ptr instanceof ProjNode pproj && pproj.in(0) == mproj.in(0) ) diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/NewNode.java index 1e6d2baa..ddb1e09a 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/node/NewNode.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/node/NewNode.java @@ -27,7 +27,7 @@ public class NewNode extends Node implements MultiNode { // Memory slices for all fields. assert nodes[2+ i]._type instanceof TypeMem; // Value slices for all fields. - assert nodes[2+_len+i]._type instanceof Type; + assert nodes[2 + _len + i]._type != null; } } diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/PhiNode.java index 139e80a3..f0140ce6 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/node/PhiNode.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/node/PhiNode.java @@ -43,7 +43,7 @@ public class PhiNode extends Node { @Override public Type compute() { if( !(region() instanceof RegionNode r) ) - return region()._type==Type.XCONTROL ? Type.TOP : _type; + return region()._type==Type.XCONTROL ? (_type instanceof TypeMem ? TypeMem.TOP : Type.TOP) : _type; // During parsing Phis have to be computed type pessimistically. if( r.inProgress() ) return _declaredType; // Set type to local top of the starting type diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/ScopeMinNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/ScopeMinNode.java index 48f81ddb..e4874e15 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/node/ScopeMinNode.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/node/ScopeMinNode.java @@ -13,7 +13,7 @@ public class ScopeMinNode extends Node { /** The tracked fields are now complex enough to deserve a array-of-structs layout */ - public class Var { + public static class Var { public final int _idx; public final String _name; public final Type _type; diff --git a/chapter16/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java b/chapter16/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java index 8b484235..ec059b8f 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java @@ -61,6 +61,8 @@ public class TypeMemPtr extends Type { @Override public Type nonZero() { return VOIDPTR; } @Override public boolean isHigh() { return this==TOP; } + @Override public boolean isConstant() { return this==NULLPTR; } + @Override public boolean isHighOrConst() { return this==TOP || this==NULLPTR; } @Override public int log_size() { return 2; } // (1<<2)==4-byte pointers |
