From 29911bc5863bf20feed72a6f4ef3a727b6003721 Mon Sep 17 00:00:00 2001 From: Volker Berlin Date: Sun, 20 Jan 2019 10:41:33 +0100 Subject: [PATCH] use synthetic method for dup instruction to handle the type dynamically --- .../module/JavaMethodWasmCodeBuilder.java | 24 +---- .../jwebassembly/module/ModuleGenerator.java | 92 +++++++++++-------- .../module/SyntheticFunctionName.java | 67 ++++++++++++++ .../module/WasmCallInstruction.java | 9 +- .../jwebassembly/module/WasmCodeBuilder.java | 8 +- 5 files changed, 131 insertions(+), 69 deletions(-) create mode 100644 src/de/inetsoftware/jwebassembly/module/SyntheticFunctionName.java diff --git a/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java index c57b4f3..5c8e175 100644 --- a/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java @@ -274,25 +274,9 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder { break; case 89: // dup: duplicate the value on top of the stack case 92: // dup2 - switch( findPreviousPushInstructionPushValueType() ) { - case i32: - addCallInstruction( new SyntheticMember( "de/inetsoftware/jwebassembly/module/NativeHelperCode", "dup_i32", "(I)II" ), codePos ); - 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$ + storeType = findPreviousPushInstructionPushValueType(); + addCallInstruction( new SyntheticFunctionName( "dup" + storeType, "get_local 0 get_local 0 return", storeType, null, storeType, storeType ), codePos ); + break; case 90: // dup_x1 case 91: // dup_x2 case 93: // dup2_x1 @@ -576,7 +560,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder { case 184: // invokestatic idx = byteCode.readUnsignedShort(); ref = (ConstantRef)constantPool.get( idx ); - addCallInstruction( ref, codePos ); + addCallInstruction( new FunctionName( ref ), codePos ); break; //TODO case 185: // invokeinterface //TODO case 186: // invokedynamic diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java index a8d0d58..dd3989c 100644 --- a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java +++ b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java @@ -110,29 +110,35 @@ public class ModuleGenerator { while( (next = functions.nextWriteLater()) != null ) { InputStream stream = libraries.getResourceAsStream( next.className + ".class" ); if( stream == null ) { - throw new WasmException( "Missing function: " + next.signatureName, -1 ); - } - ClassFile classFile = new ClassFile( stream ); - iterateMethods( classFile, method -> { - try { - FunctionName name; - Map 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( next instanceof SyntheticFunctionName ) { + watParser.parse( ((SyntheticFunctionName)next).getCode(), -1 ); + writeMethodImpl( next, true, null, watParser ); + } else { + throw new WasmException( "Missing function: " + next.signatureName, -1 ); } - } ); + } else { + ClassFile classFile = new ClassFile( stream ); + iterateMethods( classFile, method -> { + try { + FunctionName name; + Map 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 ) ) { throw new WasmException( "Missing function: " + next.signatureName, -1 ); @@ -268,6 +274,7 @@ public class ModuleGenerator { } WasmCodeBuilder codeBuilder; Code code = method.getCode(); + LocalVariableTable localVariableTable; FunctionName name; if( method.getAnnotation( JWebAssembly.TEXTCODE_ANNOTATION ) != null ) { Map wat = method.getAnnotation( JWebAssembly.TEXTCODE_ANNOTATION ); @@ -279,38 +286,43 @@ public class ModuleGenerator { name = new FunctionName( method, signature ); watParser.parse( watCode, code == null ? -1 : code.getFirstLineNr() ); codeBuilder = watParser; + localVariableTable = null; } else if( code != null ) { // abstract methods and interface methods does not have code name = new FunctionName( method ); javaCodeBuilder.buildCode( code, !method.getType().endsWith( ")V" ) ); codeBuilder = javaCodeBuilder; + localVariableTable = code.getLocalVariableTable(); } else { return; } writeExport( name, method ); - writer.writeMethodStart( name ); - 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(); + writeMethodImpl( name, method.isStatic(), localVariableTable, codeBuilder ); } catch( Exception ioex ) { int lineNumber = byteCode == null ? -1 : byteCode.getLineNumber(); 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. * diff --git a/src/de/inetsoftware/jwebassembly/module/SyntheticFunctionName.java b/src/de/inetsoftware/jwebassembly/module/SyntheticFunctionName.java new file mode 100644 index 0000000..497430b --- /dev/null +++ b/src/de/inetsoftware/jwebassembly/module/SyntheticFunctionName.java @@ -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 getSignature() { + return Arrays.asList( signature ).iterator(); + } + + /** + * Get the WAT code (WASM in text form) + * + * @return the code + */ + public String getCode() { + return code; + } +} diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCallInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmCallInstruction.java index 16beda0..5892139 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCallInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCallInstruction.java @@ -21,7 +21,6 @@ import java.util.Iterator; import javax.annotation.Nonnull; -import de.inetsoftware.classparser.Member; import de.inetsoftware.jwebassembly.wasm.AnyType; import de.inetsoftware.jwebassembly.wasm.ValueType; @@ -42,14 +41,14 @@ class WasmCallInstruction extends WasmInstruction { /** * Create an instance of a function call instruction * - * @param method - * the reference to the Java method + * @param name + * the function name that should be called * @param javaCodePos * the code position/offset in the Java method */ - WasmCallInstruction( Member method, int javaCodePos ) { + WasmCallInstruction( FunctionName name, int javaCodePos ) { super( javaCodePos ); - this.name = new FunctionName( method ); + this.name = name; } /** diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java index 19dfa0b..cefe5ce 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java @@ -178,13 +178,13 @@ public abstract class WasmCodeBuilder { /** * Add a static function call. * - * @param method - * reference to a static method + * @param name + * the function name that should be called * @param javaCodePos * the code position/offset in the Java method */ - protected void addCallInstruction( Member method, int javaCodePos ) { - instructions.add( new WasmCallInstruction( method, javaCodePos ) ); + protected void addCallInstruction( FunctionName name, int javaCodePos ) { + instructions.add( new WasmCallInstruction( name, javaCodePos ) ); } /**