Skip to content

Commit a4780dd

Browse files
committed
fix: callWithRefs dispatch splitting, SELECT/DROP isObjectRef, default alloc
Three fixes discovered by testing the metacircular-java-wasm examples (WebImage javac, Scala.js WasmGC, hello-world, count-vowels) against this branch: - Compiler: split callWithRefs dispatch into separate DispatchRefs_N classes for modules with >128 functions. Without this, modules with 13K+ functions fail with Method too large (same pattern as call). - InterpreterMachine: SELECT, SELECT_T, and DROP used Builder.isObjectRef() without TypeSection, causing concrete GC ref types (ref $MyStruct) to be misclassified as longs. This corrupted the MStack dual-array invariant and caused javac to NPE. Fixed via ValType.isObjectRef(long id, TypeSection ts) static helper. - InterpreterMachine: STRUCT_NEW_DEFAULT and ARRAY_NEW_DEFAULT did not allocate fieldRefs/elementRefs Object arrays for GC ref types. In the dual-array design these must exist so STRUCT_GET/ARRAY_GET can read ref values. - GlobalInstance: added constructor accepting Object refValue for externref globals (needed by Scala.js WasmGC module imports).
1 parent 07d27fc commit a4780dd

5 files changed

Lines changed: 72 additions & 23 deletions

File tree

compiler/src/main/java/run/endive/compiler/internal/Compiler.java

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919
import static run.endive.compiler.internal.CompilerUtil.callIndirectMethodName;
2020
import static run.endive.compiler.internal.CompilerUtil.callIndirectMethodType;
2121
import static run.endive.compiler.internal.CompilerUtil.callMethodName;
22+
import static run.endive.compiler.internal.CompilerUtil.callWithRefsDispatchMethodName;
2223
import static run.endive.compiler.internal.CompilerUtil.callWithRefsMethodName;
2324
import static run.endive.compiler.internal.CompilerUtil.classNameForCallIndirect;
25+
import static run.endive.compiler.internal.CompilerUtil.classNameForCallWithRefsDispatch;
2426
import static run.endive.compiler.internal.CompilerUtil.classNameForDispatch;
2527
import static run.endive.compiler.internal.CompilerUtil.defaultValue;
2628
import static run.endive.compiler.internal.CompilerUtil.emitInvokeFunction;
@@ -1105,7 +1107,26 @@ private void compileMachineCallClass() {
11051107
callWithRefsMethod =
11061108
asm -> compileMachineCallWithRefsInvoke(asm, 0, functionTypes.size());
11071109
} else {
1108-
callWithRefsMethod = compileMachineCallWithRefsDispatch(MAX_DISPATCH_METHODS << 2);
1110+
var maxCallWithRefsMethods = MAX_DISPATCH_METHODS << 2;
1111+
maxCallWithRefsMethods =
1112+
loadChunkedClass(
1113+
functionTypes.size(),
1114+
maxCallWithRefsMethods,
1115+
(coll, start, end, chunkSize) ->
1116+
compileExtraClass(
1117+
coll,
1118+
classNameForCallWithRefsDispatch(className, start),
1119+
(cw) ->
1120+
emitFunction(
1121+
cw,
1122+
callWithRefsDispatchMethodName(
1123+
start),
1124+
MACHINE_CALL_WITH_REFS_METHOD_TYPE,
1125+
true,
1126+
asm ->
1127+
compileMachineCallWithRefsInvoke(
1128+
asm, start, end))));
1129+
callWithRefsMethod = compileMachineCallWithRefsDispatch(maxCallWithRefsMethods);
11091130
}
11101131
emitFunction(
11111132
classWriter,
@@ -1255,14 +1276,14 @@ private Consumer<InstructionAdapter> compileMachineCallWithRefsDispatch(
12551276
asm.shr(INT_TYPE);
12561277
asm.tableswitch(0, labels.length - 1, labels[0], labels);
12571278

1258-
// For large modules, delegate to the same single invoke method
1259-
// since all the logic (host vs compiled vs callWithRefs_N) is there
12601279
for (int i = 0; i < labels.length; i++) {
12611280
asm.mark(labels[i]);
1262-
int chunkStart = i << shift;
1263-
int chunkEnd = min(chunkStart + maxMachineCallMethods, functionTypes.size());
1264-
compileMachineCallWithRefsInvoke(asm, chunkStart, chunkEnd);
1265-
// compileMachineCallWithRefsInvoke ends with areturn, no fall-through
1281+
asm.invokestatic(
1282+
internalClassName(classNameForCallWithRefsDispatch(className, i << shift)),
1283+
callWithRefsDispatchMethodName(i << shift),
1284+
MACHINE_CALL_WITH_REFS_METHOD_TYPE.toMethodDescriptorString(),
1285+
false);
1286+
asm.areturn(OBJECT_TYPE);
12661287
}
12671288
};
12681289
}

