summaryrefslogtreecommitdiff
path: root/chapter24/src/test/java
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2026-09-28 15:42:57 -0700
committerCliff Click <cliffc@acm.org>2026-09-28 15:42:57 -0700
commit75390f477ac7d4568ac02f97358d146ff9879d6e (patch)
treea6dc2226357ecb03359414b51f3de87034892aca /chapter24/src/test/java
parent586c8f65f2d0c0e1f73aadd0aa8d850aa653bddd (diff)
downloadSimple-75390f477ac7d4568ac02f97358d146ff9879d6e.tar.gz
Simple-75390f477ac7d4568ac02f97358d146ff9879d6e.zip
Backport FunPtr
Helps keep functions alive via ptr only (no calls). A few RISC 5 TFP encoding fixes.
Diffstat (limited to 'chapter24/src/test/java')
-rw-r--r--chapter24/src/test/java/com/seaofnodes/simple/Chapter18Test.java2
-rw-r--r--chapter24/src/test/java/com/seaofnodes/simple/Chapter19Test.java2
-rw-r--r--chapter24/src/test/java/com/seaofnodes/simple/Chapter20Test.java6
-rw-r--r--chapter24/src/test/java/com/seaofnodes/simple/Chapter21Test.java21
-rw-r--r--chapter24/src/test/java/com/seaofnodes/simple/Chapter22Test.java48
-rw-r--r--chapter24/src/test/java/com/seaofnodes/simple/progs/funptr.c15
6 files changed, 89 insertions, 5 deletions
diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter18Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter18Test.java
index e6ff1196..479e9e62 100644
--- a/chapter24/src/test/java/com/seaofnodes/simple/Chapter18Test.java
+++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter18Test.java
@@ -187,7 +187,7 @@ var fcn = arg ? { int x -> x*x; } : { int x -> x+x; };
return fcn(3);
""");
code.parse().opto();
- assertEquals("Stop[ return #2; return 9; return 6; ]", code._stop.toString());
+ assertEquals("Stop[ return #2; return (Parm_x($fun21,i64)*x); return (Parm_x($fun22,i64)<<1); ]", code._stop.toString());
assertEquals("6", Eval2.eval(code, 0));
assertEquals("9", Eval2.eval(code, 1));
}
diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter19Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter19Test.java
index b9764607..df94e97c 100644
--- a/chapter24/src/test/java/com/seaofnodes/simple/Chapter19Test.java
+++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter19Test.java
@@ -413,7 +413,7 @@ val fcn = arg ? { int x -> x*x; } : { int x -> x+x; };
return fcn(2)*10 + fcn(3);
""");
code.driver(Phase.LocalSched,"x86_64_v2", "SystemV");
- assertEquals("Stop[ return (add,#2,(muli,#2)); return (mul,Parm_x($fun21,[2-3]),x); return (shli,Parm_x($fun22,[2-3])); ]", code.print());
+ assertEquals("Stop[ return (add,#2,(muli,#2)); return (mul,Parm_x($fun21,i64),x); return (shli,Parm_x($fun22,i64)); ]", code.print());
}
@Test
diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter20Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter20Test.java
index 044ad4ed..4e7cb156 100644
--- a/chapter24/src/test/java/com/seaofnodes/simple/Chapter20Test.java
+++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter20Test.java
@@ -205,9 +205,9 @@ s.cs[0] = 67; // C
s.cs[1] = 108; // l
hashCode(s);
""";
- testTarget(src,"x86_64_v2", "SystemV",9,null);
- testTarget(src,"riscv" , "SystemV",4,null);
- testTarget(src,"arm" , "SystemV",3,null);
+ testTarget(src,"x86_64_v2", "SystemV",0,null);
+ testTarget(src,"riscv" , "SystemV",0,null);
+ testTarget(src,"arm" , "SystemV",0,null);
}
@Test
diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter21Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter21Test.java
index 86fa016a..afa3ce6a 100644
--- a/chapter24/src/test/java/com/seaofnodes/simple/Chapter21Test.java
+++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter21Test.java
@@ -13,6 +13,27 @@ import org.junit.Test;
import static org.junit.Assert.*;
public class Chapter21Test {
+ @Test public void testReturnedFunctionEncoding() throws IOException {
+ String src = "if(arg) return {->42;}; return {->43;};";
+ CodeGen code = new CodeGen(src).driver("riscv","SystemV",null);
+ for( int arg : new int[]{0,1} ) {
+ byte[] image = new byte[1<<16];
+ byte[] bits = code._encoding.bits();
+ System.arraycopy(bits,0,image,0,bits.length);
+ EvalRisc5 cpu = new EvalRisc5(image,1<<15);
+ cpu._pc = code._encoding._opStart[code.link(code._main)._nid];
+ cpu.regs[riscv.A0] = arg;
+ assertEquals(0,cpu.step(100));
+ assertEquals(0,cpu._pc);
+ cpu._pc = (int)cpu.regs[riscv.A0];
+ assertEquals(0,cpu.step(100));
+ assertEquals(0,cpu._pc);
+ assertEquals(arg==0 ? 43 : 42,cpu.regs[riscv.A0]);
+ }
+ // Anonymous bodies need code, but no exported ELF name.
+ new CodeGen(src).driver(TestC.CPU_PORT,TestC.CALL_CONVENTION,"build/objs/anonymous.o");
+ }
+
@Test public void testArmFloatMemory() throws IOException {
for( String type : new String[]{"f32","f64"} ) {
String src = type+"[] !a=new "+type+"[3]; a[arg]=1.25; return a[1];";
diff --git a/chapter24/src/test/java/com/seaofnodes/simple/Chapter22Test.java b/chapter24/src/test/java/com/seaofnodes/simple/Chapter22Test.java
index cf92f830..6571b4f9 100644
--- a/chapter24/src/test/java/com/seaofnodes/simple/Chapter22Test.java
+++ b/chapter24/src/test/java/com/seaofnodes/simple/Chapter22Test.java
@@ -14,6 +14,54 @@ import static org.junit.Assert.*;
public class Chapter22Test {
+ @Test public void testReturnedFunctions() throws IOException {
+ for( String src : new String[]{"return {->42;};", "val f={->42;}; return f;", "return sys.io.p;"} )
+ for( String target : new String[]{"riscv","arm"} ) {
+ CodeGen code = new CheckedCodeGen(src).driver(CodeGen.Phase.Encoding,target,"SystemV").exportELF(null);
+ byte[] image = new byte[1<<16];
+ byte[] bits = code._encoding.bits();
+ System.arraycopy(bits,0,image,0,bits.length);
+ boolean library = src.contains("sys.io.p");
+ // u8[]: four-byte length followed by its bytes.
+ image[0x2000]=2; image[0x2004]='o'; image[0x2005]='k';
+ int entry = code._encoding._opStart[code.link(code._main)._nid];
+ if( target.equals("riscv") ) {
+ EvalRisc5 cpu = new EvalRisc5(image,1<<15);
+ cpu._pc = entry;
+ assertEquals(0,cpu.step(1000));
+ assertEquals(0,cpu._pc);
+ cpu._pc = (int)cpu.regs[riscv.A0]; // Call the returned address.
+ cpu.regs[library ? riscv.A1 : riscv.A0] = 0x2000; // Methods also receive self.
+ assertEquals(0,cpu.step(1000));
+ assertEquals(0,cpu._pc);
+ if( library ) assertEquals("ok",cpu._stdout.toString());
+ else assertEquals(42,cpu.regs[riscv.A0]);
+ } else {
+ EvalArm64 cpu = new EvalArm64(image,1<<15);
+ cpu._pc = entry;
+ assertEquals(0,cpu.step(1000));
+ assertEquals(0,cpu._pc);
+ cpu._pc = (int)cpu.regs[0];
+ cpu.regs[library ? 1 : 0] = 0x2000;
+ assertEquals(0,cpu.step(1000));
+ assertEquals(0,cpu._pc);
+ if( library ) assertEquals("ok",cpu._stdout.toString());
+ else assertEquals(42,cpu.regs[0]);
+ }
+ }
+ CodeGen unused = new CodeGen("({->42;}); return 0;").parse().opto();
+ assertEquals(1,unused._stop.nIns());
+ }
+
+ @Test public void testReturnedFunctionsNative() throws IOException {
+ String src = "val factory={int x -> if(x) return {->42;}; return {->43;};}; val printer={->return sys.io.p;};";
+ String obj = "build/objs/funptr.o";
+ new CheckedCodeGen(src).driver(TestC.CPU_PORT,TestC.CALL_CONVENTION,obj);
+ assertEquals("ok",TestC.gcc(obj,"","src/test/java/com/seaofnodes/simple/progs/funptr.c",false,
+ "build/objs/funptr"+(TestC.OS.startsWith("Windows") ? ".exe" : "")));
+ }
+
+
@Test public void testRiscvRightShifts() {
// SRAI, SRLI, SRA, SRL: a0 = -32 shifted by 4.
int[] ops = {0x40455513,0x00455513,0x40b55533,0x00b55533};
diff --git a/chapter24/src/test/java/com/seaofnodes/simple/progs/funptr.c b/chapter24/src/test/java/com/seaofnodes/simple/progs/funptr.c
new file mode 100644
index 00000000..2abe6e74
--- /dev/null
+++ b/chapter24/src/test/java/com/seaofnodes/simple/progs/funptr.c
@@ -0,0 +1,15 @@
+#include <assert.h>
+#include <stdint.h>
+
+typedef int64_t (*Function)(void);
+typedef int64_t (*Printer)(void *, void *);
+extern Function factory(int64_t);
+extern Printer printer(void);
+
+int main(void) {
+ assert(factory(1)() == 42);
+ assert(factory(0)() == 43);
+ struct { uint32_t length; char data[2]; } text = {2, {'o','k'}};
+ printer()(0, &text); // Unused class receiver, then the byte array.
+ return 0;
+}