implements reading from constant strings from memory

This commit is contained in:
Volker Berlin 2019-11-23 20:39:10 +01:00
parent 835cf45f61
commit f61cebd285
5 changed files with 158 additions and 24 deletions

View File

@ -28,7 +28,21 @@ import de.inetsoftware.jwebassembly.wasm.AnyType;
*/
public abstract class ArraySyntheticFunctionName extends SyntheticFunctionName {
private final AnyType[] signature;
private final AnyType[] signatureTypes;
/**
* Create a new instance.
*
* @param className
* the Java class name
* @param name
* the function name
* @param signatureTypes
* the method signature, first the parameters, then null and the the return types
*/
public ArraySyntheticFunctionName( String className, String name, AnyType... signatureTypes ) {
this( className, name, "()V", signatureTypes ); //TODO better signature name
}
/**
* Create a new instance.
@ -38,11 +52,13 @@ public abstract class ArraySyntheticFunctionName extends SyntheticFunctionName {
* @param name
* the function name
* @param signature
* the string signature
* @param signatureTypes
* the method signature, first the parameters, then null and the the return types
*/
public ArraySyntheticFunctionName( String className, String name, AnyType... signature ) {
super( className, name, "()V" ); //TODO better signature name
this.signature = signature;
public ArraySyntheticFunctionName( String className, String name, String signature, AnyType... signatureTypes ) {
super( className, name, signature );
this.signatureTypes = signatureTypes;
}
/**
@ -50,6 +66,6 @@ public abstract class ArraySyntheticFunctionName extends SyntheticFunctionName {
*/
@Override
public Iterator<AnyType> getSignature( TypeManager types ) {
return Arrays.asList( signature ).iterator();
return Arrays.asList( signatureTypes ).iterator();
}
}

View File

@ -95,6 +95,7 @@ public class ModuleGenerator {
this.libraries = new URLClassLoader( libraries.toArray( new URL[libraries.size()] ) );
WasmOptions options = writer.options;
types.init( options );
strings.init( functions );
javaCodeBuilder.init( types, functions, strings, options );
((WasmCodeBuilder)watParser).init( types, functions, strings, options );
scanLibraries( libraries );

View File

@ -24,6 +24,9 @@ import java.util.LinkedHashMap;
import javax.annotation.Nonnegative;
import de.inetsoftware.jwebassembly.api.annotation.WasmTextCode;
import de.inetsoftware.jwebassembly.wasm.ValueType;
/**
* Handle all the constant strings. The constant strings will be write into the data section.
*
@ -31,6 +34,12 @@ import javax.annotation.Nonnegative;
*/
class StringManager extends LinkedHashMap<String, Integer> {
private FunctionManager functions;
void init( FunctionManager functions ) {
this.functions = functions;
}
/**
* Finish the prepare. Now no new strings should be added.
*
@ -41,7 +50,12 @@ class StringManager extends LinkedHashMap<String, Integer> {
*/
void prepareFinish( ModuleWriter writer ) throws IOException {
// inform the writer of string count that it can allocate a table of type anyref for the constant strings
writer.setStringCount( size() );
int size = size();
writer.setStringCount( size );
if( size == 0 ) {
// no strings, nothing to do
return;
}
/* Write the strings to the data sections.
first there is a index table, then follows the strings
@ -68,7 +82,10 @@ class StringManager extends LinkedHashMap<String, Integer> {
ByteArrayOutputStream stringOut = new ByteArrayOutputStream();
ByteArrayOutputStream dataStream = writer.dataStream;
int offset = dataStream.size() + size() * 4;
int offset = dataStream.size();
WatCodeSyntheticFunctionName stringMemoryOffset = new WatCodeSyntheticFunctionName( "de/inetsoftware/jwebassembly/module/StringManager", "stringsMemoryOffset", "()I", "i32.const " + offset, null, ValueType.i32 );
// functions.markAsNeeded( stringMemoryOffset, true );
offset += size * 4;
for( String str : this.keySet() ) {
// write the position where the string starts in the data section
@ -110,4 +127,98 @@ class StringManager extends LinkedHashMap<String, Integer> {
out.write( b );
} while( value != 0 );
}
/**
* Signature of method stringConstant.
* @see #stringConstant(int)
*/
static final String STRING_CONSTANT_SIGNATURE = "de/inetsoftware/jwebassembly/module/StringManager.stringConstant(I)Ljava/lang/String;";
/**
* WASM code
* Get a constant string from the table.
*
* @param strIdx the id/index of the string.
* @return the string
* @see #STRING_CONSTANT_SIGNATURE
*/
private static String stringConstant( int strIdx ) {
String str = getStringFromTable( strIdx );
if( str != null ) {
return str;
}
int offset = getIntFromMemory( strIdx * 4 + stringsMemoryOffset() );
int length = 0;
int b;
do {
b = getUnsignedByteFromMemory( offset++ );
length = (length << 7) + (b & 0x7F);
} while( b >= 0x80 );
byte[] bytes = new byte[length];
for( int i = 0; i < length; i++ ) {
bytes[i] = getUnsignedByteFromMemory( i + offset );
}
str = new String( bytes );
setStringIntoTable( strIdx, str );
return str;
}
/**
* WASM code
* Get a string from the string table. Should be inlined from the optimizer.
*
* @param strIdx
* the id/index of the string.
* @return the string or null if not already set.
*/
@WasmTextCode( "local.get 0 " + //
"table.get 1 " + //
"return" )
private static native String getStringFromTable( int strIdx );
/**
* WASM code
* 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 1 " + //
"return" )
private static native void setStringIntoTable( int strIdx, String str );
@WasmTextCode( "i32.const 0" )
private static native int stringsMemoryOffset();
/**
* WASM code
* Load an i32 from memory. The offset must be aligned.
*
* @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 );
/**
* WASM code
* Load a byte from the memory.
*
* @param pos
* the memory position
* @return the value from the memory
*/
@WasmTextCode( "local.get 0 " + //
"i32.load8_u offset=0 " + //
"return" )
private static native byte getUnsignedByteFromMemory( int pos );
}

View File

@ -357,20 +357,7 @@ public abstract class WasmCodeBuilder {
if( id == null ) {
strings.put( (String)value, id = strings.size() );
}
String wat = "local.get 0 " + //
"table.get 1 " + // strings table
"local.tee 1 " + //
"ref.is_null " + //
"if " + //
"local.get 0 " + //
"i32.const 4 " + //
"i32.mul " + //
"i32.load offset=0 " + //
"drop " + //
"end " + //
"local.get 1 " + //
"return";
FunctionName name = new WatCodeSyntheticFunctionName( "stringConstant", wat, ValueType.i32, null, ValueType.anyref );
FunctionName name = new FunctionName( StringManager.STRING_CONSTANT_SIGNATURE );
instructions.add( new WasmConstInstruction( id, ValueType.i32, javaCodePos, lineNumber ) );
addCallInstruction( name, javaCodePos, lineNumber );
} else {

View File

@ -35,11 +35,30 @@ class WatCodeSyntheticFunctionName extends ArraySyntheticFunctionName {
* the function name
* @param code
* the WAT code (WASM in text form)
* @param signature
* @param signatureTypes
* the method signature, first the parameters, then null and the the return types
*/
public WatCodeSyntheticFunctionName( String name, String code, AnyType... signature ) {
super( "", name, signature );
public WatCodeSyntheticFunctionName( String name, String code, AnyType... signatureTypes ) {
super( "", name, signatureTypes );
this.code = code;
}
/**
* Create a new instance.
*
* @param className
* the Java class name
* @param name
* the function name
* @param code
* the WAT code (WASM in text form)
* @param signature
* the string signature
* @param signatureTypes
* the method signature, first the parameters, then null and the the return types
*/
public WatCodeSyntheticFunctionName( String className, String name, String signature, String code, AnyType... signatureTypes ) {
super( className, name, signature, signatureTypes );
this.code = code;
}