mirror of
https://github.com/i-net-software/JWebAssembly.git
synced 2025-03-15 02:44:47 +01:00
Rewrite the LocalVariableManager to handle the Java reuse of a variable slot with different type.
This commit is contained in:
parent
0ad94fbc56
commit
9653520c2b
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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<table.length; i++ ){
|
||||
if( name.equals( table[i].getName() )) {
|
||||
return table[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
public LocalVariable[] getTable() {
|
||||
return table;
|
||||
}
|
||||
}
|
||||
|
@ -692,7 +692,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
|
||||
keys[i] = byteCode.readInt();
|
||||
positions[i] = startPosition + byteCode.readInt();
|
||||
}
|
||||
int tempI32 = -1;
|
||||
int tempI32 = getTempVariable( ValueType.i32, codePos, Integer.MAX_VALUE );
|
||||
int block = 0;
|
||||
int defaultBlock = -1;
|
||||
int currentPos = -1;
|
||||
|
@ -18,8 +18,13 @@ package de.inetsoftware.jwebassembly.module;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import de.inetsoftware.classparser.LocalVariable;
|
||||
import de.inetsoftware.classparser.LocalVariableTable;
|
||||
import de.inetsoftware.jwebassembly.WasmException;
|
||||
import de.inetsoftware.jwebassembly.wasm.AnyType;
|
||||
@ -35,22 +40,22 @@ import de.inetsoftware.jwebassembly.wasm.ValueType;
|
||||
*/
|
||||
class LocaleVariableManager {
|
||||
|
||||
private LocaleVariable[] variables;
|
||||
private Variable[] variables;
|
||||
|
||||
private int size;
|
||||
private int size;
|
||||
|
||||
private boolean needTempI32;
|
||||
private final ArrayList<AnyType> localTypes = new ArrayList<>();
|
||||
|
||||
private ArrayList<AnyType> localTypes = new ArrayList<>();
|
||||
private final HashSet<String> 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<Variable>)( 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<AnyType> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<String, Object> 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<WasmInstruction> 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<AnyType> 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 );
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user