mirror of
https://github.com/i-net-software/JWebAssembly.git
synced 2025-03-25 07:27:52 +01:00
Rewrite stack analyze to handle conditional parameters on the stack.
This commit is contained in:
parent
7fd8d16403
commit
c52bc2a0fe
@ -194,7 +194,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
|
|||||||
addArrayInstruction( ArrayOperator.GET, ValueType.f64, codePos, lineNumber );
|
addArrayInstruction( ArrayOperator.GET, ValueType.f64, codePos, lineNumber );
|
||||||
break;
|
break;
|
||||||
case 50: // aaload
|
case 50: // aaload
|
||||||
AnyType storeType = findValueTypeFromStack( 2 );
|
AnyType storeType = findValueTypeFromStack( 2, codePos );
|
||||||
addArrayInstruction( ArrayOperator.GET, storeType, codePos, lineNumber );
|
addArrayInstruction( ArrayOperator.GET, storeType, codePos, lineNumber );
|
||||||
break;
|
break;
|
||||||
case 51: // baload
|
case 51: // baload
|
||||||
@ -252,7 +252,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
|
|||||||
if( branchManager.isCatch( codePos ) ) {
|
if( branchManager.isCatch( codePos ) ) {
|
||||||
storeType = ValueType.anyref; // for the catch there are no previous instructions
|
storeType = ValueType.anyref; // for the catch there are no previous instructions
|
||||||
} else {
|
} else {
|
||||||
storeType = findValueTypeFromStack( 1 );
|
storeType = findValueTypeFromStack( 1, codePos );
|
||||||
}
|
}
|
||||||
addLoadStoreInstruction( storeType, false, op - 75, codePos, lineNumber );
|
addLoadStoreInstruction( storeType, false, op - 75, codePos, lineNumber );
|
||||||
break;
|
break;
|
||||||
@ -269,7 +269,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
|
|||||||
addArrayInstruction( ArrayOperator.SET, ValueType.f64, codePos, lineNumber );
|
addArrayInstruction( ArrayOperator.SET, ValueType.f64, codePos, lineNumber );
|
||||||
break;
|
break;
|
||||||
case 83: // aastore
|
case 83: // aastore
|
||||||
storeType = findValueTypeFromStack( 1 );
|
storeType = findValueTypeFromStack( 1, codePos );
|
||||||
addArrayInstruction( ArrayOperator.SET, storeType, codePos, lineNumber );
|
addArrayInstruction( ArrayOperator.SET, storeType, codePos, lineNumber );
|
||||||
break;
|
break;
|
||||||
case 84: // bastore
|
case 84: // bastore
|
||||||
@ -646,7 +646,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
|
|||||||
addArrayInstruction( ArrayOperator.NEW, type, codePos, lineNumber );
|
addArrayInstruction( ArrayOperator.NEW, type, codePos, lineNumber );
|
||||||
break;
|
break;
|
||||||
case 190: // arraylength
|
case 190: // arraylength
|
||||||
type = ((ArrayType)findValueTypeFromStack( 1 )).getArrayType();
|
type = ((ArrayType)findValueTypeFromStack( 1, codePos )).getArrayType();
|
||||||
addArrayInstruction( ArrayOperator.LEN, type, codePos, lineNumber );
|
addArrayInstruction( ArrayOperator.LEN, type, codePos, lineNumber );
|
||||||
break;
|
break;
|
||||||
case 191: // athrow
|
case 191: // athrow
|
||||||
|
100
src/de/inetsoftware/jwebassembly/module/StackInspector.java
Normal file
100
src/de/inetsoftware/jwebassembly/module/StackInspector.java
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
Copyright 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.
|
||||||
|
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.ArrayDeque;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
|
import de.inetsoftware.jwebassembly.WasmException;
|
||||||
|
import de.inetsoftware.jwebassembly.module.WasmInstruction.Type;
|
||||||
|
import de.inetsoftware.jwebassembly.wasm.AnyType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inspect the current parsed instructions to find details over specific stack information.
|
||||||
|
*
|
||||||
|
* @author Volker Berlin
|
||||||
|
*/
|
||||||
|
class StackInspector {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inspect the instructions to find details over a specific stack position.
|
||||||
|
*
|
||||||
|
* @param instructions
|
||||||
|
* the parsed instructions
|
||||||
|
* @param count
|
||||||
|
* the count of values on the stack back. 1 means the last value. 2 means the penultimate value.
|
||||||
|
* @param javaCodePos
|
||||||
|
* the current code position, important to follow jumps in the code
|
||||||
|
* @return details of the stack position
|
||||||
|
*/
|
||||||
|
static StackValue findInstructionThatPushValue( List<WasmInstruction> instructions, int count, int javaCodePos ) {
|
||||||
|
// because there can be jumps (GOTO) we can analyze the stack only forward. If we iterate backward we will not see that we are in a jump.
|
||||||
|
ArrayDeque<StackValue> stack = new ArrayDeque<>();
|
||||||
|
int size = instructions.size();
|
||||||
|
for( int i = 0; i < size; i++ ) {
|
||||||
|
WasmInstruction instr = instructions.get( i );
|
||||||
|
int popCount = instr.getPopCount();
|
||||||
|
for( int p = 0; p < popCount; p++ ) {
|
||||||
|
stack.pop();
|
||||||
|
}
|
||||||
|
AnyType pushValue = instr.getPushValueType();
|
||||||
|
if( pushValue != null ) {
|
||||||
|
StackValue el = new StackValue();
|
||||||
|
el.idx = i;
|
||||||
|
el.instr = instr;
|
||||||
|
stack.push( el );
|
||||||
|
}
|
||||||
|
if( instr.getType() == Type.Jump ) {
|
||||||
|
if( popCount == 0 ) { // GOTO, for example on the end of the THEN branch
|
||||||
|
JumpInstruction jump = (JumpInstruction)instr;
|
||||||
|
int jumpPos = jump.getJumpPosition();
|
||||||
|
if( jumpPos > javaCodePos ) {
|
||||||
|
// we need a stack position inside a branch, we can remove all outside
|
||||||
|
stack.clear();
|
||||||
|
} else if( jumpPos > instr.getCodePosition() ) {
|
||||||
|
while( ++i < size && jumpPos > instructions.get( i ).getCodePosition() ) {
|
||||||
|
//nothing
|
||||||
|
}
|
||||||
|
i--; // we are on the right position but the loop increment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
StackValue stackValue = null;
|
||||||
|
for( int p = 0; p < count; p++ ) {
|
||||||
|
stackValue = stack.pop();
|
||||||
|
}
|
||||||
|
return stackValue;
|
||||||
|
} catch( NoSuchElementException ex ) {
|
||||||
|
throw new WasmException( "Push instruction not found", -1 ); // should never occur
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hold the state of the stack.
|
||||||
|
*/
|
||||||
|
static class StackValue {
|
||||||
|
/** the instruction index that push the stack value */
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
/** the instruction that push the stack value */
|
||||||
|
WasmInstruction instr;
|
||||||
|
}
|
||||||
|
}
|
@ -151,11 +151,13 @@ public abstract class WasmCodeBuilder {
|
|||||||
*
|
*
|
||||||
* @param count
|
* @param count
|
||||||
* 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.
|
||||||
|
* @param javaCodePos
|
||||||
|
* current code position for which the stack is inspected
|
||||||
* @return the type of the last push value
|
* @return the type of the last push value
|
||||||
*/
|
*/
|
||||||
@Nonnull
|
@Nonnull
|
||||||
AnyType findValueTypeFromStack( int count ) {
|
AnyType findValueTypeFromStack( int count, int javaCodePos ) {
|
||||||
return findInstructionThatPushValue( count, (idx,instr ) -> instr.getPushValueType() );
|
return StackInspector.findInstructionThatPushValue( instructions, count, javaCodePos ).instr.getPushValueType();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -163,37 +165,12 @@ public abstract class WasmCodeBuilder {
|
|||||||
*
|
*
|
||||||
* @param count
|
* @param count
|
||||||
* 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.
|
||||||
|
* @param javaCodePos
|
||||||
|
* current code position for which the stack is inspected
|
||||||
* @return the instruction
|
* @return the instruction
|
||||||
*/
|
*/
|
||||||
private WasmInstruction findInstructionThatPushValue( int count ) {
|
private WasmInstruction findInstructionThatPushValue( int count, int javaCodePos ) {
|
||||||
return findInstructionThatPushValue( count, (index,instruction) -> instruction );
|
return StackInspector.findInstructionThatPushValue( instructions, count, javaCodePos ).instr;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
List<WasmInstruction> instructions = this.instructions;
|
|
||||||
for( int i = instructions.size() - 1; i >= 0; i-- ) {
|
|
||||||
WasmInstruction instr = instructions.get( i );
|
|
||||||
AnyType valueType = instr.getPushValueType();
|
|
||||||
if( valueType != null ) {
|
|
||||||
if( ++valueCount == count ) {
|
|
||||||
return funct.apply( i, instr );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
valueCount -= instr.getPopCount();
|
|
||||||
}
|
|
||||||
throw new WasmException( "Push instruction not found", -1 ); // should never occur
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -299,7 +276,7 @@ public abstract class WasmCodeBuilder {
|
|||||||
switch( op ) {
|
switch( op ) {
|
||||||
case set:
|
case set:
|
||||||
case tee:
|
case tee:
|
||||||
AnyType valueType = findValueTypeFromStack( 1 );
|
AnyType valueType = findValueTypeFromStack( 1, javaCodePos );
|
||||||
localVariables.useIndex( valueType, wasmIdx );
|
localVariables.useIndex( valueType, wasmIdx );
|
||||||
}
|
}
|
||||||
instructions.add( new WasmLocalInstruction( op, wasmIdx, localVariables, javaCodePos, lineNumber ) );
|
instructions.add( new WasmLocalInstruction( op, wasmIdx, localVariables, javaCodePos, lineNumber ) );
|
||||||
@ -314,7 +291,7 @@ 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 ) {
|
||||||
WasmInstruction instr = findInstructionThatPushValue( 1 );
|
WasmInstruction instr = findInstructionThatPushValue( 1, javaCodePos );
|
||||||
AnyType type = instr.getPushValueType();
|
AnyType type = instr.getPushValueType();
|
||||||
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
|
||||||
@ -521,7 +498,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();
|
||||||
WasmInstruction instr = findInstructionThatPushValue( count );
|
WasmInstruction instr = findInstructionThatPushValue( count, indirectCall.getCodePosition() );
|
||||||
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 ) {
|
||||||
|
@ -218,6 +218,15 @@ public class StructsNonGC extends AbstractBaseTest {
|
|||||||
Integer val = val1 == val2 ? val1 : val2;
|
Integer val = val1 == val2 ? val1 : val2;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To find the instruction that push the object of the method call we need to consider an IF THEN ELSE when analyzing the stack.
|
||||||
|
*/
|
||||||
|
@Export
|
||||||
|
static int callParameterFromCondition() {
|
||||||
|
Abc abc = new Abc();
|
||||||
|
return abc.add( 42, abc == null ? 7 : 13 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TestDefault {
|
interface TestDefault {
|
||||||
@ -247,6 +256,10 @@ public class StructsNonGC extends AbstractBaseTest {
|
|||||||
int abstractBar() {
|
int abstractBar() {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int add( int a, int b ) {
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Abc2 extends Abc {
|
static class Abc2 extends Abc {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user