diff --git a/src/de/inetsoftware/jwebassembly/module/DupThis.java b/src/de/inetsoftware/jwebassembly/module/DupThis.java index d4f5cec..6a0bb8b 100644 --- a/src/de/inetsoftware/jwebassembly/module/DupThis.java +++ b/src/de/inetsoftware/jwebassembly/module/DupThis.java @@ -1,5 +1,5 @@ /* - Copyright 2019 Volker Berlin (i-net software) + Copyright 2019 - 2021 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. @@ -82,4 +82,11 @@ class DupThis extends WasmInstruction { return 0; } + /** + * {@inheritDoc} + */ + @Override + AnyType[] getPopValueTypes() { + return null; + } } diff --git a/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java b/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java index d090018..b48a5c5 100644 --- a/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java +++ b/src/de/inetsoftware/jwebassembly/module/JavaMethodWasmCodeBuilder.java @@ -16,6 +16,7 @@ package de.inetsoftware.jwebassembly.module; import java.io.IOException; +import java.util.List; import javax.annotation.Nonnull; @@ -29,6 +30,8 @@ import de.inetsoftware.classparser.ConstantPool; import de.inetsoftware.classparser.ConstantRef; import de.inetsoftware.classparser.MethodInfo; import de.inetsoftware.jwebassembly.WasmException; +import de.inetsoftware.jwebassembly.module.TypeManager.StructType; +import de.inetsoftware.jwebassembly.module.WasmInstruction.Type; import de.inetsoftware.jwebassembly.wasm.AnyType; import de.inetsoftware.jwebassembly.wasm.ArrayOperator; import de.inetsoftware.jwebassembly.wasm.ArrayType; @@ -36,6 +39,7 @@ import de.inetsoftware.jwebassembly.wasm.NamedStorageType; import de.inetsoftware.jwebassembly.wasm.NumericOperator; import de.inetsoftware.jwebassembly.wasm.StructOperator; import de.inetsoftware.jwebassembly.wasm.ValueType; +import de.inetsoftware.jwebassembly.wasm.ValueTypeParser; import de.inetsoftware.jwebassembly.wasm.WasmBlockOperator; /** @@ -73,8 +77,8 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder { branchManager.reset( code ); byteCode = code.getByteCode(); - boolean hasReturn = !method.getType().endsWith( ")V" ); - writeCode( byteCode, code.getConstantPool(), method.getDeclaringClassFile(), hasReturn ); + AnyType returnType = new ValueTypeParser( method.getType().substring( method.getType().lastIndexOf( ')' ) + 1), getTypeManager() ).next(); + writeCode( byteCode, code.getConstantPool(), method.getDeclaringClassFile(), returnType ); calculateVariables(); } catch( Exception ioex ) { int lineNumber = byteCode == null ? -1 : byteCode.getLineNumber(); @@ -91,12 +95,13 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder { * the constant pool of the the current class * @param classFile * the declaring class file - * @param hasReturn - * if the method has a return value + * @param returnType + * the return type of the method * @throws WasmException * if some Java code can't converted */ - private void writeCode( CodeInputStream byteCode, ConstantPool constantPool, ClassFile classFile, boolean hasReturn ) throws WasmException { + private void writeCode( CodeInputStream byteCode, ConstantPool constantPool, ClassFile classFile, AnyType returnType ) throws WasmException { + boolean nullConstants = false; int lineNumber = -1; try { boolean wide = false; @@ -109,6 +114,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder { break; case 1: // aconst_null addStructInstruction( StructOperator.NULL, "java/lang/Object", null, codePos, lineNumber ); + nullConstants = true; break; case 2: // iconst_m1 case 3: // iconst_0 @@ -580,7 +586,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder { type = ValueType.f64; break; case 176: // areturn - type = ValueType.externref; + type = getOptions().useGC() ? returnType : ValueType.externref; break; } addBlockInstruction( WasmBlockOperator.RETURN, type, codePos, lineNumber ); @@ -723,12 +729,17 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder { } branchManager.calculate(); branchManager.handle( byteCode ); // add branch operations - if( hasReturn && !isEndsWithReturn() ) { + if( returnType != null && !isEndsWithReturn() ) { // if a method ends with a loop or block without a break then code after the loop is no reachable // Java does not need a return byte code in this case // But WebAssembly need the dead code to validate addBlockInstruction( WasmBlockOperator.UNREACHABLE, null, byteCode.getCodePosition(), byteCode.getLineNumber() ); } + + if( nullConstants && getOptions().useGC() ) { + patchTypeOfNullConst(); + } + } catch( Exception ex ) { throw WasmException.create( ex, lineNumber ); } @@ -925,4 +936,33 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder { branchManager.addIfOperator( codePos, offset, byteCode.getLineNumber(), compare ); } + /** + * NULL const has no type in Java. In WebAssembly currently. + */ + private void patchTypeOfNullConst() { + List instructions = getInstructions(); + int size = instructions.size(); + for( int i = 0; i < size; i++ ) { + WasmInstruction instr = instructions.get( i ); + if( instr.getType() == Type.Struct ) { + WasmStructInstruction structInst = (WasmStructInstruction)instr; + if( structInst.getOperator() == StructOperator.NULL ) { + int count = 0; + for( int s = i + 1; s < size; s++ ) { + WasmInstruction nextInstr = instructions.get( s ); + count -= nextInstr.getPopCount(); + if( count < 0 ) { + AnyType[] popValueTypes = nextInstr.getPopValueTypes(); + structInst.setStructType( (StructType)popValueTypes[-1 - count] ); + break; + } + if( nextInstr.getPushValueType() != null ) { + count++; + } + } + } + } + } + } + } diff --git a/src/de/inetsoftware/jwebassembly/module/JumpInstruction.java b/src/de/inetsoftware/jwebassembly/module/JumpInstruction.java index 1b1574d..90c23a4 100644 --- a/src/de/inetsoftware/jwebassembly/module/JumpInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/JumpInstruction.java @@ -1,5 +1,5 @@ /* - Copyright 2020 Volker Berlin (i-net software) + Copyright 2020 - 2021 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. @@ -95,4 +95,13 @@ class JumpInstruction extends WasmInstruction { int getJumpPosition() { return jumpPos; } + + /** + * {@inheritDoc} + */ + @Override + AnyType[] getPopValueTypes() { + // TODO + return null; + } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmArrayInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmArrayInstruction.java index d7d312c..7adb76a 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmArrayInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmArrayInstruction.java @@ -26,7 +26,6 @@ import de.inetsoftware.jwebassembly.module.TypeManager.StructType; import de.inetsoftware.jwebassembly.wasm.AnyType; import de.inetsoftware.jwebassembly.wasm.ArrayOperator; import de.inetsoftware.jwebassembly.wasm.ArrayType; -import de.inetsoftware.jwebassembly.wasm.StructOperator; import de.inetsoftware.jwebassembly.wasm.ValueType; /** @@ -228,4 +227,27 @@ class WasmArrayInstruction extends WasmInstruction { throw new WasmException( "Unknown array operation: " + op, -1 ); } } + + /** + * {@inheritDoc} + */ + @Override + AnyType[] getPopValueTypes() { + switch( op ) { + case GET: + case GET_S: + case GET_U: + return new AnyType[] { arrayType, ValueType.i32 }; + case NEW_ARRAY_WITH_RTT: + return new AnyType[] { ValueType.i32, ValueType.i32 }; // size, rtt type + case NEW: + return new AnyType[] { ValueType.i32 }; + case LEN: + return new AnyType[] { arrayType }; + case SET: + return new AnyType[] { arrayType, ValueType.i32, type }; + default: + throw new WasmException( "Unknown array operation: " + op, -1 ); + } + } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmBlockInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmBlockInstruction.java index ca3a132..e477016 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmBlockInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmBlockInstruction.java @@ -1,5 +1,5 @@ /* - Copyright 2018 - 2020 Volker Berlin (i-net software) + Copyright 2018 - 2021 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. @@ -123,8 +123,31 @@ class WasmBlockInstruction extends WasmInstruction { case THROW: case RETHROW: return 1; + case RETURN: + return data == null ? 0 : 1; default: return 0; } } + + /** + * {@inheritDoc} + */ + @Override + AnyType[] getPopValueTypes() { + switch( op ) { + case IF: + case BR_IF: + return new AnyType[] { ValueType.i32 }; + case DROP: + return new AnyType[] { ValueType.anyref }; + case THROW: + case RETHROW: + return new AnyType[] { ValueType.exnref }; + case RETURN: + return data == null ? null : new AnyType[] { (AnyType)data }; + default: + return null; + } + } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmCallInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmCallInstruction.java index 29e3916..10ae130 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmCallInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmCallInstruction.java @@ -1,5 +1,5 @@ /* - Copyright 2018 - 2020 Volker Berlin (i-net software) + Copyright 2018 - 2021 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. @@ -136,6 +136,29 @@ class WasmCallInstruction extends WasmInstruction { return paramCount; } + /** + * {@inheritDoc} + */ + @Override + AnyType[] getPopValueTypes() { + countParams(); + if( paramCount == 0 ) { + return null; + } + AnyType[] valueTypes = new AnyType[paramCount]; + int idx = 0; + if( needThisParameter ) { + valueTypes[ idx++ ] = types.valueOf( name.className ); + } + if( idx < paramCount ) { + Iterator parser = name.getSignature( types ); + while( idx < paramCount ) { + valueTypes[ idx++ ] = parser.next(); + } + } + return valueTypes; + } + /** * Count the parameters in the signature */ diff --git a/src/de/inetsoftware/jwebassembly/module/WasmConstInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmConstInstruction.java index 0a177b3..68513c1 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmConstInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmConstInstruction.java @@ -1,5 +1,5 @@ /* - Copyright 2018 - 2019 Volker Berlin (i-net software) + Copyright 2018 - 2021 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. @@ -121,4 +121,12 @@ class WasmConstInstruction extends WasmInstruction { int getPopCount() { return 0; } + + /** + * {@inheritDoc} + */ + @Override + AnyType[] getPopValueTypes() { + return null; + } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmConvertInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmConvertInstruction.java index af90fd3..7535e68 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmConvertInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmConvertInstruction.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 - 2019 Volker Berlin (i-net software) + * Copyright 2018 - 2021 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. @@ -97,4 +97,34 @@ class WasmConvertInstruction extends WasmInstruction { int getPopCount() { return 1; } + + /** + * {@inheritDoc} + */ + @Override + AnyType[] getPopValueTypes() { + switch( conversion ) { + case i2b: + case i2c: + case i2s: + case i2l: + case i2f: + case i2d: + return new AnyType[] { ValueType.i32 }; + case l2i: + case l2f: + case l2d: + return new AnyType[] { ValueType.i64 }; + case f2i: + case f2l: + case f2d: + return new AnyType[] { ValueType.f32 }; + case d2i: + case d2l: + case d2f: + return new AnyType[] { ValueType.f64 }; + default: + throw new Error( conversion.toString() ); + } + } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmGlobalInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmGlobalInstruction.java index 0e9aabb..bcacd10 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmGlobalInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmGlobalInstruction.java @@ -1,5 +1,5 @@ /* - Copyright 2018 - 2019 Volker Berlin (i-net software) + Copyright 2018 - 2021 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. @@ -98,4 +98,12 @@ class WasmGlobalInstruction extends WasmInstruction { int getPopCount() { return load ? 0 : 1; } + + /** + * {@inheritDoc} + */ + @Override + AnyType[] getPopValueTypes() { + return load ? null : new AnyType[] { type }; + } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmInstruction.java index dcf1728..e3f7784 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmInstruction.java @@ -1,5 +1,5 @@ /* - Copyright 2018 - 2020 Volker Berlin (i-net software) + Copyright 2018 - 2021 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. @@ -115,4 +115,6 @@ abstract class WasmInstruction { * @return the count */ abstract int getPopCount(); + + abstract AnyType[] getPopValueTypes(); } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmLocalInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmLocalInstruction.java index ae52f68..a82216a 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmLocalInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmLocalInstruction.java @@ -1,5 +1,5 @@ /* - Copyright 2018 - 2020 Volker Berlin (i-net software) + Copyright 2018 - 2021 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. @@ -122,4 +122,12 @@ class WasmLocalInstruction extends WasmInstruction { int getPopCount() { return op == get ? 0 : 1; } + + /** + * {@inheritDoc} + */ + @Override + AnyType[] getPopValueTypes() { + return op == get ? null : new AnyType[] { localVariables.getValueType( getIndex() ) }; + } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmMemoryInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmMemoryInstruction.java index 6bbd640..114b80c 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmMemoryInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmMemoryInstruction.java @@ -1,5 +1,5 @@ /* - Copyright 2019 Volker Berlin (i-net software) + Copyright 2019 - 2021 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. @@ -95,4 +95,12 @@ class WasmMemoryInstruction extends WasmInstruction { int getPopCount() { return op.name().startsWith( "load" ) ? 0 : 1; } + + /** + * {@inheritDoc} + */ + @Override + AnyType[] getPopValueTypes() { + return op.name().startsWith( "load" ) ? null : new AnyType[] { type }; + } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmNopInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmNopInstruction.java index 042e058..ce5e00a 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmNopInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmNopInstruction.java @@ -1,5 +1,5 @@ /* - Copyright 2018 - 2019 Volker Berlin (i-net software) + Copyright 2018 - 2021 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. @@ -71,4 +71,12 @@ class WasmNopInstruction extends WasmInstruction { int getPopCount() { return 0; } + + /** + * {@inheritDoc} + */ + @Override + AnyType[] getPopValueTypes() { + return null; + } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmNumericInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmNumericInstruction.java index 2cfa645..04a951a 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmNumericInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmNumericInstruction.java @@ -1,5 +1,5 @@ /* - Copyright 2018 - 2019 Volker Berlin (i-net software) + Copyright 2018 - 2021 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. @@ -111,4 +111,26 @@ class WasmNumericInstruction extends WasmInstruction { return 2; } } + + /** + * {@inheritDoc} + */ + @Override + AnyType[] getPopValueTypes() { + switch( numOp ) { + case eqz: + case ifnull: + case ifnonnull: + case neg: + case sqrt: + case abs: + case ceil: + case floor: + case trunc: + case nearest: + return new AnyType[] { ValueType.i32 }; + default: + return new AnyType[] { valueType, valueType }; + } + } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmStructInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmStructInstruction.java index a782431..3767e8d 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmStructInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmStructInstruction.java @@ -18,6 +18,7 @@ package de.inetsoftware.jwebassembly.module; import java.io.IOException; import java.util.List; +import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -41,7 +42,7 @@ class WasmStructInstruction extends WasmInstruction { @Nonnull private final StructOperator op; - private final StructType type; + private StructType type; private final NamedStorageType fieldName; @@ -176,6 +177,14 @@ class WasmStructInstruction extends WasmInstruction { return type; } + /** + * Set a new type for NULL const. + * @param type the type + */ + void setStructType( @Nonnull StructType type ) { + this.type = Objects.requireNonNull( type ); + } + /** * {@inheritDoc} */ @@ -285,4 +294,29 @@ class WasmStructInstruction extends WasmInstruction { throw new WasmException( "Unknown array operation: " + op, -1 ); } } + + /** + * {@inheritDoc} + */ + @Override + AnyType[] getPopValueTypes() { + switch( op ) { + case GET: + return new AnyType[] { type }; + case INSTANCEOF: + case CAST: + return new AnyType[] { options.types.valueOf( "java/lang/Object" ) }; + case NEW_WITH_RTT: + return new AnyType[] { ValueType.i32 };// rtt type + case SET: + return new AnyType[] { type, fieldName.getType() }; + case NEW: + case NEW_DEFAULT: + case NULL: + case RTT_CANON: + return null; + default: + throw new WasmException( "Unknown array operation: " + op, -1 ); + } + } } diff --git a/src/de/inetsoftware/jwebassembly/module/WasmTableInstruction.java b/src/de/inetsoftware/jwebassembly/module/WasmTableInstruction.java index 0fd7452..151b500 100644 --- a/src/de/inetsoftware/jwebassembly/module/WasmTableInstruction.java +++ b/src/de/inetsoftware/jwebassembly/module/WasmTableInstruction.java @@ -1,5 +1,5 @@ /* - Copyright 2019 Volker Berlin (i-net software) + Copyright 2019 - 2021 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. @@ -85,4 +85,12 @@ class WasmTableInstruction extends WasmInstruction { int getPopCount() { return load ? 0 : 1; } + + /** + * {@inheritDoc} + */ + @Override + AnyType[] getPopValueTypes() { + return load ? null : new AnyType[] { ValueType.externref }; + } }