Skip to content

Commit

Permalink
wasm gc: fix with passing JS objects to non-JS methods
Browse files Browse the repository at this point in the history
  • Loading branch information
konsoletyper committed Oct 23, 2024
1 parent d29b436 commit dff3e2f
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 6 deletions.
31 changes: 25 additions & 6 deletions jso/impl/src/main/java/org/teavm/jso/impl/JSClassProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ void processProgram(MethodHolder methodToProcess) {
processConstructArray((ConstructArrayInstruction) insn);
} else if (insn instanceof ExitInstruction) {
var exit = (ExitInstruction) insn;
exit.setValueToReturn(wrapJsAsJava(insn, exit.getValueToReturn(),
exit.setValueToReturn(convertValue(insn, exit.getValueToReturn(),
methodToProcess.getResultType()));
} else if (insn instanceof ClassConstantInstruction) {
processClassConstant((ClassConstantInstruction) insn);
Expand Down Expand Up @@ -399,7 +399,7 @@ private void processInvokeArgs(InvokeInstruction invoke, MethodReader methodToIn
for (var i = 0; i < invoke.getArguments().size(); ++i) {
var type = invoke.getMethod().parameterType(i);
var arg = invoke.getArguments().get(i);
var newArg = wrapJsAsJava(invoke, arg, type);
var newArg = convertValue(invoke, arg, type);
if (newArg != arg) {
if (newArgs == null) {
newArgs = invoke.getArguments().toArray(new Variable[0]);
Expand All @@ -412,12 +412,12 @@ private void processInvokeArgs(InvokeInstruction invoke, MethodReader methodToIn
}

if (invoke.getInstance() != null) {
invoke.setInstance(wrapJsAsJava(invoke, invoke.getInstance(), ValueType.object(className)));
invoke.setInstance(convertValue(invoke, invoke.getInstance(), ValueType.object(className)));
}
}

private void processPutField(PutFieldInstruction putField) {
putField.setValue(wrapJsAsJava(putField, putField.getValue(), putField.getFieldType()));
putField.setValue(convertValue(putField, putField.getValue(), putField.getFieldType()));
}

private void processGetFromArray(GetElementInstruction insn) {
Expand Down Expand Up @@ -772,16 +772,20 @@ private String getPrimitiveType(String className) {
return null;
}

private Variable wrapJsAsJava(Instruction instruction, Variable var, ValueType type) {
private Variable convertValue(Instruction instruction, Variable var, ValueType type) {
if (!(type instanceof ValueType.Object)) {
return var;
}

var cls = ((ValueType.Object) type).getClassName();
if (typeHelper.isJavaScriptClass(cls)) {
return var;
return convertJavaValueToJs(instruction, var);
} else {
return convertJsValueToJava(instruction, var);
}
}

private Variable convertJsValueToJava(Instruction instruction, Variable var) {
var varType = types.typeOf(var);
if (varType != JSType.JS && varType != JSType.MIXED) {
return var;
Expand All @@ -796,6 +800,21 @@ private Variable wrapJsAsJava(Instruction instruction, Variable var, ValueType t
return wrap.getReceiver();
}

private Variable convertJavaValueToJs(Instruction instruction, Variable var) {
var varType = types.typeOf(var);
if (varType == JSType.JS || varType == JSType.MIXED || varType == JSType.NULL) {
return var;
}
var wrap = new InvokeInstruction();
wrap.setType(InvocationType.SPECIAL);
wrap.setMethod(JSMethods.UNWRAP);
wrap.setArguments(var);
wrap.setReceiver(program.createVariable());
wrap.setLocation(instruction.getLocation());
instruction.insertPrevious(wrap);
return wrap.getReceiver();
}

private Variable unwrapJavaToJs(Instruction instruction, Variable var) {
var varType = types.typeOf(var);
if (varType != JSType.JAVA && varType != JSType.MIXED) {
Expand Down
10 changes: 10 additions & 0 deletions tests/src/test/java/org/teavm/jso/test/ExportClassTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ public void classWithPropertiesExported() {
assertEquals("w", o.fooValue);
}

@Test
public void simpleClassExportedViaStaticHelper() {
assertEquals("(OK)", callNativeJSMethod(new SimpleClass()));
assertEquals("[OK]", callNativeJSMethod(new DerivedSimpleClass()));
}

private static String callNativeJSMethod(I a) {
return callIFromJs(a);
}

@JSBody(params = "a", script = "return a.foo('OK');")
private static native String callIFromJs(I a);

Expand Down

0 comments on commit dff3e2f

Please sign in to comment.