From a4040a8d3b58728abb2148d0d726930db6e0be4a Mon Sep 17 00:00:00 2001 From: Volker Berlin Date: Sun, 1 Mar 2020 19:02:49 +0100 Subject: [PATCH] optimize the DUP instruction, only use a temp local variable if needed. --- .../module/JavaMethodWasmCodeBuilder.java | 2 +- .../jwebassembly/module/WasmCodeBuilder.java | 68 +++++++++++++++---- .../module/WasmLoadStoreInstruction.java | 14 +--- .../module/WasmLocalInstruction.java | 13 ++-- 4 files changed, 66 insertions(+), 31 deletions(-) diff --git a/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java index f9a4644..28bcc95 100644 --- a/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java @@ -723,7 +723,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder { byteCode.skip( 4 - padding ); } startPosition--; - int switchValuestartPosition = findPushInstructionCodePosition( 1 ); + int switchValuestartPosition = findBlockStartCodePosition( 1 ); int defaultPosition = startPosition + byteCode.readInt(); int[] keys; diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java index 0aceb8c..4bd2afd 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java @@ -18,6 +18,7 @@ package de.inetsoftware.jwebassembly.module; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.function.BiFunction; import java.util.function.Function; 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. * @return the code position that push the last instruction */ - int findPushInstructionCodePosition( int count ) { - return findPushInstruction( count, true ); + int findBlockStartCodePosition( int count ) { + return findBlockStart( count, true ); } /** @@ -126,7 +127,7 @@ public abstract class WasmCodeBuilder { * 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 ) { + private int findBlockStart( int count, boolean codePosition ) { int valueCount = 0; List instructions = this.instructions; for( int i = instructions.size() - 1; i >= 0; i-- ) { @@ -152,6 +153,32 @@ public abstract class WasmCodeBuilder { */ @Nonnull 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 + * 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 findInstructionThatPushValue( int count, BiFunction funct ) { int valueCount = 0; List instructions = this.instructions; for( int i = instructions.size() - 1; i >= 0; i-- ) { @@ -159,12 +186,12 @@ public abstract class WasmCodeBuilder { AnyType valueType = instr.getPushValueType(); if( valueType != null ) { if( ++valueCount == count ) { - return valueType; + return funct.apply( i, instr ); } } 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 ); 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 */ protected void addDupInstruction( int javaCodePos, int lineNumber ) { - AnyType type = findValueTypeFromStack( 1 ); - int idx = getTempVariable( type, javaCodePos, javaCodePos + 1 ); - instructions.add( new WasmDupInstruction( idx, 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 ) + WasmInstruction instr = findInstructionThatPushValue( 1 ); + AnyType type = instr.getPushValueType(); + int varIndex = -1; + // if it is a GET to a local variable then we can use it + 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 int count = indirectCall.getPopCount(); - int idx = findPushInstruction( count, false ); - WasmInstruction instr = instructions.get( idx ); + WasmInstruction instr = findInstructionThatPushValue( count ); int varIndex = -1; // if it is a GET to a local variable then we can use it if( instr.getType() == Type.Local ) { @@ -487,7 +527,7 @@ public abstract class WasmCodeBuilder { if( varIndex < 0 ) { int javaCodePos = indirectCall.getCodePosition(); 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 ) ); } indirectCall.setVariableIndexOfThis( varIndex ); diff --git a/src/de/inetsoftware/jwebassembly/module/WasmLoadStoreInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmLoadStoreInstruction.java index 70e1f9d..5dfd211 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmLoadStoreInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmLoadStoreInstruction.java @@ -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"); 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 { - private LocaleVariableManager localVariables; - /** * Create an instance of a load/store instruction * @@ -48,8 +46,7 @@ class WasmLoadStoreInstruction extends WasmLocalInstruction { * the line number in the Java source code */ WasmLoadStoreInstruction( boolean load, @Nonnegative int idx, LocaleVariableManager localVariables, int javaCodePos, int lineNumber ) { - super( load ? get : set, idx, javaCodePos, lineNumber ); - this.localVariables = localVariables; + super( load ? get : set, idx, localVariables, javaCodePos, lineNumber ); } /** @@ -59,11 +56,4 @@ class WasmLoadStoreInstruction extends WasmLocalInstruction { int getIndex() { return localVariables.get( super.getIndex(), getCodePosition() ); // translate slot index to position index } - - /** - * {@inheritDoc} - */ - AnyType getPushValueType() { - return getPopCount() == 0 ? localVariables.getValueType( getIndex() ) : null; - } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmLocalInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmLocalInstruction.java index e89ac3b..52d11e3 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmLocalInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmLocalInstruction.java @@ -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"); you may not use this file except in compliance with the License. @@ -38,6 +38,8 @@ class WasmLocalInstruction extends WasmInstruction { private int idx; + final LocaleVariableManager localVariables; + /** * Create an instance of a load/store instruction for a local variable. * @@ -45,15 +47,18 @@ class WasmLocalInstruction extends WasmInstruction { * the operation * @param idx * the memory/slot idx of the variable + * @param localVariables + * the manager for local variables * @param javaCodePos * the code position/offset in the Java method * @param lineNumber * 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 ); this.op = op; this.idx = idx; + this.localVariables = localVariables; } /** @@ -86,7 +91,7 @@ class WasmLocalInstruction extends WasmInstruction { /** * Get the number of the locals * - * @return the index + * @return the index, mostly the Wasm Index */ @Nonnegative int getIndex() { @@ -107,7 +112,7 @@ class WasmLocalInstruction extends WasmInstruction { */ @Override AnyType getPushValueType() { - return null; + return op == get ? localVariables.getValueType( getIndex() ) : null; } /**