use synthetic method for dup instruction to handle the type dynamically

This commit is contained in:
Volker Berlin 2019-01-20 10:41:33 +01:00
parent 238a281757
commit 29911bc586
5 changed files with 131 additions and 69 deletions

View File

@ -274,25 +274,9 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
break; break;
case 89: // dup: duplicate the value on top of the stack case 89: // dup: duplicate the value on top of the stack
case 92: // dup2 case 92: // dup2
switch( findPreviousPushInstructionPushValueType() ) { storeType = findPreviousPushInstructionPushValueType();
case i32: addCallInstruction( new SyntheticFunctionName( "dup" + storeType, "get_local 0 get_local 0 return", storeType, null, storeType, storeType ), codePos );
addCallInstruction( new SyntheticMember( "de/inetsoftware/jwebassembly/module/NativeHelperCode", "dup_i32", "(I)II" ), codePos ); break;
break OP;
case f32:
addCallInstruction( new SyntheticMember( "de/inetsoftware/jwebassembly/module/NativeHelperCode", "dup_f32", "(F)FF" ), codePos );
break OP;
case i64:
addCallInstruction( new SyntheticMember( "de/inetsoftware/jwebassembly/module/NativeHelperCode", "dup_i64", "(J)JJ" ), codePos );
break OP;
case f64:
addCallInstruction( new SyntheticMember( "de/inetsoftware/jwebassembly/module/NativeHelperCode", "dup_f64", "(D)DD" ), codePos );
break OP;
case anyref:
addCallInstruction( new SyntheticMember( "de/inetsoftware/jwebassembly/module/NativeHelperCode", "dup_anyref", "(Ljava.lang.Object;)Ljava.lang.Object;Ljava.lang.Object;" ), codePos );
break OP;
default:
}
//$FALL-THROUGH$
case 90: // dup_x1 case 90: // dup_x1
case 91: // dup_x2 case 91: // dup_x2
case 93: // dup2_x1 case 93: // dup2_x1
@ -576,7 +560,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
case 184: // invokestatic case 184: // invokestatic
idx = byteCode.readUnsignedShort(); idx = byteCode.readUnsignedShort();
ref = (ConstantRef)constantPool.get( idx ); ref = (ConstantRef)constantPool.get( idx );
addCallInstruction( ref, codePos ); addCallInstruction( new FunctionName( ref ), codePos );
break; break;
//TODO case 185: // invokeinterface //TODO case 185: // invokeinterface
//TODO case 186: // invokedynamic //TODO case 186: // invokedynamic

View File

