diff --git a/src/de/inetsoftware/jwebassembly/module/TypeManager.java b/src/de/inetsoftware/jwebassembly/module/TypeManager.java
index 7f023bb..7199322 100644
--- a/src/de/inetsoftware/jwebassembly/module/TypeManager.java
+++ b/src/de/inetsoftware/jwebassembly/module/TypeManager.java
@@ -52,6 +52,11 @@ public class TypeManager {
/** name of virtual function table, start with a point for an invalid Java identifier */
static final String VTABLE = ".vtable";
+ /**
+ * The reserved position on start of the vtable:
+ *
offset of interface call table (itable)
+ * offset of instanceof list
+ */
private static final int VTABLE_FIRST_FUNCTION_INDEX = 2;
private Map structTypes = new LinkedHashMap<>();
@@ -132,13 +137,13 @@ public class TypeManager {
}
/**
- * Get the FunctionName for a virtual call and mark it as used. The function has 2 parameters (THIS,
+ * Create the FunctionName for a virtual call and mark it as used. The function has 2 parameters (THIS,
* virtualfunctionIndex) and returns the index of the function.
*
* @return the name
*/
@Nonnull
- WatCodeSyntheticFunctionName getCallVirtualGC() {
+ WatCodeSyntheticFunctionName createCallVirtualGC() {
return new WatCodeSyntheticFunctionName( //
"callVirtual", "local.get 0 " // THIS
+ "struct.get java/lang/Object .vtable " // vtable is on index 0
@@ -149,6 +154,49 @@ public class TypeManager {
, valueOf( "java/lang/Object" ), ValueType.i32, null, ValueType.i32 ); //
}
+ /**
+ * Create the FunctionName for the INSTANCEOF operation and mark it as used. The function has 2 parameters (THIS,
+ * classIndex) and returns true if there is a match.
+ *
+ * @return the name
+ */
+ WatCodeSyntheticFunctionName createInstanceOf() {
+ return new WatCodeSyntheticFunctionName( //
+ "instanceof", "local.get 0 " // THIS
+ + "struct.get java/lang/Object .vtable " // vtable is on index 0
+ + "local.tee 2 " // save the vtable location
+ + "i32.load offset=4 align=4 " // get offset of instanceof inside vtable (int position 1, byte position 4)
+ + "local.get 2 " // get the vtable location
+ + "i32.add " //
+ + "local.tee 2 " // save the instanceof location
+ + "i32.load offset=0 align=4 " // count of instanceof entries
+ + "i32.const 4 " //
+ + "i32.mul " //
+ + "local.get 2 " // get the instanceof location
+ + "i32.add " //
+ + "local.set 3 " // save end position
+ + "loop" //
+ + " local.get 2 " // get the instanceof location pointer
+ + " local.get 3 " // get the end location
+ + " i32.eq" //
+ + " if" // current offset == end offset
+ + " i32.const 0" // not found
+ + " return" //
+ + " end" //
+ + " local.get 2" // get the instanceof location pointer
+ + " i32.const 4" //
+ + " i32.add" // increment offset
+ + " local.tee 2" // save the instanceof location pointer
+ + " i32.load offset=0 align=4" //
+ + " local.get 1" // the class index that we search
+ + " i32.ne" //
+ + " br_if 0 " //
+ + "end " //
+ + "i32.const 1 " // class/interface found
+ + "return " //
+ , valueOf( "java/lang/Object" ), ValueType.i32, null, ValueType.i32 ); //
+ }
+
/**
* A reference to a type.
*
@@ -259,9 +307,9 @@ public class TypeManager {
}
}
- // add all interfaces to the instanceof
+ // add all interfaces to the instanceof set
for(ConstantClass interClass : classFile.getInterfaces() ) {
- StructType type = types.structTypes.get( className );
+ StructType type = types.structTypes.get( interClass.getName() );
if( type != null ) {
instanceOFs.add( type );
}
diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java
index ed864ad..b443d2e 100644
--- a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java
+++ b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java
@@ -52,11 +52,6 @@ import de.inetsoftware.jwebassembly.wasm.WasmBlockOperator;
*/
public abstract class WasmCodeBuilder {
- /**
- * declare for frequently use of virtual call with non GC mode.
- */
- static final SyntheticFunctionName GET_I32 = new JavaScriptSyntheticFunctionName( "NonGC", "get_i32", () -> "(a,i) => a[i]", ValueType.anyref, ValueType.i32, null, ValueType.i32 );
-
private final LocaleVariableManager localVariables = new LocaleVariableManager();
private final List instructions = new ArrayList<>();
@@ -497,11 +492,7 @@ public abstract class WasmCodeBuilder {
}
indirectCall.setVariableIndexOfThis( varIndex );
instructions.add( indirectCall );
- if( !options.useGC() ) {
- // for later access of the vtable
- functions.markAsNeeded( GET_I32 );
- functions.markAsImport( GET_I32, GET_I32.getAnnotation() );
- }
+ options.registerGet_i32(); // for later access of the vtable
}
/**
@@ -643,6 +634,12 @@ public abstract class WasmCodeBuilder {
* the line number in the Java source code
*/
protected void addStructInstruction( StructOperator op, @Nonnull String typeName, @Nullable NamedStorageType fieldName, int javaCodePos, int lineNumber ) {
+ if( op == StructOperator.INSTANCEOF ) {
+ instructions.add( new WasmConstInstruction( types.valueOf( typeName ).getClassIndex(), javaCodePos, lineNumber ) );
+ FunctionName name = options.getInstanceOf();
+ instructions.add( new WasmCallInstruction( name, javaCodePos, lineNumber, types, false ) );
+ return;
+ }
WasmStructInstruction structInst = new WasmStructInstruction( op, typeName, fieldName, javaCodePos, lineNumber, types );
instructions.add( structInst );
if( !options.useGC() ) {
diff --git a/src/de/inetsoftware/jwebassembly/module/WasmOptions.java b/src/de/inetsoftware/jwebassembly/module/WasmOptions.java
index be90bef..aefcaae 100644
--- a/src/de/inetsoftware/jwebassembly/module/WasmOptions.java
+++ b/src/de/inetsoftware/jwebassembly/module/WasmOptions.java
@@ -20,11 +20,13 @@ import java.util.HashMap;
import javax.annotation.Nonnull;
import de.inetsoftware.jwebassembly.JWebAssembly;
+import de.inetsoftware.jwebassembly.javascript.JavaScriptSyntheticFunctionName;
import de.inetsoftware.jwebassembly.module.CodeOptimizer;
import de.inetsoftware.jwebassembly.module.FunctionManager;
import de.inetsoftware.jwebassembly.module.FunctionName;
import de.inetsoftware.jwebassembly.module.StringManager;
import de.inetsoftware.jwebassembly.module.TypeManager;
+import de.inetsoftware.jwebassembly.wasm.ValueType;
/**
* The option/properties for the behavior of the compiler.
@@ -55,9 +57,12 @@ public class WasmOptions {
*/
public FunctionName ref_eq;
+ private FunctionName get_i32;
private FunctionName callVirtual;
+ private FunctionName instanceOf;
+
/**
* Create a new instance of options
*
@@ -112,6 +117,21 @@ public class WasmOptions {
return sourceMapBase;
}
+ /**
+ * Register FunctionName "NonGC.get_i32" for frequently access to vtable with non GC mode.
+ */
+ void registerGet_i32() {
+ if( useGC ) {
+ return;
+ }
+ if( get_i32 == null ) {
+ SyntheticFunctionName name;
+ get_i32 = name = new JavaScriptSyntheticFunctionName( "NonGC", "get_i32", () -> "(a,i) => a[i]", ValueType.anyref, ValueType.i32, null, ValueType.i32 );
+ functions.markAsNeeded( name );
+ functions.markAsImport( name, name.getAnnotation() );
+ }
+ }
+
/**
* Get the FunctionName for a virtual call and mark it as used. The function has 2 parameters (THIS,
* virtualfunctionIndex) and returns the index of the function.
@@ -122,8 +142,26 @@ public class WasmOptions {
FunctionName getCallVirtual() {
FunctionName name = callVirtual;
if( name == null ) {
- callVirtual = name = types.getCallVirtualGC();
+ callVirtual = name = types.createCallVirtualGC();
functions.markAsNeeded( name );
+ registerGet_i32();
+ }
+ return name;
+ }
+
+ /**
+ * Get the FunctionName for an INSTANCEOF check and mark it as used. The function has 2 parameters (THIS,
+ * classIndex) and returns true or false.
+ *
+ * @return the name
+ */
+ @Nonnull
+ FunctionName getInstanceOf() {
+ FunctionName name = instanceOf;
+ if( name == null ) {
+ instanceOf = name = types.createInstanceOf();
+ functions.markAsNeeded( name );
+ registerGet_i32();
}
return name;
}
diff --git a/test/de/inetsoftware/jwebassembly/runtime/RuntimeErrors.java b/test/de/inetsoftware/jwebassembly/runtime/RuntimeErrors.java
index 45b848c..a3afda9 100644
--- a/test/de/inetsoftware/jwebassembly/runtime/RuntimeErrors.java
+++ b/test/de/inetsoftware/jwebassembly/runtime/RuntimeErrors.java
@@ -126,19 +126,6 @@ public class RuntimeErrors {
}
}
- @Test
- public void instanceofCall() throws IOException {
- compileErrorTest( "Unknown operator: INSTANCEOF", InstanceofMethod.class );
- }
-
- static class InstanceofMethod {
- @Export
- static boolean runnable() {
- Object obj = new Object();
- return obj instanceof Integer;
- }
- }
-
@Test
public void checkcast() throws IOException {
compileErrorTest( "Unknown operator: CAST", CheckcastMethod.class );
diff --git a/test/de/inetsoftware/jwebassembly/runtime/StructsNonGC.java b/test/de/inetsoftware/jwebassembly/runtime/StructsNonGC.java
index 302e974..5243829 100644
--- a/test/de/inetsoftware/jwebassembly/runtime/StructsNonGC.java
+++ b/test/de/inetsoftware/jwebassembly/runtime/StructsNonGC.java
@@ -17,6 +17,8 @@ package de.inetsoftware.jwebassembly.runtime;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
import org.junit.ClassRule;
import org.junit.runners.Parameterized.Parameters;
@@ -50,6 +52,9 @@ public class StructsNonGC extends AbstractBaseTest {
addParam( list, script, "useGlobalObject" );
addParam( list, script, "multipleAssign" );
addParam( list, script, "getDefaultValue" );
+ addParam( list, script, "instanceof1" );
+ addParam( list, script, "instanceof2" );
+ addParam( list, script, "instanceof3" );
}
rule.setTestParameters( list );
return list;
@@ -143,6 +148,24 @@ public class StructsNonGC extends AbstractBaseTest {
Abc2 val = new Abc2();
return val.getDefault();
}
+
+ @Export
+ static boolean instanceof1() {
+ Object obj = new Object();
+ return obj instanceof Integer;
+ }
+
+ @Export
+ static boolean instanceof2() {
+ Object obj = new Object();
+ return obj instanceof Object;
+ }
+
+ @Export
+ static boolean instanceof3() {
+ Object obj = new LinkedList();
+ return obj instanceof List;
+ }
}
interface TestDefault {