optimize the DUP instruction, only use a temp local variable if needed.

This commit is contained in:
Volker Berlin 2020-03-01 19:02:49 +01:00
parent 3d8f49c79a
commit a4040a8d3b
4 changed files with 66 additions and 31 deletions

View File

@ -723,7 +723,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
byteCode.skip( 4 - padding ); byteCode.skip( 4 - padding );
} }
startPosition--; startPosition--;
int switchValuestartPosition = findPushInstructionCodePosition( 1 ); int switchValuestartPosition = findBlockStartCodePosition( 1 );
int defaultPosition = startPosition + byteCode.readInt(); int defaultPosition = startPosition + byteCode.readInt();
int[] keys; int[] keys;

View File

@ -18,6 +18,7 @@ package de.inetsoftware.jwebassembly.module;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function; import java.util.function.Function;
import javax.annotation.Nonnegative; import javax.annotation.Nonnegative;
@ -112,8 +113,8 @@ public abstract class WasmCodeBuilder {
* the count of values on the stack back. 1 means the last value. 2 means the penultimate value. * 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 * @return the code position that push the last instruction
*/ */
int findPushInstructionCodePosition( int count ) { int findBlockStartCodePosition( int count ) {
return findPushInstruction( count, true ); return findBlockStart( count, true );
} }
/** /**
@ -126,7 +127,7 @@ public abstract class WasmCodeBuilder {
* true, get the code position; false, get the index in the instructions * true, get the code position; false, get the index in the instructions
* @return the code position that push the last instruction * @return the code position that push the last instruction
*/ */
private int findPushInstruction( int count, boolean codePosition ) { private int findBlockStart( int count, boolean codePosition ) {
int valueCount = 0; int valueCount = 0;
List<WasmInstruction> instructions = this.instructions; List<WasmInstruction> instructions = this.instructions;
for( int i = instructions.size() - 1; i >= 0; i-- ) { for( int i = instructions.size() - 1; i >= 0; i-- ) {
@ -152,6 +153,32 @@ public abstract class WasmCodeBuilder {
*/ */
@Nonnull @Nonnull
AnyType findValueTypeFromStack( int count ) { AnyType findValueTypeFromStack( int count ) {
return findInstructionThatPushValue( count, (idx,instr ) -> instr.getPushValueType() );
}
/**
* Find the instruction that push the x-th value to the stack.
*
* @param count
* the count of values on the stack back. 1 means the last value. 2 means the penultimate value.
* @return the instruction
*/
private WasmInstruction findInstructionThatPushValue( int count ) {
return findInstructionThatPushValue( count, (index,instruction) -> instruction );
}
/**
* Find the instruction that push the x-th value to the stack.
*
* @param <T>
* the return type
* @param count
* the count of values on the stack back. 1 means the last value. 2 means the penultimate value.
* @param funct
* the return value from the instruction
* @return the function value
*/
<T> T findInstructionThatPushValue( int count, BiFunction<Integer, WasmInstruction, T> funct ) {
int valueCount = 0; int valueCount = 0;
List<WasmInstruction> instructions = this.instructions; List<WasmInstruction> instructions = this.instructions;
for( int i = instructions.size() - 1; i >= 0; i-- ) { for( int i = instructions.size() - 1; i >= 0; i-- ) {
@ -159,12 +186,12 @@ public abstract class WasmCodeBuilder {
AnyType valueType = instr.getPushValueType(); AnyType valueType = instr.getPushValueType();
if( valueType != null ) { if( valueType != null ) {
if( ++valueCount == count ) { if( ++valueCount == count ) {
return valueType; return funct.apply( i, instr );
} }
} }
valueCount -= instr.getPopCount(); valueCount -= instr.getPopCount();
} }
throw new WasmException( "Push Value not found", -1 ); // should never occur throw new WasmException( "Push instruction not found", -1 ); // should never occur
} }
/** /**
@ -271,7 +298,7 @@ public abstract class WasmCodeBuilder {
AnyType valueType = findValueTypeFromStack( 1 ); AnyType valueType = findValueTypeFromStack( 1 );
localVariables.useIndex( valueType, wasmIdx ); localVariables.useIndex( valueType, wasmIdx );
} }
instructions.add( new WasmLocalInstruction( op, wasmIdx, javaCodePos, lineNumber ) ); instructions.add( new WasmLocalInstruction( op, wasmIdx, localVariables, javaCodePos, lineNumber ) );
} }
/** /**
@ -283,11 +310,25 @@ public abstract class WasmCodeBuilder {
* the line number in the Java source code * the line number in the Java source code
*/ */
protected void addDupInstruction( int javaCodePos, int lineNumber ) { protected void addDupInstruction( int javaCodePos, int lineNumber ) {
AnyType type = findValueTypeFromStack( 1 ); WasmInstruction instr = findInstructionThatPushValue( 1 );
int idx = getTempVariable( type, javaCodePos, javaCodePos + 1 ); AnyType type = instr.getPushValueType();
instructions.add( new WasmDupInstruction( idx, type, localVariables, javaCodePos, lineNumber ) ); int varIndex = -1;
// an alternative solution can be a function call with multiple return values but this seems to be slower // if it is a GET to a local variable then we can use it
// new SyntheticFunctionName( "dup" + storeType, "local.get 0 local.get 0 return", storeType, null, storeType, storeType ), codePos, lineNumber ) if( instr.getType() == Type.Local ) {
WasmLocalInstruction local1 = (WasmLocalInstruction)instr;
if( local1.getOperator() == VariableOperator.get ) {
varIndex = local1.getIndex();
}
}
//alternate we need to create a new locale variable
if( varIndex < 0 ) {
varIndex = getTempVariable( type, javaCodePos, javaCodePos + 1 );
instructions.add( new WasmDupInstruction( varIndex, type, localVariables, javaCodePos, lineNumber ) );
// an alternative solution can be a function call with multiple return values but this seems to be slower
// new SyntheticFunctionName( "dup" + storeType, "local.get 0 local.get 0 return", storeType, null, storeType, storeType ), codePos, lineNumber )
} else {
instructions.add( new WasmLocalInstruction( VariableOperator.get, varIndex, localVariables, javaCodePos, lineNumber ) );
}
} }
/** /**
@ -473,8 +514,7 @@ public abstract class WasmCodeBuilder {
// find the instruction that this push on stack // find the instruction that this push on stack
int count = indirectCall.getPopCount(); int count = indirectCall.getPopCount();
int idx = findPushInstruction( count, false ); WasmInstruction instr = findInstructionThatPushValue( count );
WasmInstruction instr = instructions.get( idx );
int varIndex = -1; int varIndex = -1;
// if it is a GET to a local variable then we can use it // if it is a GET to a local variable then we can use it
if( instr.getType() == Type.Local ) { if( instr.getType() == Type.Local ) {
@ -487,7 +527,7 @@ public abstract class WasmCodeBuilder {
if( varIndex < 0 ) { if( varIndex < 0 ) {
int javaCodePos = indirectCall.getCodePosition(); int javaCodePos = indirectCall.getCodePosition();
varIndex = getTempVariable( indirectCall.getThisType(), instr.getCodePosition(), javaCodePos + 1 ); varIndex = getTempVariable( indirectCall.getThisType(), instr.getCodePosition(), javaCodePos + 1 );
idx = count == 1 ? instructions.size() : findPushInstruction( count - 1, false ); int idx = count == 1 ? instructions.size() : findBlockStart( count - 1, false );
instructions.add( idx, new DupThis( indirectCall, varIndex, javaCodePos ) ); instructions.add( idx, new DupThis( indirectCall, varIndex, javaCodePos ) );
} }
indirectCall.setVariableIndexOfThis( varIndex ); indirectCall.setVariableIndexOfThis( varIndex );

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2018 - 2019 Volker Berlin (i-net software) Copyright 2018 - 2020 Volker Berlin (i-net software)
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -31,8 +31,6 @@ import de.inetsoftware.jwebassembly.wasm.AnyType;
*/ */
class WasmLoadStoreInstruction extends WasmLocalInstruction { class WasmLoadStoreInstruction extends WasmLocalInstruction {
private LocaleVariableManager localVariables;
/** /**
* Create an instance of a load/store instruction * Create an instance of a load/store instruction
* *
@ -48,8 +46,7 @@ class WasmLoadStoreInstruction extends WasmLocalInstruction {
* the line number in the Java source code * the line number in the Java source code
*/ */
WasmLoadStoreInstruction( boolean load, @Nonnegative int idx, LocaleVariableManager localVariables, int javaCodePos, int lineNumber ) { WasmLoadStoreInstruction( boolean load, @Nonnegative int idx, LocaleVariableManager localVariables, int javaCodePos, int lineNumber ) {
super( load ? get : set, idx, javaCodePos, lineNumber ); super( load ? get : set, idx, localVariables, javaCodePos, lineNumber );
this.localVariables = localVariables;
} }
/** /**
@ -59,11 +56,4 @@ class WasmLoadStoreInstruction extends WasmLocalInstruction {
int getIndex() { int getIndex() {
return localVariables.get( super.getIndex(), getCodePosition() ); // translate slot index to position index return localVariables.get( super.getIndex(), getCodePosition() ); // translate slot index to position index
} }
/**
* {@inheritDoc}
*/
AnyType getPushValueType() {
return getPopCount() == 0 ? localVariables.getValueType( getIndex() ) : null;
}
} }

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2018 - 2019 Volker Berlin (i-net software) Copyright 2018 - 2020 Volker Berlin (i-net software)
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -38,6 +38,8 @@ class WasmLocalInstruction extends WasmInstruction {
private int idx; private int idx;
final LocaleVariableManager localVariables;
/** /**
* Create an instance of a load/store instruction for a local variable. * Create an instance of a load/store instruction for a local variable.
* *
@ -45,15 +47,18 @@ class WasmLocalInstruction extends WasmInstruction {
* the operation * the operation
* @param idx * @param idx
* the memory/slot idx of the variable * the memory/slot idx of the variable
* @param localVariables
* the manager for local variables
* @param javaCodePos * @param javaCodePos
* the code position/offset in the Java method * the code position/offset in the Java method
* @param lineNumber * @param lineNumber
* the line number in the Java source code * the line number in the Java source code
*/ */
WasmLocalInstruction( VariableOperator op, @Nonnegative int idx, int javaCodePos, int lineNumber ) { WasmLocalInstruction( VariableOperator op, @Nonnegative int idx, LocaleVariableManager localVariables, int javaCodePos, int lineNumber ) {
super( javaCodePos, lineNumber ); super( javaCodePos, lineNumber );
this.op = op; this.op = op;
this.idx = idx; this.idx = idx;
this.localVariables = localVariables;
} }
/** /**
@ -86,7 +91,7 @@ class WasmLocalInstruction extends WasmInstruction {
/** /**
* Get the number of the locals * Get the number of the locals
* *
* @return the index * @return the index, mostly the Wasm Index
*/ */
@Nonnegative @Nonnegative
int getIndex() { int getIndex() {
@ -107,7 +112,7 @@ class WasmLocalInstruction extends WasmInstruction {
*/ */
@Override @Override
AnyType getPushValueType() { AnyType getPushValueType() {
return null; return op == get ? localVariables.getValueType( getIndex() ) : null;
} }
/** /**