@ -110,29 +110,35 @@ public class ModuleGenerator {
while( (next = functions.nextWriteLater()) != null ) { while( (next = functions.nextWriteLater()) != null ) {
InputStream stream = libraries.getResourceAsStream( next.className + ".class" ); InputStream stream = libraries.getResourceAsStream( next.className + ".class" );
if( stream == null ) { if( stream == null ) {
throw new WasmException( "Missing function: " + next.signatureName, -1 ); if( next instanceof SyntheticFunctionName ) {
} watParser.parse( ((SyntheticFunctionName)next).getCode(), -1 );
ClassFile classFile = new ClassFile( stream ); writeMethodImpl( next, true, null, watParser );
iterateMethods( classFile, method -> { } else {
try { throw new WasmException( "Missing function: " + next.signatureName, -1 );
FunctionName name;
Map<String, Object> wat = method.getAnnotation( JWebAssembly.TEXTCODE_ANNOTATION );
if( wat != null ) {
String signature = (String)wat.get( "signature" );
if( signature == null ) {
signature = method.getType();
}
name = new FunctionName( method, signature );
} else {
name = new FunctionName( method );
}
if( functions.isToWrite( name ) ) {
writeMethod( method );
}
} catch (IOException ioex){
throw WasmException.create( ioex, sourceFile, className, -1 );
} }
} ); } else {
ClassFile classFile = new ClassFile( stream );
iterateMethods( classFile, method -> {
try {
FunctionName name;
Map<String, Object> wat = method.getAnnotation( JWebAssembly.TEXTCODE_ANNOTATION );
if( wat != null ) {
String signature = (String)wat.get( "signature" );
if( signature == null ) {
signature = method.getType();
}
name = new FunctionName( method, signature );
} else {
name = new FunctionName( method );
}
if( functions.isToWrite( name ) ) {
writeMethod( method );
}
} catch (IOException ioex){
throw WasmException.create( ioex, sourceFile, className, -1 );
}
} );
}
if( functions.isToWrite( next ) ) { if( functions.isToWrite( next ) ) {
throw new WasmException( "Missing function: " + next.signatureName, -1 ); throw new WasmException( "Missing function: " + next.signatureName, -1 );
@ -268,6 +274,7 @@ public class ModuleGenerator {
} }
WasmCodeBuilder codeBuilder; WasmCodeBuilder codeBuilder;
Code code = method.getCode(); Code code = method.getCode();
LocalVariableTable localVariableTable;
FunctionName name; FunctionName name;
if( method.getAnnotation( JWebAssembly.TEXTCODE_ANNOTATION ) != null ) { if( method.getAnnotation( JWebAssembly.TEXTCODE_ANNOTATION ) != null ) {
Map<String, Object> wat = method.getAnnotation( JWebAssembly.TEXTCODE_ANNOTATION ); Map<String, Object> wat = method.getAnnotation( JWebAssembly.TEXTCODE_ANNOTATION );
@ -279,38 +286,43 @@ public class ModuleGenerator {
name = new FunctionName( method, signature ); name = new FunctionName( method, signature );
watParser.parse( watCode, code == null ? -1 : code.getFirstLineNr() ); watParser.parse( watCode, code == null ? -1 : code.getFirstLineNr() );
codeBuilder = watParser; codeBuilder = watParser;
localVariableTable = null;
} else if( code != null ) { // abstract methods and interface methods does not have code } else if( code != null ) { // abstract methods and interface methods does not have code
name = new FunctionName( method ); name = new FunctionName( method );
javaCodeBuilder.buildCode( code, !method.getType().endsWith( ")V" ) ); javaCodeBuilder.buildCode( code, !method.getType().endsWith( ")V" ) );
codeBuilder = javaCodeBuilder; codeBuilder = javaCodeBuilder;
localVariableTable = code.getLocalVariableTable();
} else { } else {
return; return;
} }
writeExport( name, method ); writeExport( name, method );
writer.writeMethodStart( name ); writeMethodImpl( name, method.isStatic(), localVariableTable, codeBuilder );
functions.writeFunction( name );
LocalVariableTable localVariableTable = code == null ? null : code.getLocalVariableTable();
writeMethodSignature( name, method.isStatic(), localVariableTable, codeBuilder );
for( WasmInstruction instruction : codeBuilder.getInstructions() ) {
switch( instruction.getType() ) {
case Call:
functions.functionCall( ((WasmCallInstruction)instruction).getFunctionName() );
break;
case Struct:
setStructType( (WasmStructInstruction)instruction );
break;
default:
}
instruction.writeTo( writer );
}
writer.writeMethodFinish();
} catch( Exception ioex ) { } catch( Exception ioex ) {
int lineNumber = byteCode == null ? -1 : byteCode.getLineNumber(); int lineNumber = byteCode == null ? -1 : byteCode.getLineNumber();
throw WasmException.create( ioex, sourceFile, className, lineNumber ); throw WasmException.create( ioex, sourceFile, className, lineNumber );
} }
} }
private void writeMethodImpl( FunctionName name, boolean isStatic, LocalVariableTable localVariableTable, WasmCodeBuilder codeBuilder ) throws WasmException, IOException {
writer.writeMethodStart( name );
functions.writeFunction( name );
writeMethodSignature( name, isStatic, localVariableTable, codeBuilder );
for( WasmInstruction instruction : codeBuilder.getInstructions() ) {
switch( instruction.getType() ) {
case Call:
functions.functionCall( ((WasmCallInstruction)instruction).getFunctionName() );
break;
case Struct:
setStructType( (WasmStructInstruction)instruction );
break;
default:
}
instruction.writeTo( writer );
}
writer.writeMethodFinish();
}
/** /**
* Look for a Export annotation and if there write an export directive. * Look for a Export annotation and if there write an export directive.
* *

View File

@ -0,0 +1,67 @@
/*
Copyright 2019 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 java.util.Arrays;
import java.util.Iterator;
import de.inetsoftware.jwebassembly.wasm.AnyType;
/**
* Synthetic/dynamic method.
*
* @author Volker Berlin
*/
public class SyntheticFunctionName extends FunctionName {
private final AnyType[] signature;
private final String code;
/**
* Create a new instance.
*
* @param name
* the function name
* @param code
* the WAT code (WASM in text form)
* @param signature
* the method signature
*/
public SyntheticFunctionName( String name, String code, AnyType... signature ) {
super( "", name, "()V" ); //TODO better signature name
this.signature = signature;
this.code = code;
}
/**
* {@inheritDoc}
*/
@Override
public Iterator<AnyType> getSignature() {
return Arrays.asList( signature ).iterator();
}
/**
* Get the WAT code (WASM in text form)
*
* @return the code
*/
public String getCode() {
return code;
}
}

View File

@ -21,7 +21,6 @@ import java.util.Iterator;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import de.inetsoftware.classparser.Member;
import de.inetsoftware.jwebassembly.wasm.AnyType; import de.inetsoftware.jwebassembly.wasm.AnyType;
import de.inetsoftware.jwebassembly.wasm.ValueType; import de.inetsoftware.jwebassembly.wasm.ValueType;
@ -42,14 +41,14 @@ class WasmCallInstruction extends WasmInstruction {
/** /**
* Create an instance of a function call instruction * Create an instance of a function call instruction
* *
* @param method * @param name
* the reference to the Java method * the function name that should be called
* @param javaCodePos * @param javaCodePos
* the code position/offset in the Java method * the code position/offset in the Java method
*/ */
WasmCallInstruction( Member method, int javaCodePos ) { WasmCallInstruction( FunctionName name, int javaCodePos ) {
super( javaCodePos ); super( javaCodePos );
this.name = new FunctionName( method ); this.name = name;
} }
/** /**

View File

@ -178,13 +178,13 @@ public abstract class WasmCodeBuilder {
/** /**
* Add a static function call. * Add a static function call.
* *
* @param method * @param name
* reference to a static method * the function name that should be called
* @param javaCodePos * @param javaCodePos
* the code position/offset in the Java method * the code position/offset in the Java method
*/ */
protected void addCallInstruction( Member method, int javaCodePos ) { protected void addCallInstruction( FunctionName name, int javaCodePos ) {
instructions.add( new WasmCallInstruction( method, javaCodePos ) ); instructions.add( new WasmCallInstruction( name, javaCodePos ) );
} }
/** /**