From 19a119d7f49d0f0cd03cfbeb9c78c22d5ee1299c Mon Sep 17 00:00:00 2001 From: Volker Berlin Date: Sat, 5 Oct 2019 16:15:18 +0200 Subject: [PATCH] fix position of duplicating THIS on virtual method calls --- .../jwebassembly/module/DupThis.java | 85 +++++++++++++++++++ .../module/WasmCallIndirectInstruction.java | 45 ++++++---- .../jwebassembly/module/WasmCodeBuilder.java | 37 +++++++- .../jwebassembly/module/WasmInstruction.java | 2 +- 4 files changed, 150 insertions(+), 19 deletions(-) create mode 100644 src/de/inetsoftware/jwebassembly/module/DupThis.java diff --git a/src/de/inetsoftware/jwebassembly/module/DupThis.java b/src/de/inetsoftware/jwebassembly/module/DupThis.java new file mode 100644 index 0000000..d4f5cec --- /dev/null +++ b/src/de/inetsoftware/jwebassembly/module/DupThis.java @@ -0,0 +1,85 @@ +/* + 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.io.IOException; + +import de.inetsoftware.jwebassembly.wasm.AnyType; +import de.inetsoftware.jwebassembly.wasm.VariableOperator; + +/** + * This class save a reference of THIS to a temporary variable for a later virtual caLL. The reference of THIS is used for accessing the vtable of the object. + * + * @author Volker Berlin + */ +class DupThis extends WasmInstruction { + + private WasmCallIndirectInstruction virtualCall; + + private int tempVarIdx; + + /** + * Create a instance. + * + * @param virtualCall + * the related virtual function call. + * @param tempVarIdx + * the index of the temporary variable + * @param javaCodePos + * the code position + */ + DupThis( WasmCallIndirectInstruction virtualCall, int tempVarIdx, int javaCodePos ) { + super( javaCodePos, virtualCall.getLineNumber() ); + this.virtualCall = virtualCall; + this.tempVarIdx = tempVarIdx; + } + + /** + * {@inheritDoc} + */ + @Override + Type getType() { + return Type.DupThis; + } + + /** + * {@inheritDoc} + */ + @Override + void writeTo( ModuleWriter writer ) throws IOException { + if( virtualCall.isVirtual() ) { + writer.writeLocal( VariableOperator.tee, tempVarIdx ); + } + } + + /** + * {@inheritDoc} + */ + @Override + AnyType getPushValueType() { + return null; + } + + /** + * {@inheritDoc} + */ + @Override + int getPopCount() { + return 0; + } + +} diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCallIndirectInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmCallIndirectInstruction.java index 8a1a10c..73e255a 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCallIndirectInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCallIndirectInstruction.java @@ -40,12 +40,7 @@ class WasmCallIndirectInstruction extends WasmCallInstruction { private final StructType type; - /** - * the slot of a temporary variable of type "type" to duplicate "this" - */ - private final int tempVar; - - private final LocaleVariableManager localVariables; + private int tempVarIdx; private final WasmOptions options; @@ -54,21 +49,18 @@ class WasmCallIndirectInstruction extends WasmCallInstruction { * * @param name * the function name that should be called - * @param localVariables - * the manager for local variables to translate the Java slot of the temporary variable into wasm local - * position * @param javaCodePos * the code position/offset in the Java method * @param lineNumber * the line number in the Java source code * @param types * the type manager + * @param options + * compiler properties */ - WasmCallIndirectInstruction( FunctionName name, LocaleVariableManager localVariables, int javaCodePos, int lineNumber, TypeManager types, WasmOptions options ) { + WasmCallIndirectInstruction( FunctionName name, int javaCodePos, int lineNumber, TypeManager types, WasmOptions options ) { super( name, javaCodePos, lineNumber, types ); this.type = types.valueOf( name.className ); - this.tempVar = localVariables.getTempVariable( type, javaCodePos, javaCodePos + 1 ); - this.localVariables = localVariables; this.options = options; } @@ -80,6 +72,23 @@ class WasmCallIndirectInstruction extends WasmCallInstruction { return Type.CallIndirect; } + /** + * Get the type of this. + * + * @return the type + */ + StructType getThisType() { + return type; + } + + /** + * Set the variable index on which this can be found. + * @param tempVarIdx the index + */ + void setVariableIndexOfThis( int tempVarIdx ) { + this.tempVarIdx = tempVarIdx; + } + /** * {@inheritDoc} */ @@ -89,6 +98,15 @@ class WasmCallIndirectInstruction extends WasmCallInstruction { virtualFunctionIdx = functions.getFunctionIndex( getFunctionName() ); } + /** + * if this call is executed virtual or if is was optimized. + * + * @return true, virtual call + */ + boolean isVirtual() { + return virtualFunctionIdx > 0; + } + /** * {@inheritDoc} */ @@ -97,10 +115,7 @@ class WasmCallIndirectInstruction extends WasmCallInstruction { if( virtualFunctionIdx < 0 ) { super.writeTo( writer ); } else { - int tempVarIdx = localVariables.get( tempVar, getCodePosition() ); - // duplicate this on the stack - writer.writeLocal( VariableOperator.tee, tempVarIdx ); writer.writeLocal( VariableOperator.get, tempVarIdx ); if( options.useGC() ) { diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java index 72f5f1d..673f592 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java @@ -37,6 +37,7 @@ import de.inetsoftware.jwebassembly.wasm.NumericOperator; import de.inetsoftware.jwebassembly.wasm.StructOperator; import de.inetsoftware.jwebassembly.wasm.ValueType; import de.inetsoftware.jwebassembly.wasm.ValueTypeParser; +import de.inetsoftware.jwebassembly.wasm.VariableOperator; import de.inetsoftware.jwebassembly.wasm.WasmBlockOperator; import de.inetsoftware.jwebassembly.wasm.WasmOptions; @@ -104,8 +105,21 @@ public abstract class WasmCodeBuilder { * the count of values on the stack back. 1 means the last value. 2 means the penultimate value. * @return the code position that push the last instruction */ - @Nonnull int findPushInstructionCodePosition( int count ) { + return findPushInstruction( count, true ); + } + + /** + * We need one value from the stack inside of a block. We need to find the WasmInstruction on which the block can + * start. If this a function call or numeric expression this can be complex to find the right point. + * + * @param count + * the count of values on the stack back. 1 means the last value. 2 means the penultimate value. + * @param codePosition + * true, get the code position; false, get the index in the instructions + * @return the code position that push the last instruction + */ + private int findPushInstruction( int count, boolean codePosition ) { int valueCount = 0; List instructions = this.instructions; for( int i = instructions.size() - 1; i >= 0; i-- ) { @@ -116,7 +130,7 @@ public abstract class WasmCodeBuilder { } valueCount -= instr.getPopCount(); if( valueCount == count ) { - return instr.getCodePosition(); + return codePosition ? instr.getCodePosition() : i; } } throw new WasmException( "Start position not found", -1 ); // should never occur @@ -358,7 +372,24 @@ public abstract class WasmCodeBuilder { * the line number in the Java source code */ protected void addCallVirtualInstruction( FunctionName name, int javaCodePos, int lineNumber ) { - instructions.add( new WasmCallIndirectInstruction( name, localVariables, javaCodePos, lineNumber, types, options ) ); + WasmCallIndirectInstruction virtualCall = new WasmCallIndirectInstruction( name, javaCodePos, lineNumber, types, options ); + int count = virtualCall.getPopCount(); + int idx = findPushInstruction( count, false ); + WasmInstruction instr = instructions.get( idx ); + int varIndex = -1; + if( instr.getType() == Type.Local ) { + WasmLocalInstruction local1 = (WasmLocalInstruction)instr; + if( local1.getOperator() == VariableOperator.get ) { + varIndex = local1.getIndex(); + } + } + if( varIndex < 0 ) { + varIndex = getTempVariable( virtualCall.getThisType(), instr.getCodePosition(), javaCodePos + 1 ); + idx = findPushInstruction( count - 1, false ); + instructions.add( idx, new DupThis( virtualCall, varIndex, javaCodePos ) ); + } + virtualCall.setVariableIndexOfThis( varIndex ); + instructions.add( virtualCall ); } /** diff --git a/src/de/inetsoftware/jwebassembly/module/WasmInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmInstruction.java index 2c17c0d..d406e57 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmInstruction.java @@ -35,7 +35,7 @@ abstract class WasmInstruction { * Type of instruction to faster differ as with instanceof. */ static enum Type { - Const, Convert, Local, Global, Block, Numeric, Nop, Call, CallIndirect, Array, Struct; + Const, Convert, Local, Global, Block, Numeric, Nop, Call, CallIndirect, Array, Struct, DupThis; } private int javaCodePos;