mirror of
https://github.com/i-net-software/JWebAssembly.git
synced 2025-03-25 07:27:52 +01:00
implements INSTANCEOF operation
This commit is contained in:
parent
0138eb5dc0
commit
6c820ba5e6
@ -52,6 +52,11 @@ public class TypeManager {
|
|||||||
/** name of virtual function table, start with a point for an invalid Java identifier */
|
/** name of virtual function table, start with a point for an invalid Java identifier */
|
||||||
static final String VTABLE = ".vtable";
|
static final String VTABLE = ".vtable";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The reserved position on start of the vtable:
|
||||||
|
* <li>offset of interface call table (itable)
|
||||||
|
* <li>offset of instanceof list
|
||||||
|
*/
|
||||||
private static final int VTABLE_FIRST_FUNCTION_INDEX = 2;
|
private static final int VTABLE_FIRST_FUNCTION_INDEX = 2;
|
||||||
|
|
||||||
private Map<String, StructType> structTypes = new LinkedHashMap<>();
|
private Map<String, StructType> 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.
|
* virtualfunctionIndex) and returns the index of the function.
|
||||||
*
|
*
|
||||||
* @return the name
|
* @return the name
|
||||||
*/
|
*/
|
||||||
@Nonnull
|
@Nonnull
|
||||||
WatCodeSyntheticFunctionName getCallVirtualGC() {
|
WatCodeSyntheticFunctionName createCallVirtualGC() {
|
||||||
return new WatCodeSyntheticFunctionName( //
|
return new WatCodeSyntheticFunctionName( //
|
||||||
"callVirtual", "local.get 0 " // THIS
|
"callVirtual", "local.get 0 " // THIS
|
||||||
+ "struct.get java/lang/Object .vtable " // vtable is on index 0
|
+ "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 ); //
|
, 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.
|
* 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() ) {
|
for(ConstantClass interClass : classFile.getInterfaces() ) {
|
||||||
StructType type = types.structTypes.get( className );
|
StructType type = types.structTypes.get( interClass.getName() );
|
||||||
if( type != null ) {
|
if( type != null ) {
|
||||||
instanceOFs.add( type );
|
instanceOFs.add( type );
|
||||||
}
|
}
|
||||||
|
@ -52,11 +52,6 @@ import de.inetsoftware.jwebassembly.wasm.WasmBlockOperator;
|
|||||||
*/
|
*/
|
||||||
public abstract class WasmCodeBuilder {
|
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 LocaleVariableManager localVariables = new LocaleVariableManager();
|
||||||
|
|
||||||
private final List<WasmInstruction> instructions = new ArrayList<>();
|
private final List<WasmInstruction> instructions = new ArrayList<>();
|
||||||
@ -497,11 +492,7 @@ public abstract class WasmCodeBuilder {
|
|||||||
}
|
}
|
||||||
indirectCall.setVariableIndexOfThis( varIndex );
|
indirectCall.setVariableIndexOfThis( varIndex );
|
||||||
instructions.add( indirectCall );
|
instructions.add( indirectCall );
|
||||||
if( !options.useGC() ) {
|
options.registerGet_i32(); // for later access of the vtable
|
||||||
// for later access of the vtable
|
|
||||||
functions.markAsNeeded( GET_I32 );
|
|
||||||
functions.markAsImport( GET_I32, GET_I32.getAnnotation() );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -643,6 +634,12 @@ public abstract class WasmCodeBuilder {
|
|||||||
* the line number in the Java source code
|
* the line number in the Java source code
|
||||||
*/
|
*/
|
||||||
protected void addStructInstruction( StructOperator op, @Nonnull String typeName, @Nullable NamedStorageType fieldName, int javaCodePos, int lineNumber ) {
|
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 );
|
WasmStructInstruction structInst = new WasmStructInstruction( op, typeName, fieldName, javaCodePos, lineNumber, types );
|
||||||
instructions.add( structInst );
|
instructions.add( structInst );
|
||||||
if( !options.useGC() ) {
|
if( !options.useGC() ) {
|
||||||
|
@ -20,11 +20,13 @@ import java.util.HashMap;
|
|||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
import de.inetsoftware.jwebassembly.JWebAssembly;
|
import de.inetsoftware.jwebassembly.JWebAssembly;
|
||||||
|
import de.inetsoftware.jwebassembly.javascript.JavaScriptSyntheticFunctionName;
|
||||||
import de.inetsoftware.jwebassembly.module.CodeOptimizer;
|
import de.inetsoftware.jwebassembly.module.CodeOptimizer;
|
||||||
import de.inetsoftware.jwebassembly.module.FunctionManager;
|
import de.inetsoftware.jwebassembly.module.FunctionManager;
|
||||||
import de.inetsoftware.jwebassembly.module.FunctionName;
|
import de.inetsoftware.jwebassembly.module.FunctionName;
|
||||||
import de.inetsoftware.jwebassembly.module.StringManager;
|
import de.inetsoftware.jwebassembly.module.StringManager;
|
||||||
import de.inetsoftware.jwebassembly.module.TypeManager;
|
import de.inetsoftware.jwebassembly.module.TypeManager;
|
||||||
|
import de.inetsoftware.jwebassembly.wasm.ValueType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The option/properties for the behavior of the compiler.
|
* The option/properties for the behavior of the compiler.
|
||||||
@ -55,9 +57,12 @@ public class WasmOptions {
|
|||||||
*/
|
*/
|
||||||
public FunctionName ref_eq;
|
public FunctionName ref_eq;
|
||||||
|
|
||||||
|
private FunctionName get_i32;
|
||||||
|
|
||||||
private FunctionName callVirtual;
|
private FunctionName callVirtual;
|
||||||
|
|
||||||
|
private FunctionName instanceOf;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new instance of options
|
* Create a new instance of options
|
||||||
*
|
*
|
||||||
@ -112,6 +117,21 @@ public class WasmOptions {
|
|||||||
return sourceMapBase;
|
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,
|
* 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.
|
* virtualfunctionIndex) and returns the index of the function.
|
||||||
@ -122,8 +142,26 @@ public class WasmOptions {
|
|||||||
FunctionName getCallVirtual() {
|
FunctionName getCallVirtual() {
|
||||||
FunctionName name = callVirtual;
|
FunctionName name = callVirtual;
|
||||||
if( name == null ) {
|
if( name == null ) {
|
||||||
callVirtual = name = types.getCallVirtualGC();
|
callVirtual = name = types.createCallVirtualGC();
|
||||||
functions.markAsNeeded( name );
|
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;
|
return name;
|
||||||
}
|
}
|
||||||
|
@ -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
|
@Test
|
||||||
public void checkcast() throws IOException {
|
public void checkcast() throws IOException {
|
||||||
compileErrorTest( "Unknown operator: CAST", CheckcastMethod.class );
|
compileErrorTest( "Unknown operator: CAST", CheckcastMethod.class );
|
||||||
|
@ -17,6 +17,8 @@ package de.inetsoftware.jwebassembly.runtime;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.junit.ClassRule;
|
import org.junit.ClassRule;
|
||||||
import org.junit.runners.Parameterized.Parameters;
|
import org.junit.runners.Parameterized.Parameters;
|
||||||
@ -50,6 +52,9 @@ public class StructsNonGC extends AbstractBaseTest {
|
|||||||
addParam( list, script, "useGlobalObject" );
|
addParam( list, script, "useGlobalObject" );
|
||||||
addParam( list, script, "multipleAssign" );
|
addParam( list, script, "multipleAssign" );
|
||||||
addParam( list, script, "getDefaultValue" );
|
addParam( list, script, "getDefaultValue" );
|
||||||
|
addParam( list, script, "instanceof1" );
|
||||||
|
addParam( list, script, "instanceof2" );
|
||||||
|
addParam( list, script, "instanceof3" );
|
||||||
}
|
}
|
||||||
rule.setTestParameters( list );
|
rule.setTestParameters( list );
|
||||||
return list;
|
return list;
|
||||||
@ -143,6 +148,24 @@ public class StructsNonGC extends AbstractBaseTest {
|
|||||||
Abc2 val = new Abc2();
|
Abc2 val = new Abc2();
|
||||||
return val.getDefault();
|
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 {
|
interface TestDefault {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user