compiler/src/main/java/run/endive/compiler/internal/CompilerUtil.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,14 @@ static String callDispatchMethodName(int start) {
323323
return "call_dispatch_" + start;
324324
}
325325

326+
static String classNameForCallWithRefsDispatch(String prefix, int id) {
327+
return prefix + "DispatchRefs_" + id;
328+
}
329+
330+
static String callWithRefsDispatchMethodName(int start) {
331+
return "callWithRefs_dispatch_" + start;
332+
}
333+
326334
static String classNameForCallIndirect(String prefix, int typeId, int start) {
327335
return prefix + "Indirect_" + typeId + "_" + start;
328336
}

runtime/src/main/java/run/endive/runtime/GlobalInstance.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ public GlobalInstance(
4444
this.mutabilityType = mutabilityType;
4545
}
4646

47+
public GlobalInstance(Object refValue, ValType valType, MutabilityType mutabilityType) {
48+
this.refValue = refValue;
49+
this.valType = valType;
50+
this.mutabilityType = mutabilityType;
51+
}
52+
4753
public long getValueLow() {
4854
return valueLow;
4955
}

runtime/src/main/java/run/endive/runtime/InterpreterMachine.java

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -355,13 +355,13 @@ protected void eval(MStack stack, Instance instance, Deque<StackFrame> callStack
355355
CALL_INDIRECT(stack, instance, callStack, operands);
356356
break;
357357
case DROP:
358-
DROP(stack, operands);
358+
DROP(stack, instance.module().typeSection(), operands);
359359
break;
360360
case SELECT:
361-
SELECT(stack, operands);
361+
SELECT(stack, instance.module().typeSection(), operands);
362362
break;
363363
case SELECT_T:
364-
SELECT_T(stack, operands);
364+
SELECT_T(stack, instance.module().typeSection(), operands);
365365
break;
366366
case LOCAL_GET:
367367
LOCAL_GET(stack, operands, frame);
@@ -2346,19 +2346,19 @@ private static void GLOBAL_GET(MStack stack, Instance instance, Operands operand
23462346
}
23472347
}
23482348

