mirror of
https://github.com/i-net-software/JWebAssembly.git
synced 2025-03-15 02:44:47 +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 );
|
||||
break;
|
||||
case 50: // aaload
|
||||
AnyType storeType = findValueTypeFromStack( 2 );
|
||||
AnyType storeType = findValueTypeFromStack( 2, codePos );
|
||||
addArrayInstruction( ArrayOperator.GET, storeType, codePos, lineNumber );
|
||||
break;
|
||||
case 51: // baload
|
||||
@ -252,7 +252,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
|
||||
if( branchManager.isCatch( codePos ) ) {
|
||||
storeType = ValueType.anyref; // for the catch there are no previous instructions
|
||||
} else {
|
||||
storeType = findValueTypeFromStack( 1 );
|
||||
storeType = findValueTypeFromStack( 1, codePos );
|
||||
}
|
||||
addLoadStoreInstruction( storeType, false, op - 75, codePos, lineNumber );
|
||||
break;
|
||||
@ -269,7 +269,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
|
||||
addArrayInstruction( ArrayOperator.SET, ValueType.f64, codePos, lineNumber );
|
||||
break;
|
||||
case 83: // aastore
|
||||
storeType = findValueTypeFromStack( 1 );
|
||||
storeType = findValueTypeFromStack( 1, codePos );
|
||||
addArrayInstruction( ArrayOperator.SET, storeType, codePos, lineNumber );
|
||||
break;
|
||||
case 84: // bastore
|
||||
@ -646,7 +646,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
|
||||
addArrayInstruction( ArrayOperator.NEW, type, codePos, lineNumber );
|
||||
break;
|
||||
case 190: // arraylength
|
||||
type = ((ArrayType)findValueTypeFromStack( 1 )).getArrayType();
|
||||
type = ((ArrayType)findValueTypeFromStack( 1, codePos )).getArrayType();
|
||||
addArrayInstruction( ArrayOperator.LEN, type, codePos, lineNumber );
|
||||
break;
|
||||
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
|
||||
* 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
|
||||
*/
|
||||
@Nonnull
|
||||
AnyType findValueTypeFromStack( int count ) {
|
||||
return findInstructionThatPushValue( count, (idx,instr ) -> instr.getPushValueType() );
|
||||
AnyType findValueTypeFromStack( int count, int javaCodePos ) {
|
||||
return StackInspector.findInstructionThatPushValue( instructions, count, javaCodePos ).instr.getPushValueType();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -163,37 +165,12 @@ public abstract class WasmCodeBuilder {
|
||||
*
|
||||
* @param count
|
||||
* 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
|
||||
*/
|
||||
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;
|
||||
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
|
||||
private WasmInstruction findInstructionThatPushValue( int count, int javaCodePos ) {
|
||||
return StackInspector.findInstructionThatPushValue( instructions, count, javaCodePos ).instr;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -299,7 +276,7 @@ public abstract class WasmCodeBuilder {
|
||||
switch( op ) {
|
||||
case set:
|
||||
case tee:
|
||||
AnyType valueType = findValueTypeFromStack( 1 );
|
||||
AnyType valueType = findValueTypeFromStack( 1, javaCodePos );
|
||||
localVariables.useIndex( valueType, wasmIdx );
|
||||
}
|
||||
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
|
||||
*/
|
||||
protected void addDupInstruction( int javaCodePos, int lineNumber ) {
|
||||
WasmInstruction instr = findInstructionThatPushValue( 1 );
|
||||
WasmInstruction instr = findInstructionThatPushValue( 1, javaCodePos );
|
||||
AnyType type = instr.getPushValueType();
|
||||
int varIndex = -1;
|
||||
// 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
|
||||
int count = indirectCall.getPopCount();
|
||||
WasmInstruction instr = findInstructionThatPushValue( count );
|
||||
WasmInstruction instr = findInstructionThatPushValue( count, indirectCall.getCodePosition() );
|
||||
int varIndex = -1;
|
||||
// if it is a GET to a local variable then we can use it
|
||||
if( instr.getType() == Type.Local ) {
|
||||
|
@ -218,6 +218,15 @@ public class StructsNonGC extends AbstractBaseTest {
|
||||
Integer val = val1 == val2 ? val1 : val2;
|
||||
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 {
|
||||
@ -247,6 +256,10 @@ public class StructsNonGC extends AbstractBaseTest {
|
||||
int abstractBar() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
int add( int a, int b ) {
|
||||
return a + b;
|
||||
}
|
||||
}
|
||||
|
||||
static class Abc2 extends Abc {
|
||||
|
Loading…
x
Reference in New Issue
Block a user