From 9653520c2b516a5c31a497140ca9abf2ef249ff0 Mon Sep 17 00:00:00 2001 From: Volker Berlin Date: Sun, 14 Apr 2019 14:29:09 +0200 Subject: [PATCH] Rewrite the LocalVariableManager to handle the Java reuse of a variable slot with different type. --- src/de/inetsoftware/classparser/Code.java | 8 +- .../classparser/LocalVariable.java | 62 ++--- .../classparser/LocalVariableTable.java | 93 ++----- .../module/JavaMethodWasmCodeBuilder.java | 2 +- .../module/LocaleVariableManager.java | 236 ++++++++++++++---- .../jwebassembly/module/ModuleGenerator.java | 95 +++---- .../jwebassembly/module/WasmCodeBuilder.java | 26 ++ .../module/WasmLoadStoreInstruction.java | 2 +- .../runtime/ControlFlowOperators.java | 15 ++ 9 files changed, 325 insertions(+), 214 deletions(-) diff --git a/src/de/inetsoftware/classparser/Code.java b/src/de/inetsoftware/classparser/Code.java index c3a9576..37458de 100644 --- a/src/de/inetsoftware/classparser/Code.java +++ b/src/de/inetsoftware/classparser/Code.java @@ -105,11 +105,9 @@ public class Code { AttributeInfo data = attributes.get( "LocalVariableTable" ); if( data != null ) { localVariableTable = new LocalVariableTable( maxLocals, constantPool ); - localVariableTable.read( data.getDataInputStream(), true ); - data = attributes.get( "LocalVariableTypeTable" ); - if( data != null ) { - localVariableTable.read( data.getDataInputStream(), false ); - } + localVariableTable.read( data.getDataInputStream() ); + // we does not need any generics information + // data = attributes.get( "LocalVariableTypeTable" ); } return localVariableTable; } diff --git a/src/de/inetsoftware/classparser/LocalVariable.java b/src/de/inetsoftware/classparser/LocalVariable.java index 719cfc2..f62d2e9 100644 --- a/src/de/inetsoftware/classparser/LocalVariable.java +++ b/src/de/inetsoftware/classparser/LocalVariable.java @@ -1,5 +1,5 @@ /* - Copyright 2011 - 2018 Volker Berlin (i-net software) + Copyright 2011 - 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. @@ -28,18 +28,12 @@ public class LocalVariable { private final int length; - private final int name_index; + private final String name; - private final int descriptor_index; + private final String signature; private final int index; - private final int position; - - private final ConstantPool constantPool; - - private boolean declared; - /** * http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.13 * http://docs.oracle.com/javase/specs/jvms/se5.0/html/ClassFile.doc.html#5956 @@ -53,14 +47,12 @@ public class LocalVariable { * @throws IOException * if any I/O error occurs. */ - LocalVariable( DataInputStream input, int position, ConstantPool constantPool ) throws IOException { + LocalVariable( DataInputStream input, ConstantPool constantPool ) throws IOException { start_pc = input.readUnsignedShort(); length = input.readUnsignedShort(); - name_index = input.readUnsignedShort(); - descriptor_index = input.readUnsignedShort(); + name = (String)constantPool.get( input.readUnsignedShort() ); + signature = (String)constantPool.get( input.readUnsignedShort() ); index = input.readUnsignedShort(); - this.position = position; - this.constantPool = constantPool; } /** @@ -72,40 +64,40 @@ public class LocalVariable { return index; } - /** - * Get the position in the local variable table. - * - * @return the position - */ - public int getPosition() { - return position; - } - /** * Get the name of the variable * * @return the name */ public String getName() { - return (String)constantPool.get( name_index ); - } - - public int getDescriptorIdx() { - return descriptor_index; + return name; } /** - * Was the declaration printed? - * @return true if already declared + * Get the type/signature of the variable + * + * @return the signature */ - public boolean isDeclared() { - return declared; + public String getSignature() { + return signature; } /** - * Mark this variable as declared. + * Get the code position within the local variable has a value. The first set operation to the variable will start + * before this position. + * + * @return the position. */ - public void setDeclared() { - declared = true; + public int getStartPosition() { + return start_pc; + } + + /** + * Get the code position length within the local variable has a value. + * + * @return the length + */ + public int getLengthPosition() { + return length; } } diff --git a/src/de/inetsoftware/classparser/LocalVariableTable.java b/src/de/inetsoftware/classparser/LocalVariableTable.java index 7e7c8fb..fa4527d 100644 --- a/src/de/inetsoftware/classparser/LocalVariableTable.java +++ b/src/de/inetsoftware/classparser/LocalVariableTable.java @@ -19,9 +19,6 @@ package de.inetsoftware.classparser; import java.io.DataInputStream; import java.io.IOException; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - /** * @author Volker Berlin */ @@ -29,11 +26,9 @@ public class LocalVariableTable { private final ConstantPool constantPool; - private LocalVariable[] tablePosition; + private final int maxLocals; - private LocalVariable[] table; - - private int count; + private LocalVariable[] table; /** * Create a new instance of the code attribute "LocalVariableTable". @@ -44,8 +39,7 @@ public class LocalVariableTable { * Reference to the current ConstantPool */ LocalVariableTable( int maxLocals, ConstantPool constantPool ) { - table = new LocalVariable[maxLocals]; - tablePosition = new LocalVariable[maxLocals]; + this.maxLocals = maxLocals; this.constantPool = constantPool; } @@ -55,87 +49,34 @@ public class LocalVariableTable { * * @param input * the stream of the class - * @param withPositions - * a hack if we find a better solution to map the positions LocalVariableTypeTable * @throws IOException * if any I/O error occurs. */ - void read( DataInputStream input, boolean withPositions ) throws IOException { - count = input.readUnsignedShort(); - boolean[] wasSet = new boolean[table.length]; + void read( DataInputStream input ) throws IOException { + int count = input.readUnsignedShort(); + table = new LocalVariable[count]; for( int i = 0; i < count; i++ ) { - LocalVariable var = new LocalVariable( input, i, constantPool ); - int idx = var.getIndex(); - if( !wasSet[idx] ) { // does not use index of reused variable - table[idx] = var; - wasSet[idx] = true; - } - } - - if( withPositions ) { - for( int i = 0, t = 0; i < table.length; i++ ) { - LocalVariable var = table[i]; - if( var != null ) { - tablePosition[t++] = var; - } - } + table[i] = new LocalVariable( input, constantPool ); } } /** - * Get the count of variables. + * Get the count of variables/slots. This is not the count of declared LocalVariable in this table. There can be + * unnamed helper variables for the compiler which are not in the table. There can be reused slots for different + * variables. + * * @return the count */ - public int getPositionSize() { - return tablePosition.length; + public int getMaxLocals() { + return maxLocals; } /** - * Get the count of storage places a 4 bytes for local variables. Double and long variables need 2 of this places. + * Get the declared local variables * - * @return the local stack size + * @return the variables */ - public int getSize() { - return table.length; - } - - /** - * Get the LocalVariable with it position. The position is continue also with double and long variables. Or if a variable is reused from a other block. - * - * @param pos - * the position - */ - @Nonnull - public LocalVariable getPosition( int pos ) { - return tablePosition[pos]; - } - - /** - * Get the LocalVariable with its memory location (slot). The index has empty places with double and long variables. - * - * @param idx - * the index in the memory - * @return the LocalVariable - */ - @Nonnull - public LocalVariable get( int idx ) { - return table[idx]; - } - - /** - * Find a LocalVariable with a given name. - * - * @param name - * needed for evaluate the name. - * @return the LocalVariable or null - */ - @Nullable - public LocalVariable get( String name ) { - for( int i=0; i localTypes = new ArrayList<>(); - private ArrayList localTypes = new ArrayList<>(); + private final HashSet names = new HashSet<>(); /** * Create a new instance. */ LocaleVariableManager() { // initialize with a initial capacity that should be enough for the most methods - variables = new LocaleVariable[8]; + variables = new Variable[8]; for( int i = 0; i < variables.length; i++ ) { - variables[i] = new LocaleVariable(); + variables[i] = new Variable(); } } @@ -61,13 +66,118 @@ class LocaleVariableManager { * variable table of the Java method. */ void reset( LocalVariableTable variableTable ) { - for( int i = 0; i < size; i++ ) { - LocaleVariable var = variables[i]; - var.valueType = null; - var.idx = -1; - } size = 0; - needTempI32 = false; + + if( variableTable == null ) { + return; + } + + /** + * Java can use reuse a variable slot in a different block. The type can be different in the block. WebAssembly + * does not support a type change for a local variable. That we need to create 2 variables. This try the follow + * complex code. + */ + + LocalVariable[] vars = variableTable.getTable(); + ensureCapacity( vars.length ); + + // transfer all declarations from the LocalVariableTable + for( int i = 0; i < vars.length; i++ ) { + LocalVariable local = vars[i]; + Variable var = variables[size]; + var.valueType = ValueType.getValueType( local.getSignature() ); + var.name = local.getName(); + var.idx = local.getIndex(); + var.startPos = local.getStartPosition() - 2; + var.endPos = local.getStartPosition() + local.getLengthPosition(); + size++; + } + + // sort to make sure but it should already sorted + Arrays.sort( variables, 0, size, (Comparator)( v1, v2 ) -> { + int comp = Integer.compare( v1.idx, v2.idx ); + if( comp != 0 ) { + return comp; + } + return Integer.compare( v1.startPos, v2.startPos ); + } ); + + // reduce all duplications if there are no conflicts and expands startPos and endPos + for( int i = 0; i < size - 1; i++ ) { + Variable var = variables[i]; + int j = i + 1; + Variable var2 = variables[j]; + if( var.idx == var2.idx ) { + if( var.valueType == var2.valueType ) { + var.endPos = var2.endPos; + size--; + int count = size - j; + if( count > 0 ) { + System.arraycopy( variables, j + 1, variables, j, count ); + variables[size] = var2; + } + i--; + continue; + } + } else { + var.endPos = Integer.MAX_VALUE; + var2.startPos = 0; + } + } + if( size > 0 ) { + variables[0].startPos = 0; + variables[size - 1].endPos = Integer.MAX_VALUE; + } + + // make the names unique if there conflicts. Java can use the same variable name in different blocks. WebAssembly text output does not accept this. + names.clear(); + for( int i = 0; i < size; i++ ) { + Variable var = variables[i]; + var.valueType = null; // TODO temporary hack + var.name = findUniqueVarName( var.name ); + } + + // add all missing slots that we can add self temporary variables + int maxLocals = variableTable.getMaxLocals(); + NEXT: for( int i = 0; i < maxLocals; i++ ) { + for( int j = 0; j < size; j++ ) { + Variable var = variables[j]; + if( var.idx == i ) { + continue NEXT; + } + } + ensureCapacity( size + 1 ); + Variable var = variables[size]; + var.valueType = null; + var.name = null; + var.idx = size; + var.startPos = 0; + var.endPos = Integer.MAX_VALUE; + size++; + } + } + + /** + * Find a unique variable name. + * + * @param name + * the suggested name + * @return a name that not was used before + */ + private String findUniqueVarName( String name ) { + if( names.contains( name ) ) { + // duplicate name for a variable in a different block + int id = 1; + do { + String name2 = name + '_' + ++id; + if( !names.contains( name2 ) ) { + name = name2; + break; + } + } while( true ); + } + names.add( name ); + return name; } /** @@ -81,13 +191,8 @@ class LocaleVariableManager { * the code position/offset in the Java method */ void use( AnyType valueType, int slot, int javaCodePos ) { - if( slot < 0 ) { - needTempI32 = true; - return; - } - ensureCapacity( slot ); - size = Math.max( size, slot + 1 ); - LocaleVariable var = variables[slot]; + int idx = get( slot, javaCodePos ); + Variable var = variables[idx]; if( var.valueType != null && var.valueType != valueType ) { if( var.valueType.getCode() >= 0 && valueType == ValueType.anyref ) { return; @@ -95,7 +200,8 @@ class LocaleVariableManager { if( valueType.getCode() >= 0 && var.valueType == ValueType.anyref ) { // set the more specific type } else { - throw new WasmException( "Redefine local variable type from " + var.valueType + " to " + valueType + " in slot " + slot, null, null, -1 ); + throw new WasmException( "Redefine local variable '" + var.name + "' type from " + var.valueType + " to " + valueType + " in slot " + + slot, null, null, -1 ); } } var.valueType = valueType; @@ -105,16 +211,14 @@ class LocaleVariableManager { * Calculate the WebAssembly index position on the consumed data. */ void calculate() { - if( needTempI32 ) { - use( ValueType.i32, size, -1 ); - } - int idx = 0; for( int i = 0; i < size; i++ ) { - LocaleVariable var = variables[i]; - if( var.valueType == null ) { // unused slot or extra slot for double and long values - continue; + Variable var = variables[i]; + if( var.valueType == null ) { + size--; + System.arraycopy( variables, i + 1, variables, i, size - i ); + variables[size] = var; + i--; } - var.idx = idx++; } } @@ -127,23 +231,45 @@ class LocaleVariableManager { */ List getLocalTypes( int paramCount ) { localTypes.clear(); - for( int i = 0; i < size; i++ ) { - LocaleVariable var = variables[i]; - if( var.idx >= paramCount ) { - localTypes.add( var.valueType ); - } + for( int i = paramCount; i < size; i++ ) { + Variable var = variables[i]; + localTypes.add( var.valueType ); } return localTypes; } + /** + * Get the name of the variable or null if no name available + * + * @param idx + * the wasm variable index + * @return the name + */ + @Nullable + String getLocalName( int idx ) { + return variables[idx].name; + } + /** * Get the slot of the temporary variable. * + * @param valueType + * the valueType for the variable + * @param startCodePosition + * the start of the Java code position + * @param endCodePosition + * the end of the Java code position * @return the slot */ - int getTempI32() { - needTempI32 = true; - return -1; + int getTempVariable( AnyType valueType, int startCodePosition, int endCodePosition ) { + ensureCapacity( size + 1 ); + Variable var = variables[size]; + var.valueType = valueType; + var.name = null; + var.idx = size; + var.startPos = startCodePosition; + var.endPos = endCodePosition; + return size++; } /** @@ -151,13 +277,21 @@ class LocaleVariableManager { * * @param slot * the memory/slot index of the local variable in Java + * @param javaCodePos the current code position in the Java method * @return the variable index in WebAssembly */ - int get( int slot ) { - if( slot < 0 ) { - slot = size - 1; // temp i32 + int get( int slot, int javaCodePos ) { + for( int i = 0; i < size; i++ ) { + Variable var = variables[i]; + if( slot != var.idx ) { + continue; + } + if( var.matchCodePosition( javaCodePos ) ) { + return i; + } } - return variables[slot].idx; + + throw new WasmException( "Can not find local variable for slot: " + slot + " on code position " + javaCodePos, -1 ); } /** @@ -182,7 +316,7 @@ class LocaleVariableManager { int i = variables.length; variables = Arrays.copyOf( variables, slot + 1 ); for( ; i < variables.length; i++ ) { - variables[i] = new LocaleVariable(); + variables[i] = new Variable(); } } } @@ -190,9 +324,27 @@ class LocaleVariableManager { /** * The state of a single local variable slot. */ - private static class LocaleVariable { + private static class Variable { + private AnyType valueType; + private String name; + private int idx = -1; + + private int startPos; + + private int endPos; + + /** + * If the variable is valid at this position + * + * @param codePosition + * the position to check + * @return true, if this variable match + */ + public boolean matchCodePosition( int codePosition ) { + return startPos <= codePosition && codePosition <= endPos; + } } } diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java index 9243ef7..69a8652 100644 --- a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java +++ b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java @@ -32,14 +32,10 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import javax.annotation.Nonnull; -import javax.annotation.Nullable; import de.inetsoftware.classparser.ClassFile; import de.inetsoftware.classparser.Code; -import de.inetsoftware.classparser.CodeInputStream; import de.inetsoftware.classparser.FieldInfo; -import de.inetsoftware.classparser.LocalVariable; -import de.inetsoftware.classparser.LocalVariableTable; import de.inetsoftware.classparser.MethodInfo; import de.inetsoftware.jwebassembly.JWebAssembly; import de.inetsoftware.jwebassembly.WasmException; @@ -169,7 +165,7 @@ public class ModuleGenerator { if( stream == null ) { if( next instanceof SyntheticFunctionName ) { watParser.parse( ((SyntheticFunctionName)next).getCode(), -1 ); - writeMethodImpl( next, true, null, watParser ); + writeMethodImpl( next, true, watParser ); } else { throw new WasmException( "Missing function: " + next.signatureName, -1 ); } @@ -297,7 +293,7 @@ public class ModuleGenerator { String impoarModule = (String)annotationValues.get( "module" ); String importName = (String)annotationValues.get( "name" ); writer.prepareImport( name, impoarModule, importName ); - writeMethodSignature( name, true, null, null ); + writeMethodSignature( name, true, null ); return; } if( (annotationValues = method.getAnnotation( JWebAssembly.EXPORT_ANNOTATION )) != null ) { @@ -328,15 +324,14 @@ public class ModuleGenerator { * @throws WasmException * if some Java code can't converted */ - private void writeMethod( FunctionName name, MethodInfo method ) throws WasmException { - CodeInputStream byteCode = null; + private void writeMethod( FunctionName name, MethodInfo method ) throws WasmException, IOException { + Code code = null; try { if( method.getAnnotation( JWebAssembly.IMPORT_ANNOTATION ) != null ) { return; } WasmCodeBuilder codeBuilder; - Code code = method.getCode(); - LocalVariableTable localVariableTable; + code = method.getCode(); if( method.getAnnotation( JWebAssembly.TEXTCODE_ANNOTATION ) != null ) { Map wat = method.getAnnotation( JWebAssembly.TEXTCODE_ANNOTATION ); String watCode = (String)wat.get( "value" ); @@ -346,56 +341,58 @@ public class ModuleGenerator { } watParser.parse( watCode, code == null ? -1 : code.getFirstLineNr() ); codeBuilder = watParser; - localVariableTable = null; } else if( code != null ) { // abstract methods and interface methods does not have code javaCodeBuilder.buildCode( code, !method.getType().endsWith( ")V" ) ); codeBuilder = javaCodeBuilder; - localVariableTable = code.getLocalVariableTable(); } else { throw new WasmException( "Abstract or native method can not be used: " + name.fullName, -1 ); } writeExport( name, method ); - writeMethodImpl( name, method.isStatic(), localVariableTable, codeBuilder ); + writeMethodImpl( name, method.isStatic(), codeBuilder ); } catch( Exception ioex ) { - int lineNumber = byteCode == null ? -1 : byteCode.getLineNumber(); + int lineNumber = code == null ? -1 : code.getFirstLineNr(); throw WasmException.create( ioex, sourceFile, className, lineNumber ); } } - private void writeMethodImpl( FunctionName name, boolean isStatic, LocalVariableTable localVariableTable, WasmCodeBuilder codeBuilder ) throws WasmException, IOException { + private void writeMethodImpl( FunctionName name, boolean isStatic, WasmCodeBuilder codeBuilder ) throws WasmException, IOException { writer.writeMethodStart( name, sourceFile ); functions.writeFunction( name ); - writeMethodSignature( name, isStatic, localVariableTable, codeBuilder ); + writeMethodSignature( name, isStatic, codeBuilder ); List instructions = codeBuilder.getInstructions(); optimizer.optimze( instructions ); int lastJavaSourceLine = -1; for( WasmInstruction instruction : instructions ) { - switch( instruction.getType() ) { - case Block: - switch( ((WasmBlockInstruction)instruction).getOperation() ) { - case TRY: - case CATCH: - writer.writeException(); - break; - default: - } - break; - case Call: - functions.functionCall( ((WasmCallInstruction)instruction).getFunctionName() ); - break; - case Struct: - setStructType( (WasmStructInstruction)instruction ); - break; - default: + try { + switch( instruction.getType() ) { + case Block: + switch( ((WasmBlockInstruction)instruction).getOperation() ) { + case TRY: + case CATCH: + writer.writeException(); + break; + default: + } + break; + case Call: + functions.functionCall( ((WasmCallInstruction)instruction).getFunctionName() ); + break; + case Struct: + setStructType( (WasmStructInstruction)instruction ); + break; + default: + } + int javaSourceLine = instruction.getLineNumber(); + if( javaSourceLine >= 0 && javaSourceLine != lastJavaSourceLine ) { + writer.markSourceLine( javaSourceLine ); + lastJavaSourceLine = javaSourceLine; + } + instruction.writeTo( writer ); + } catch( Throwable th ) { + throw WasmException.create( th, instruction.getLineNumber() ); } - int javaSourceLine = instruction.getLineNumber(); - if( javaSourceLine >= 0 && javaSourceLine != lastJavaSourceLine ) { - writer.markSourceLine( javaSourceLine ); - lastJavaSourceLine = javaSourceLine; - } - instruction.writeTo( writer ); } writer.writeMethodFinish(); } @@ -429,8 +426,6 @@ public class ModuleGenerator { * the Java signature, typical method.getType(); * @param isStatic * if method is static - * @param variables - * Java variable table with names of the variables for debugging * @param codeBuilder * the calculated variables * @throws IOException @@ -438,7 +433,7 @@ public class ModuleGenerator { * @throws WasmException * if some Java code can't converted */ - private void writeMethodSignature( FunctionName name, boolean isStatic, @Nullable LocalVariableTable variables, WasmCodeBuilder codeBuilder ) throws IOException, WasmException { + private void writeMethodSignature( FunctionName name, boolean isStatic, WasmCodeBuilder codeBuilder ) throws IOException, WasmException { int paramCount = 0; if( !isStatic ) { writer.writeMethodParam( "param", ValueType.anyref, "this" ); @@ -449,8 +444,8 @@ public class ModuleGenerator { while( parser.hasNext() && (type = parser.next()) != null ) { String paramName = null; if( kind == "param" ) { - if( variables != null ) { - paramName = variables.getPosition( paramCount ).getName(); + if( codeBuilder != null ) { + paramName = codeBuilder.getLocalName( paramCount ); } paramCount++; } @@ -466,16 +461,8 @@ public class ModuleGenerator { List localTypes = codeBuilder.getLocalTypes( paramCount ); for( int i = 0; i < localTypes.size(); i++ ) { type = localTypes.get( i ); - String paramName = null; - if( variables != null ) { - int idx = paramCount + i; - if( idx < variables.getPositionSize() ) { - LocalVariable variable = variables.getPosition( idx ); - if( variable != null ) { - paramName = variable.getName(); - } - } - } + int idx = paramCount + i; + String paramName = codeBuilder.getLocalName( idx ); writer.writeMethodParam( "local", type, paramName ); } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java index 87db0df..4ce9049 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCodeBuilder.java @@ -88,6 +88,32 @@ public abstract class WasmCodeBuilder { return localVariables.getLocalTypes( paramCount ); } + /** + * Get the name of the variable or null if no name available + * + * @param idx + * the wasm variable index + * @return the name + */ + String getLocalName( int idx ) { + return localVariables.getLocalName( idx ); + } + + /** + * Get the slot of the temporary variable. + * + * @param valueType + * the valueType for the variable + * @param startCodePosition + * the start of the Java code position + * @param endCodePosition + * the end of the Java code position + * @return the slot + */ + int getTempVariable( AnyType valueType, int startCodePosition, int endCodePosition ) { + return localVariables.getTempVariable( valueType, startCodePosition, endCodePosition ); + } + /** * Reset the code builder. * diff --git a/src/de/inetsoftware/jwebassembly/module/WasmLoadStoreInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmLoadStoreInstruction.java index 8dfe76e..a58b964 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmLoadStoreInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmLoadStoreInstruction.java @@ -54,7 +54,7 @@ class WasmLoadStoreInstruction extends WasmLocalInstruction { */ @Override int getIndex() { - return localVariables.get( super.getIndex() ); // translate slot index to position index + return localVariables.get( super.getIndex(), getCodePosition() ); // translate slot index to position index } /** diff --git a/test/de/inetsoftware/jwebassembly/runtime/ControlFlowOperators.java b/test/de/inetsoftware/jwebassembly/runtime/ControlFlowOperators.java index 4f05828..ed3e715 100644 --- a/test/de/inetsoftware/jwebassembly/runtime/ControlFlowOperators.java +++ b/test/de/inetsoftware/jwebassembly/runtime/ControlFlowOperators.java @@ -52,6 +52,7 @@ public class ControlFlowOperators extends AbstractBaseTest { addParam( list, script, "whileLoop" ); addParam( list, script, "forLoop" ); addParam( list, script, "conditionalOperator" ); + addParam( list, script, "redifineVariable" ); } return list; } @@ -301,5 +302,19 @@ public class ControlFlowOperators extends AbstractBaseTest { int condition = 4; return condition >= 4 ? condition < 4 ? 1 : 2 : condition == 4 ? 3 : 4; } + + @Export + static double redifineVariable() { + int x = 42; + if( x > 0 ) { + double a = 1; + double b = 2.5; + return a + b; + } else { + int a = 1; + int b = 3; + return a + b; + } + } } }