2349-
private static void DROP(MStack stack, Operands operands) {
2349+
private static void DROP(MStack stack, TypeSection typeSection, Operands operands) {
23502350
var typeId = operands.get(0);
23512351
if (typeId == ValType.ID.V128) {
23522352
stack.pop();
23532353
stack.pop();
2354-
} else if (ValType.builder().fromId(typeId).isObjectRef()) {
2354+
} else if (ValType.isObjectRef(typeId, typeSection)) {
23552355
stack.popRef();
23562356
} else {
23572357
stack.pop();
23582358
}
23592359
}
23602360

2361-
private static void SELECT(MStack stack, Operands operands) {
2361+
private static void SELECT(MStack stack, TypeSection typeSection, Operands operands) {
23622362
var pred = (int) stack.pop();
23632363
if (operands.get(0) == ValType.ID.V128) {
23642364
var b1 = stack.pop();
@@ -2372,7 +2372,7 @@ private static void SELECT(MStack stack, Operands operands) {
23722372
stack.push(a2);
23732373
stack.push(a1);
23742374
}
2375-
} else if (ValType.builder().fromId(operands.get(0)).isObjectRef()) {
2375+
} else if (ValType.isObjectRef(operands.get(0), typeSection)) {
23762376
var b = stack.popRef();
23772377
var a = stack.popRef();
23782378
if (pred == 0) {
@@ -2391,7 +2391,7 @@ private static void SELECT(MStack stack, Operands operands) {
23912391
}
23922392
}
23932393

2394-
private static void SELECT_T(MStack stack, Operands operands) {
2394+
private static void SELECT_T(MStack stack, TypeSection typeSection, Operands operands) {
23952395
var pred = (int) stack.pop();
23962396
var typeId = operands.get(0);
23972397

@@ -2407,7 +2407,7 @@ private static void SELECT_T(MStack stack, Operands operands) {
24072407
stack.push(a2);
24082408
stack.push(a1);
24092409
}
2410-
} else if (ValType.builder().fromId(typeId).isObjectRef()) {
2410+
} else if (ValType.isObjectRef(typeId, typeSection)) {
24112411
var b = stack.popRef();
24122412
var a = stack.popRef();
24132413
if (pred == 0) {
@@ -3493,17 +3493,21 @@ private static void STRUCT_NEW_DEFAULT(MStack stack, Instance instance, Operands
34933493
var typeIdx = (int) operands.get(0);
34943494
var st = instance.module().typeSection().getSubType(typeIdx).compType().structType();
34953495
var fields = new long[st.fieldTypes().length];
3496-
// Default values: 0 for numeric, null for GC refs (already zero-initialized),
3497-
// REF_NULL_VALUE for non-GC references (funcref, externref)
3496+
boolean hasObjRefFields = false;
34983497
for (int i = 0; i < fields.length; i++) {
34993498
var ft = st.fieldTypes()[i];
3500-
if (ft.storageType().valType() != null
3499+
if (ft.storageType().valType() != null && ft.storageType().isObjectRef()) {
3500+
hasObjRefFields = true;
3501+
} else if (ft.storageType().valType() != null
35013502
&& ft.storageType().valType().isReference()
35023503
&& !ft.storageType().isObjectRef()) {
35033504
fields[i] = REF_NULL_VALUE;
35043505
}
35053506
}
3506-
var struct = new WasmStruct(typeIdx, fields);
3507+
var struct =
3508+
hasObjRefFields
3509+
? new WasmStruct(typeIdx, fields, new Object[fields.length])
3510+
: new WasmStruct(typeIdx, fields);
35073511
stack.pushRef(struct);
35083512
}
35093513

@@ -3590,13 +3594,19 @@ private static void ARRAY_NEW_DEFAULT(MStack stack, Instance instance, Operands
35903594
var elems = new long[len];
35913595
var at = instance.module().typeSection().getSubType(typeIdx).compType().arrayType();
35923596
var ft = at.fieldType();
3593-
if (ft.storageType().valType() != null
3597+
if (ft.storageType().valType() != null && ft.storageType().isObjectRef()) {
3598+
var arr = new WasmArray(typeIdx, elems, new Object[len]);
3599+
stack.pushRef(arr);
3600+
} else if (ft.storageType().valType() != null
35943601
&& ft.storageType().valType().isReference()
35953602
&& !ft.storageType().isObjectRef()) {
35963603
java.util.Arrays.fill(elems, Value.REF_NULL_VALUE);
3604+
var arr = new WasmArray(typeIdx, elems);
3605+
stack.pushRef(arr);
3606+
} else {
3607+
var arr = new WasmArray(typeIdx, elems);
3608+
stack.pushRef(arr);
35973609
}
3598-
var arr = new WasmArray(typeIdx, elems);
3599-
stack.pushRef(arr);
36003610
}
36013611

36023612
private static void ARRAY_NEW_FIXED(MStack stack, Instance instance, Operands operands) {

wasm/src/main/java/run/endive/wasm/types/ValType.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,10 @@ public boolean isObjectRef() {
289289
return objectRef;
290290
}
291291

292+
public static boolean isObjectRef(long valTypeId, TypeSection typeSection) {
293+
return builder().fromId(valTypeId).isObjectRef(typeSection);
294+
}
295+
292296
private boolean computeIsExternRef() {
293297
int op = opcode();
294298
if (op != ID.Ref && op != ID.RefNull) {

0 commit comments

Comments
 (0)