mirror of
https://github.com/i-net-software/JWebAssembly.git
synced 2025-03-25 07:27:52 +01:00
implementation of a a replacement for java.lang.Class
This commit is contained in:
parent
a6f1743109
commit
946e911982
@ -472,7 +472,11 @@ public class ModuleGenerator {
|
|||||||
javaCodeBuilder.buildCode( code, method );
|
javaCodeBuilder.buildCode( code, method );
|
||||||
return javaCodeBuilder;
|
return javaCodeBuilder;
|
||||||
} else {
|
} else {
|
||||||
throw new WasmException( "Abstract or native method can not be used: " + new FunctionName( method ).signatureName, -1 );
|
FunctionName name = new FunctionName( method );
|
||||||
|
if( "de/inetsoftware/jwebassembly/module/ReplacementForClass.typeTableMemoryOffset()I".equals( name.signatureName ) ) {
|
||||||
|
return types.getTypeTableMemoryOffsetFunctionName().getCodeBuilder( watParser );
|
||||||
|
}
|
||||||
|
throw new WasmException( "Abstract or native method can not be used: " + name.signatureName, -1 );
|
||||||
}
|
}
|
||||||
} catch( Exception ioex ) {
|
} catch( Exception ioex ) {
|
||||||
int lineNumber = code == null ? -1 : code.getFirstLineNr();
|
int lineNumber = code == null ? -1 : code.getFirstLineNr();
|
||||||
@ -533,7 +537,7 @@ public class ModuleGenerator {
|
|||||||
StructType structType = instr.getStructType();
|
StructType structType = instr.getStructType();
|
||||||
List<NamedStorageType> list = structType.getFields();
|
List<NamedStorageType> list = structType.getFields();
|
||||||
for( NamedStorageType storageType : list ) {
|
for( NamedStorageType storageType : list ) {
|
||||||
if( TypeManager.VTABLE == storageType.getName() ) {
|
if( TypeManager.FIELD_VTABLE == storageType.getName() ) {
|
||||||
writer.writeConst( structType.getVTable(), ValueType.i32 );
|
writer.writeConst( structType.getVTable(), ValueType.i32 );
|
||||||
} else {
|
} else {
|
||||||
writer.writeDefaultValue( storageType.getType() );
|
writer.writeDefaultValue( storageType.getType() );
|
||||||
|
151
src/de/inetsoftware/jwebassembly/module/ReplacementForClass.java
Normal file
151
src/de/inetsoftware/jwebassembly/module/ReplacementForClass.java
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 Volker Berlin (i-net software)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
package de.inetsoftware.jwebassembly.module;
|
||||||
|
|
||||||
|
import de.inetsoftware.jwebassembly.api.annotation.Replace;
|
||||||
|
import de.inetsoftware.jwebassembly.api.annotation.WasmTextCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replacement for java.lang.Class
|
||||||
|
*
|
||||||
|
* @author Volker Berlin
|
||||||
|
*/
|
||||||
|
@Replace( "java/lang/Class" )
|
||||||
|
class ReplacementForClass {
|
||||||
|
|
||||||
|
private final int vtable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a instance
|
||||||
|
*
|
||||||
|
* @param vtable
|
||||||
|
* the pointer in the memory for the class/type description.
|
||||||
|
*/
|
||||||
|
private ReplacementForClass( int vtable ) {
|
||||||
|
this.vtable = vtable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replacement for {@link Class#getName()}
|
||||||
|
*
|
||||||
|
* @return the name
|
||||||
|
*/
|
||||||
|
String getName() {
|
||||||
|
return StringManager.stringConstant( getIntFromMemory( vtable + TypeManager.TYPE_DESCRIPTION_TYPE_NAME ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replacement for {@link Object#getClass()}
|
||||||
|
*
|
||||||
|
* @param obj
|
||||||
|
* the instance
|
||||||
|
* @return the class
|
||||||
|
*/
|
||||||
|
@WasmTextCode( "local.get 0 " // THIS
|
||||||
|
+ "struct.get java/lang/Object .vtable " // vtable is on index 0
|
||||||
|
+ "call $de/inetsoftware/jwebassembly/module/ReplacementForClass.classConstant(I)Lde/inetsoftware/jwebassembly/module/ReplacementForClass; " //
|
||||||
|
+ "return " //
|
||||||
|
)
|
||||||
|
@Replace( "java/lang/Object.getClass()Ljava/lang/Class;" )
|
||||||
|
private static native ReplacementForClass getClassObject( Object obj );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WASM code
|
||||||
|
* <p>
|
||||||
|
* Get a constant Class from the table.
|
||||||
|
*
|
||||||
|
* @param classIdx
|
||||||
|
* the id/index of the Class.
|
||||||
|
* @return the string
|
||||||
|
* @see #CLASS_CONSTANT_FUNCTION
|
||||||
|
*/
|
||||||
|
private static ReplacementForClass classConstant( int classIdx ) {
|
||||||
|
ReplacementForClass clazz = getClassFromTable( classIdx );
|
||||||
|
if( clazz != null ) {
|
||||||
|
return clazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
The memory/data section has the follow content:
|
||||||
|
┌──────────────────────────────────┐
|
||||||
|
| Type/Class descriptions (vtable) |
|
||||||
|
├──────────────────────────────────┤
|
||||||
|
| Type/Class table |
|
||||||
|
├──────────────────────────────────┤
|
||||||
|
| String table |
|
||||||
|
└──────────────────────────────────┘
|
||||||
|
*/
|
||||||
|
int vtable = getIntFromMemory( classIdx * 4 + typeTableMemoryOffset() );
|
||||||
|
clazz = new ReplacementForClass( vtable );
|
||||||
|
// save the string for future use
|
||||||
|
setClassIntoTable( classIdx, clazz );
|
||||||
|
return clazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WASM code
|
||||||
|
* <p>
|
||||||
|
* Get a Class instance from the Class table. Should be inlined from the optimizer.
|
||||||
|
*
|
||||||
|
* @param classIdx
|
||||||
|
* the id/index of the Class.
|
||||||
|
* @return the string or null if not already set.
|
||||||
|
*/
|
||||||
|
@WasmTextCode( "local.get 0 " + //
|
||||||
|
"table.get 2 " + // table 2 is used for classes
|
||||||
|
"return" )
|
||||||
|
private static native ReplacementForClass getClassFromTable( int classIdx );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WASM code
|
||||||
|
* <p>
|
||||||
|
* Set a string from the string table. Should be inlined from the optimizer.
|
||||||
|
*
|
||||||
|
* @param strIdx
|
||||||
|
* the id/index of the string.
|
||||||
|
* @param str
|
||||||
|
* the string
|
||||||
|
*/
|
||||||
|
@WasmTextCode( "local.get 0 " + //
|
||||||
|
"local.get 1 " + //
|
||||||
|
"table.set 2 " + //
|
||||||
|
"return" )
|
||||||
|
private static native void setClassIntoTable( int strIdx, ReplacementForClass clazz );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WASM code
|
||||||
|
* <p>
|
||||||
|
* Placeholder for a synthetic function. Should be inlined from the optimizer.
|
||||||
|
*
|
||||||
|
* @return the memory offset of the string data in the element section
|
||||||
|
*/
|
||||||
|
private static native int typeTableMemoryOffset();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WASM code
|
||||||
|
* <p>
|
||||||
|
* Load an i32 from memory. The offset must be aligned. Should be inlined from the optimizer.
|
||||||
|
*
|
||||||
|
* @param pos
|
||||||
|
* the memory position
|
||||||
|
* @return the value from the memory
|
||||||
|
*/
|
||||||
|
@WasmTextCode( "local.get 0 " + //
|
||||||
|
"i32.load offset=0 align=4 " + //
|
||||||
|
"return" )
|
||||||
|
private static native int getIntFromMemory( int pos );
|
||||||
|
}
|
@ -190,7 +190,7 @@ public class StringManager extends LinkedHashMap<String, Integer> {
|
|||||||
* @return the string
|
* @return the string
|
||||||
* @see #STRING_CONSTANT_FUNCTION
|
* @see #STRING_CONSTANT_FUNCTION
|
||||||
*/
|
*/
|
||||||
private static String stringConstant( int strIdx ) {
|
static String stringConstant( int strIdx ) {
|
||||||
String str = getStringFromTable( strIdx );
|
String str = getStringFromTable( strIdx );
|
||||||
if( str != null ) {
|
if( str != null ) {
|
||||||
return str;
|
return str;
|
||||||
|
@ -50,12 +50,27 @@ import de.inetsoftware.jwebassembly.wasm.ValueType;
|
|||||||
public class TypeManager {
|
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 FIELD_VTABLE = ".vtable";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of field with system hash code, start with a point for an invalid Java identifier.
|
* Name of field with system hash code, start with a point for an invalid Java identifier.
|
||||||
*/
|
*/
|
||||||
static final String HASHCODE = ".hashcode";
|
static final String FIELD_HASHCODE = ".hashcode";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Byte position in the type description that contains the offset to the interfaces. Length 4 bytes.
|
||||||
|
*/
|
||||||
|
static final int TYPE_DESCRIPTION_INTERFACE_OFFSET = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Byte position in the type description that contains the offset to the instanceof list. Length 4 bytes.
|
||||||
|
*/
|
||||||
|
static final int TYPE_DESCRIPTION_INSTANCEOF_OFFSET = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Byte position in the type description that contains the offset to class name idx. Length 4 bytes.
|
||||||
|
*/
|
||||||
|
static final int TYPE_DESCRIPTION_TYPE_NAME = 8;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The reserved position on start of the vtable:
|
* The reserved position on start of the vtable:
|
||||||
@ -72,6 +87,8 @@ public class TypeManager {
|
|||||||
|
|
||||||
private final WasmOptions options;
|
private final WasmOptions options;
|
||||||
|
|
||||||
|
private int typeTableOffset;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the type manager.
|
* Initialize the type manager.
|
||||||
*
|
*
|
||||||
@ -108,6 +125,29 @@ public class TypeManager {
|
|||||||
for( StructType type : structTypes.values() ) {
|
for( StructType type : structTypes.values() ) {
|
||||||
type.writeStructType( writer, functions, this, classFileLoader );
|
type.writeStructType( writer, functions, this, classFileLoader );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// write type table
|
||||||
|
ByteArrayOutputStream dataStream = writer.dataStream;
|
||||||
|
typeTableOffset = dataStream.size();
|
||||||
|
for( StructType type : structTypes.values() ) {
|
||||||
|
dataStream.write( type.vtableOffset );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an accessor for typeTableOffset and mark it.
|
||||||
|
*
|
||||||
|
* @return the function name
|
||||||
|
*/
|
||||||
|
WatCodeSyntheticFunctionName getTypeTableMemoryOffsetFunctionName() {
|
||||||
|
WatCodeSyntheticFunctionName offsetFunction =
|
||||||
|
new WatCodeSyntheticFunctionName( "de/inetsoftware/jwebassembly/module/ReplacementForClass", "typeTableMemoryOffset", "()I", "", null, ValueType.i32 ) {
|
||||||
|
protected String getCode() {
|
||||||
|
return "i32.const " + typeTableOffset;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
options.functions.markAsNeeded( offsetFunction );
|
||||||
|
return offsetFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -352,8 +392,8 @@ public class TypeManager {
|
|||||||
String superClassName = superClass.getName();
|
String superClassName = superClass.getName();
|
||||||
listStructFields( superClassName, functions, types, classFileLoader, allNeededFields );
|
listStructFields( superClassName, functions, types, classFileLoader, allNeededFields );
|
||||||
} else {
|
} else {
|
||||||
fields.add( new NamedStorageType( ValueType.i32, className, VTABLE ) );
|
fields.add( new NamedStorageType( ValueType.i32, className, FIELD_VTABLE ) );
|
||||||
fields.add( new NamedStorageType( ValueType.i32, className, HASHCODE ) );
|
fields.add( new NamedStorageType( ValueType.i32, className, FIELD_HASHCODE ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
for( FieldInfo field : classFile.getFields() ) {
|
for( FieldInfo field : classFile.getFields() ) {
|
||||||
@ -443,6 +483,23 @@ public class TypeManager {
|
|||||||
* should never occur
|
* should never occur
|
||||||
*/
|
*/
|
||||||
public void writeToStream( ByteArrayOutputStream dataStream, ToIntFunction<FunctionName> getFunctionsID ) throws IOException {
|
public void writeToStream( ByteArrayOutputStream dataStream, ToIntFunction<FunctionName> getFunctionsID ) throws IOException {
|
||||||
|
/*
|
||||||
|
┌───────────────────────────────────────┐
|
||||||
|
| Offset to the interfaces (4 bytes) |
|
||||||
|
├───────────────────────────────────────┤
|
||||||
|
| Offset to the instanceof (4 bytes) |
|
||||||
|
├───────────────────────────────────────┤
|
||||||
|
| String id of the class name (4 bytes) |
|
||||||
|
├───────────────────────────────────────┤
|
||||||
|
| first vtable entry (4 bytes) |
|
||||||
|
├───────────────────────────────────────┤
|
||||||
|
| ..... |
|
||||||
|
├───────────────────────────────────────┤
|
||||||
|
| interface calls (itable) |
|
||||||
|
├───────────────────────────────────────┤
|
||||||
|
| list of implemented interface |
|
||||||
|
└───────────────────────────────────────┘
|
||||||
|
*/
|
||||||
this.vtableOffset = dataStream.size();
|
this.vtableOffset = dataStream.size();
|
||||||
|
|
||||||
LittleEndianOutputStream header = new LittleEndianOutputStream( dataStream );
|
LittleEndianOutputStream header = new LittleEndianOutputStream( dataStream );
|
||||||
@ -452,9 +509,11 @@ public class TypeManager {
|
|||||||
data.writeInt32( functIdx );
|
data.writeInt32( functIdx );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// header position TYPE_DESCRIPTION_INTERFACE_OFFSET
|
||||||
header.writeInt32( data.size() + VTABLE_FIRST_FUNCTION_INDEX * 4 ); // offset of interface calls
|
header.writeInt32( data.size() + VTABLE_FIRST_FUNCTION_INDEX * 4 ); // offset of interface calls
|
||||||
//TODO interface calls
|
//TODO interface calls
|
||||||
|
|
||||||
|
// header position TYPE_DESCRIPTION_INSTANCEOF_OFFSET
|
||||||
header.writeInt32( data.size() + VTABLE_FIRST_FUNCTION_INDEX * 4 ); // offset of instanceeof list
|
header.writeInt32( data.size() + VTABLE_FIRST_FUNCTION_INDEX * 4 ); // offset of instanceeof list
|
||||||
data.writeInt32( instanceOFs.size() );
|
data.writeInt32( instanceOFs.size() );
|
||||||
for( StructType type : instanceOFs ) {
|
for( StructType type : instanceOFs ) {
|
||||||
@ -462,6 +521,7 @@ public class TypeManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int classNameIdx = options.strings.get( getName().replace( '/', '.' ) );
|
int classNameIdx = options.strings.get( getName().replace( '/', '.' ) );
|
||||||
|
// header position TYPE_DESCRIPTION_TYPE_NAME
|
||||||
header.writeInt32( classNameIdx ); // string id of the className
|
header.writeInt32( classNameIdx ); // string id of the className
|
||||||
|
|
||||||
data.writeTo( dataStream );
|
data.writeTo( dataStream );
|
||||||
|
@ -91,7 +91,7 @@ class WasmStructInstruction extends WasmInstruction {
|
|||||||
}
|
}
|
||||||
js.append( i ).append( ':' );
|
js.append( i ).append( ':' );
|
||||||
NamedStorageType storageType = list.get( i );
|
NamedStorageType storageType = list.get( i );
|
||||||
if( TypeManager.VTABLE == storageType.getName() ) {
|
if( TypeManager.FIELD_VTABLE == storageType.getName() ) {
|
||||||
js.append( type.getVTable() );
|
js.append( type.getVTable() );
|
||||||
} else {
|
} else {
|
||||||
AnyType fieldType = storageType.getType();
|
AnyType fieldType = storageType.getType();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user