fix position of duplicating THIS on virtual method calls

This commit is contained in:
Volker Berlin 2019-10-05 16:15:18 +02:00
parent be12f047dd
commit 19a119d7f4
4 changed files with 150 additions and 19 deletions

View File

@ -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;
}
}

View File

@ -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() ) {

View File

@ -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<WasmInstruction> 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 );
}
/**

View File

@ -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;