summaryrefslogtreecommitdiff
path: root/chapter25/src/test
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-10-08 16:52:27 -0700
committerCliff Click <cliffc@acm.org>2026-10-08 16:52:27 -0700
commit7096ba70c05eabfe96fd7e69d276b16ac1bd0bb9 (patch)
treebda5cb52577488cb61544c671afa5080297d0381 /chapter25/src/test
parent87a75c83b75480e65147a4d425fddd14a05df4d9 (diff)
downloadSimple-7096ba70c05eabfe96fd7e69d276b16ac1bd0bb9.tar.gz
Simple-7096ba70c05eabfe96fd7e69d276b16ac1bd0bb9.zip
Support putting static data into ELF constant poolmain
Mostly fcn inits in <clinit>
Diffstat (limited to 'chapter25/src/test')
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/Chapter20Test.java2
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java2
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/Chapter22Test.java18
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/StaticDataTest.java112
-rw-r--r--chapter25/src/test/java/com/seaofnodes/simple/TestC.java1
5 files changed, 124 insertions, 11 deletions
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter20Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter20Test.java
index 40e9172e..b46a54b2 100644
--- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter20Test.java
+++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter20Test.java
@@ -258,7 +258,7 @@ val _hashCodeString = { !String self ->
};
""";
testCPU(src,"x86_64_v2", "SystemV",21,null);
- testCPU(src,"riscv" , "SystemV",10,null);
+ testCPU(src,"riscv" , "SystemV",8,null);
testCPU(src,"arm" , "SystemV",8,null);
}
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java
index 8010e245..0cfdb577 100644
--- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java
+++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter21Test.java
@@ -384,7 +384,7 @@ val _hashCodeString = { !String self ->
};
""";
testCPU(src,"x86_64_v2", "SystemV",21,null);
- testCPU(src,"riscv" , "SystemV",10,null);
+ testCPU(src,"riscv" , "SystemV",8,null);
testCPU(src,"arm" , "SystemV",8,null);
}
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/Chapter22Test.java b/chapter25/src/test/java/com/seaofnodes/simple/Chapter22Test.java
index e8c080fd..7484a6ae 100644
--- a/chapter25/src/test/java/com/seaofnodes/simple/Chapter22Test.java
+++ b/chapter25/src/test/java/com/seaofnodes/simple/Chapter22Test.java
@@ -146,9 +146,9 @@ struct _Person { i32 age;};
p.age = (arg<<17)>>17;
return 0;
""";
- assertEquals(82, testCPUSize(src, "x86_64_v2","win64", 3 ));
- assertEquals(96, testCPUSize(src, "riscv", "SystemV", 4 ));
- assertEquals(96, testCPUSize(src, "arm" , "SystemV", 4 ));
+ assertEquals(65, testCPUSize(src, "x86_64_v2","win64", 3 ));
+ assertEquals(76, testCPUSize(src, "riscv", "SystemV", 4 ));
+ assertEquals(76, testCPUSize(src, "arm" , "SystemV", 4 ));
// do assertEquals here
EvalRisc5 R5 = TestRisc5.build( src, "sext_str_not_fold_away", 0, 4, false);
@@ -178,9 +178,9 @@ return 0;
int trap_arm = A5.step(100);
assertEquals(0,trap_arm);
- assertEquals(82, testCPUSize(src, "x86_64_v2","win64",3 ));
- assertEquals(96, testCPUSize(src, "riscv", "SystemV",4 ));
- assertEquals(96, testCPUSize(src, "arm", "SystemV",4 ));
+ assertEquals(65, testCPUSize(src, "x86_64_v2","win64",3 ));
+ assertEquals(76, testCPUSize(src, "riscv", "SystemV",4 ));
+ assertEquals(76, testCPUSize(src, "arm", "SystemV",4 ));
}
@@ -202,9 +202,9 @@ return 0;
int trap_arm = A5.step(100);
assertEquals(0,trap_arm);
- assertEquals(72, testCPUSize(src, "x86_64_v2","win64",3 ));
- assertEquals(92, testCPUSize(src, "riscv", "SystemV",5 ));
- assertEquals(92, testCPUSize(src, "arm", "SystemV",5));
+ assertEquals(55, testCPUSize(src, "x86_64_v2","win64",3 ));
+ assertEquals(72, testCPUSize(src, "riscv", "SystemV",5 ));
+ assertEquals(72, testCPUSize(src, "arm", "SystemV",5));
// do assertEquals here
}
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/StaticDataTest.java b/chapter25/src/test/java/com/seaofnodes/simple/StaticDataTest.java
new file mode 100644
index 00000000..070b7a9e
--- /dev/null
+++ b/chapter25/src/test/java/com/seaofnodes/simple/StaticDataTest.java
@@ -0,0 +1,112 @@
+package com.seaofnodes.simple;
+
+import com.seaofnodes.simple.codegen.CodeGen;
+import com.seaofnodes.simple.codegen.StaticData;
+import com.seaofnodes.simple.type.TypeStruct;
+import com.seaofnodes.simple.type.TypeInteger;
+import com.seaofnodes.simple.util.Ary;
+import com.seaofnodes.isa.eval.EvalArm64;
+import com.seaofnodes.isa.eval.EvalRisc5;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class StaticDataTest {
+ private static final String SRC="val n=42; val f={int x -> x+n;}; return 0;";
+
+ private static StaticData.ObjectData root(CodeGen code) {
+ return code._encoding._data.entries().stream()
+ .filter(obj -> obj.symbol.endsWith("Test.$class")).findFirst().orElseThrow();
+ }
+
+ // Read the image before <clinit>, then call the function through its data slot.
+ @Test public void testEmulatorImage() {
+ for( String cpu : new String[]{"arm","riscv"} ) {
+ CodeGen code=new CodeGen(SRC).driver(cpu,"SystemV",true,false);
+ var e=code._encoding;
+ var obj=root(code);
+ TypeStruct ts=(TypeStruct)obj.type;
+ int cp=(e._bits.size()+15)&-16, sd=(cp+e._cpool.size()+15)&-16;
+ byte[] image=new byte[1<<20];
+ System.arraycopy(e._bits.buf(),0,image,0,e._bits.size());
+ System.arraycopy(e._cpool.buf(),0,image,cp,e._cpool.size());
+ System.arraycopy(e._sdata.buf(),0,image,sd,e._sdata.size());
+ int n=sd+obj.offset+ts.offset(ts.find("n"));
+ int f=sd+obj.offset+ts.offset(ts.find("f"));
+ if( cpu.equals("arm") ) {
+ var arm=new EvalArm64(image,1<<16);
+ assertEquals(42,arm.ld4s(n));
+ arm._pc=arm.ld4s(f);
+ arm.regs[0]=7;
+ assertEquals(0,arm.step(1000));
+ assertEquals(49,arm.regs[0]);
+ } else {
+ var r5=new EvalRisc5(image,1<<16);
+ assertEquals(42,r5.ld4s(n));
+ r5._pc=r5.ld4s(f);
+ r5.regs[10]=7;
+ assertEquals(0,r5.step(1000));
+ assertEquals(49,r5.regs[10]);
+ }
+ }
+ }
+
+ @Test public void testNativeImage() throws Exception {
+ Path dir=Path.of("build/objs/static-data");
+ Files.createDirectories(dir);
+ CodeGen code=new CodeGen(null,dir.toString(),null,"Test",SRC,123L,true,
+ TypeInteger.BOT)
+ .driver(TestC.CPU_PORT,TestC.CALL_CONVENTION,false,false);
+ TypeStruct ts=(TypeStruct)root(code).type;
+ Path driver=dir.resolve("driver.c");
+ Files.writeString(driver,"""
+ #include <stdint.h>
+ #include <string.h>
+ extern unsigned char data[] __asm__("Test.$class");
+ typedef int64_t (__attribute__((CALL_CONV)) *fun)(int64_t);
+ int main(void) {
+ int64_t n; uint32_t f;
+ memcpy(&n,data+%d,sizeof(n));
+ memcpy(&f,data+%d,sizeof(f));
+ return n!=42 || ((fun)(uintptr_t)f)(7)!=49;
+ }
+ """.formatted(ts.offset(ts.find("n")),ts.offset(ts.find("f"))));
+ String exe=dir.resolve(TestC.OS.startsWith("Windows")?"test.exe":"test").toString();
+ TestC.linkExe(dir.resolve("Test.o").toString(),
+ TestC.CALL_CONVENTION.equals("win64")?"ms_abi":"sysv_abi",
+ driver.toString(),null,exe);
+ assertEquals("",TestC.exec(TestC.TEST_TIMEOUT_SECONDS,exe));
+ }
+
+ // Two separately compiled users must reference the same mutable class object.
+ @Test public void testSharedClass() throws Exception {
+ Path dir=Path.of("build/objs/static-data-shared");
+ Files.createDirectories(dir);
+ Path lib=dir.resolve("lib");
+ Files.createDirectories(lib);
+ var paths=new Ary<>(new String[]{lib.toString()});
+ String[] names={"Globals","A","B"};
+ String[] sources={"int count=0;",
+ "val a={ -> Globals; };", "val b={ -> Globals; };"};
+ for( int i=0; i<names.length; i++ )
+ new CodeGen(null,(i==0?lib:dir).toString(),i==0?null:paths,names[i],sources[i],123L,true,TypeInteger.BOT)
+ .driver(TestC.CPU_PORT,TestC.CALL_CONVENTION,false,false);
+ Path driver=dir.resolve("driver.c");
+ Files.writeString(driver,"""
+ #include <stdint.h>
+ __attribute__((CALL_CONV)) extern int64_t *a(void),*b(void);
+ int main(void) {
+ int64_t *x=a(),*y=b();
+ if(x!=y) return 1;
+ *x=37;
+ return *y!=37;
+ }
+ """);
+ String exe=dir.resolve(TestC.OS.startsWith("Windows")?"test.exe":"test").toString();
+ TestC.linkExe(lib.resolve("Globals.o").toString(),
+ TestC.CALL_CONVENTION.equals("win64")?"ms_abi":"sysv_abi",
+ driver.toString(),new Ary<>(new String[]{dir+"/A.o",dir+"/B.o"}),exe);
+ assertEquals("",TestC.exec(TestC.TEST_TIMEOUT_SECONDS,exe));
+ }
+}
diff --git a/chapter25/src/test/java/com/seaofnodes/simple/TestC.java b/chapter25/src/test/java/com/seaofnodes/simple/TestC.java
index 64518b0d..b08be824 100644
--- a/chapter25/src/test/java/com/seaofnodes/simple/TestC.java
+++ b/chapter25/src/test/java/com/seaofnodes/simple/TestC.java
@@ -167,6 +167,7 @@ public abstract class TestC {
// pointers as 4bytes.
var params = new Ary<>(String.class);
params.add("gcc");
+ params.add(OS.startsWith("Windows") ? "-Wl,--image-base,0x400000" : "-no-pie");
if( cfile!=null ) params.add(cfile); // Associated C driver, usually has a `main`
params.add(obj);
// Standalone Simple programs export `simple_main`; the small C