summaryrefslogtreecommitdiff
path: root/chapter25/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'chapter25/src/main/java')
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/Parser.java37
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/codegen/ElfWriter.java19
-rw-r--r--chapter25/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java30
3 files changed, 58 insertions, 28 deletions
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/Parser.java b/chapter25/src/main/java/com/seaofnodes/simple/Parser.java
index 4c2dfc84..e964fa5b 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/Parser.java
@@ -1450,8 +1450,10 @@ public class Parser {
// Make an array type of t. Always record a mutable version,
// but return the requested version.
private TypeStruct typeAry( Type t, boolean efinal ) {
- if( t instanceof TypeMemPtr tmp && tmp.notNull() )
- throw error("Arrays of reference types must always be nullable");
+ // Non-null reference arrays are valid types, even though an ordinary
+ // zero-filled `new T[len]` cannot construct one. Allocation retains
+ // that check in alloc(); trusted runtimes (notably argv construction)
+ // may fill the private array completely before publishing it.
String tname = ("[]"+t.str()).intern();
TypeStruct ta = (TypeStruct)TYPES.get(tname);
if( ta==null ) {
@@ -2406,22 +2408,33 @@ public class Parser {
}
if( _lexer.isEOF() )
throw error("Unclosed string");
- char esc = _lexer.nextChar();
- sb.append(switch( esc ) {
- case 'n' -> '\n';
- case 't' -> '\t';
- case 'r' -> '\r';
- case '\\' -> '\\';
- case '"' -> '"';
- default -> throw error("Unknown string escape \\\\"+esc);
- });
+ sb.append(escapedChar("string"));
}
throw error("Unclosed string");
}
+ private char escapedChar(String kind) {
+ char esc = _lexer.nextChar();
+ return switch( esc ) {
+ case 'n' -> '\n';
+ case 't' -> '\t';
+ case 'r' -> '\r';
+ case '\\' -> '\\';
+ case '"' -> '"';
+ case '\'' -> '\'';
+ default -> throw error("Unknown "+kind+" escape \\\\"+esc);
+ };
+ }
+
// Already parsed "'"
private Node parseChar() {
- return require(con(TypeInteger.constant(_lexer.nextChar())),"'");
+ if( _lexer.isEOF() ) throw error("Unclosed character");
+ char c = _lexer.nextChar();
+ if( c=='\\' ) {
+ if( _lexer.isEOF() ) throw error("Unclosed character");
+ c = escapedChar("character");
+ }
+ return require(con(TypeInteger.constant(c)),"'");
}
private boolean noLowerCase(String s) {
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/codegen/ElfWriter.java b/chapter25/src/main/java/com/seaofnodes/simple/codegen/ElfWriter.java
index 508cdcca..274be838 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/codegen/ElfWriter.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/codegen/ElfWriter.java
@@ -182,7 +182,7 @@ public class ElfWriter {
// creates function and stores where it starts.
// Filters to just this class.obj file.
- void encodeFunctions(StopNode stop, Encoding enc, int text_idx) {
+ void encodeFunctions(StopNode stop, Encoding enc, int text_idx, boolean emitEntrySymbol) {
for( Node stopcu : stop._inputs ) {
for( Node ret : stopcu._inputs ) {
FunNode fun = ((ReturnNode)ret).fun();
@@ -191,8 +191,15 @@ public class ElfWriter {
int end = enc.opStart(fun.ret()) + enc.opLen(fun.ret());
long value = enc.opStart(fun);
long size = end - value;
- if( fun._name != null ) // Anonymous functions have no name
- symbol(fun._name, text_idx, SYM_BIND_GLOBAL, SYM_TYPE_FUNC, value, size);
+ if( fun._name != null ) { // Anonymous functions have no name
+ // The C runtime owns `main` and adapts argc/argv into
+ // a normal Simple array. Keep the Simple function on
+ // its native ABI under a private entry symbol.
+ String name = emitEntrySymbol && "main".equals(fun._name)
+ ? "simple_main"
+ : fun._name;
+ symbol(name, text_idx, SYM_BIND_GLOBAL, SYM_TYPE_FUNC, value, size);
+ }
}
}
}
@@ -205,14 +212,14 @@ public class ElfWriter {
for( FunNode fun : _code._linker )
if( fun != null && _code.owns(fun) ) {
if( "main".equals(fun._name) )
- return; // Top-level declared a main, take the existing one
+ return; // encodeFunctions exported this as simple_main
if( entryName.equals(fun._name) )
clinit = fun; // Keep top-level entry, if we don't find an explicit main
}
// No top-level main, so the top-level clinit becomes a default main
if( clinit != null ) {
assert enc.opStart(clinit) == 0;
- symbol("main",text_idx, SYM_BIND_GLOBAL, SYM_TYPE_FUNC, enc.opStart(clinit), 0);
+ symbol("simple_main",text_idx, SYM_BIND_GLOBAL, SYM_TYPE_FUNC, enc.opStart(clinit), 0);
return;
}
throw new IllegalStateException("Missing entry <clinit> "+entryName);
@@ -293,7 +300,7 @@ public class ElfWriter {
// populate function symbols
- symbols.encodeFunctions(_code._stop, _code._encoding, text._index);
+ symbols.encodeFunctions(_code._stop, _code._encoding, text._index, emitEntrySymbol);
// Export the source compilation unit <clinit> as the C runtime "main".
// Encoding keeps this function at text offset zero.
if( emitEntrySymbol )
diff --git a/chapter25/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java b/chapter25/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java
index 5d8ed03c..fa187000 100644
--- a/chapter25/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java
+++ b/chapter25/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java
@@ -63,6 +63,13 @@ public abstract class GlobalCodeMotion {
private static void breakUpGlobalConstantSingle( Node con ) {
+ // If an immediate global-value user still spans functions, it cannot
+ // yet be assigned to one clone. Keeping the constant at Start is a
+ // valid schedule; a downstream value with concrete ownership can be
+ // split independently.
+ for( Node use : con.outs() )
+ if( use != null && useFun(use)==null )
+ return;
// While constant has users in different functions
while( true ) {
// Find a function user, and another function
@@ -106,26 +113,29 @@ public abstract class GlobalCodeMotion {
}
private static FunNode useFun(Node use) {
+ return useFun(use,new BitSet());
+ }
+
+ private static FunNode useFun(Node use, BitSet visit) {
+ if( visit.get(use._nid) ) return null;
+ visit.set(use._nid);
if( use instanceof ReturnNode ret )
return ret.fun();
if( use instanceof ParmNode parm )
return parm.fun();
CFGNode cfg = use.cfg0();
- if( cfg==null ) return null;
- FunNode fun = cfg.fun();
+ FunNode fun = cfg==null ? null : cfg.fun();
// Use itself is not in a function... which makes it a 2-part
// constant such as happens on some chips where large constants have
// to be built up in parts. PtrToInt followed by the array-body Add is
// another zero-code/global-value chain, so walk through any number of
// single-use pieces until reaching the function-owned use.
- if( fun==null ) {
- do {
- assert use.nOuts()==1;
- use = use.out(0);
- cfg = use.cfg0();
- fun = cfg==null ? null : cfg.fun();
- } while( fun==null );
- }
+ if( fun==null )
+ for( Node out : use.outs() ) {
+ FunNode f = useFun(out,(BitSet)visit.clone());
+ if( f != null && fun != null && f != fun ) return null;
+ if( f != null ) fun = f;
+ }
return fun;
}