Type specific NULL constant values.

This commit is contained in:
Volker Berlin 2021-02-14 16:27:10 +01:00
parent fb7e3e2468
commit 99e406958f
16 changed files with 282 additions and 22 deletions

View File

@ -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"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -82,4 +82,11 @@ class DupThis extends WasmInstruction {
return 0; return 0;
} }
/**
* {@inheritDoc}
*/
@Override
AnyType[] getPopValueTypes() {
return null;
}
} }

View File

@ -16,6 +16,7 @@
package de.inetsoftware.jwebassembly.module; package de.inetsoftware.jwebassembly.module;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -29,6 +30,8 @@ import de.inetsoftware.classparser.ConstantPool;
import de.inetsoftware.classparser.ConstantRef; import de.inetsoftware.classparser.ConstantRef;
import de.inetsoftware.classparser.MethodInfo; import de.inetsoftware.classparser.MethodInfo;
import de.inetsoftware.jwebassembly.WasmException; 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.AnyType;
import de.inetsoftware.jwebassembly.wasm.ArrayOperator; import de.inetsoftware.jwebassembly.wasm.ArrayOperator;
import de.inetsoftware.jwebassembly.wasm.ArrayType; 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.NumericOperator;
import de.inetsoftware.jwebassembly.wasm.StructOperator; import de.inetsoftware.jwebassembly.wasm.StructOperator;
import de.inetsoftware.jwebassembly.wasm.ValueType; import de.inetsoftware.jwebassembly.wasm.ValueType;
import de.inetsoftware.jwebassembly.wasm.ValueTypeParser;
import de.inetsoftware.jwebassembly.wasm.WasmBlockOperator; import de.inetsoftware.jwebassembly.wasm.WasmBlockOperator;
/** /**
@ -73,8 +77,8 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
branchManager.reset( code ); branchManager.reset( code );
byteCode = code.getByteCode(); byteCode = code.getByteCode();
boolean hasReturn = !method.getType().endsWith( ")V" ); AnyType returnType = new ValueTypeParser( method.getType().substring( method.getType().lastIndexOf( ')' ) + 1), getTypeManager() ).next();
writeCode( byteCode, code.getConstantPool(), method.getDeclaringClassFile(), hasReturn ); writeCode( byteCode, code.getConstantPool(), method.getDeclaringClassFile(), returnType );
calculateVariables(); calculateVariables();
} catch( Exception ioex ) { } catch( Exception ioex ) {
int lineNumber = byteCode == null ? -1 : byteCode.getLineNumber(); int lineNumber = byteCode == null ? -1 : byteCode.getLineNumber();
@ -91,12 +95,13 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
* the constant pool of the the current class * the constant pool of the the current class
* @param classFile * @param classFile
* the declaring class file * the declaring class file
* @param hasReturn * @param returnType
* if the method has a return value * the return type of the method
* @throws WasmException * @throws WasmException
* if some Java code can't converted * 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; int lineNumber = -1;
try { try {
boolean wide = false; boolean wide = false;
@ -109,6 +114,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
break; break;
case 1: // aconst_null case 1: // aconst_null
addStructInstruction( StructOperator.NULL, "java/lang/Object", null, codePos, lineNumber ); addStructInstruction( StructOperator.NULL, "java/lang/Object", null, codePos, lineNumber );
nullConstants = true;
break; break;
case 2: // iconst_m1 case 2: // iconst_m1
case 3: // iconst_0 case 3: // iconst_0
@ -580,7 +586,7 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
type = ValueType.f64; type = ValueType.f64;
break; break;
case 176: // areturn case 176: // areturn
type = ValueType.externref; type = getOptions().useGC() ? returnType : ValueType.externref;
break; break;
} }
addBlockInstruction( WasmBlockOperator.RETURN, type, codePos, lineNumber ); addBlockInstruction( WasmBlockOperator.RETURN, type, codePos, lineNumber );
@ -723,12 +729,17 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
} }
branchManager.calculate(); branchManager.calculate();
branchManager.handle( byteCode ); // add branch operations 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 // 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 // Java does not need a return byte code in this case
// But WebAssembly need the dead code to validate // But WebAssembly need the dead code to validate
addBlockInstruction( WasmBlockOperator.UNREACHABLE, null, byteCode.getCodePosition(), byteCode.getLineNumber() ); addBlockInstruction( WasmBlockOperator.UNREACHABLE, null, byteCode.getCodePosition(), byteCode.getLineNumber() );
} }
if( nullConstants && getOptions().useGC() ) {
patchTypeOfNullConst();
}
} catch( Exception ex ) { } catch( Exception ex ) {
throw WasmException.create( ex, lineNumber ); throw WasmException.create( ex, lineNumber );
} }
@ -925,4 +936,33 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
branchManager.addIfOperator( codePos, offset, byteCode.getLineNumber(), compare ); branchManager.addIfOperator( codePos, offset, byteCode.getLineNumber(), compare );
} }
/**
* NULL const has no type in Java. In WebAssembly currently.
*/
private void patchTypeOfNullConst() {
List<WasmInstruction> 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++;
}
}
}
}
}
}
} }

View File

@ -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"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -95,4 +95,13 @@ class JumpInstruction extends WasmInstruction {
int getJumpPosition() { int getJumpPosition() {
return jumpPos; return jumpPos;
} }
/**
* {@inheritDoc}
*/
@Override
AnyType[] getPopValueTypes() {
// TODO
return null;
}
} }

View File

@ -26,7 +26,6 @@ import de.inetsoftware.jwebassembly.module.TypeManager.StructType;
import de.inetsoftware.jwebassembly.wasm.AnyType; import de.inetsoftware.jwebassembly.wasm.AnyType;
import de.inetsoftware.jwebassembly.wasm.ArrayOperator; import de.inetsoftware.jwebassembly.wasm.ArrayOperator;
import de.inetsoftware.jwebassembly.wasm.ArrayType; import de.inetsoftware.jwebassembly.wasm.ArrayType;
import de.inetsoftware.jwebassembly.wasm.StructOperator;
import de.inetsoftware.jwebassembly.wasm.ValueType; import de.inetsoftware.jwebassembly.wasm.ValueType;
/** /**
@ -228,4 +227,27 @@ class WasmArrayInstruction extends WasmInstruction {
throw new WasmException( "Unknown array operation: " + op, -1 ); 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 );
}
}
} }

View File

@ -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"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with 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 THROW:
case RETHROW: case RETHROW:
return 1; return 1;
case RETURN:
return data == null ? 0 : 1;
default: default:
return 0; 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;
}
}
} }

View File

@ -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"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -136,6 +136,29 @@ class WasmCallInstruction extends WasmInstruction {
return paramCount; 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<AnyType> parser = name.getSignature( types );
while( idx < paramCount ) {
valueTypes[ idx++ ] = parser.next();
}
}
return valueTypes;
}
/** /**
* Count the parameters in the signature * Count the parameters in the signature
*/ */

View File

@ -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"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -121,4 +121,12 @@ class WasmConstInstruction extends WasmInstruction {
int getPopCount() { int getPopCount() {
return 0; return 0;
} }
/**
* {@inheritDoc}
*/
@Override
AnyType[] getPopValueTypes() {
return null;
}
} }

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -97,4 +97,34 @@ class WasmConvertInstruction extends WasmInstruction {
int getPopCount() { int getPopCount() {
return 1; 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() );
}
}
} }

View File

@ -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"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -98,4 +98,12 @@ class WasmGlobalInstruction extends WasmInstruction {
int getPopCount() { int getPopCount() {
return load ? 0 : 1; return load ? 0 : 1;
} }
/**
* {@inheritDoc}
*/
@Override
AnyType[] getPopValueTypes() {
return load ? null : new AnyType[] { type };
}
} }

View File

@ -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"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -115,4 +115,6 @@ abstract class WasmInstruction {
* @return the count * @return the count
*/ */
abstract int getPopCount(); abstract int getPopCount();
abstract AnyType[] getPopValueTypes();
} }

View File

@ -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"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -122,4 +122,12 @@ class WasmLocalInstruction extends WasmInstruction {
int getPopCount() { int getPopCount() {
return op == get ? 0 : 1; return op == get ? 0 : 1;
} }
/**
* {@inheritDoc}
*/
@Override
AnyType[] getPopValueTypes() {
return op == get ? null : new AnyType[] { localVariables.getValueType( getIndex() ) };
}
} }

View File

@ -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"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -95,4 +95,12 @@ class WasmMemoryInstruction extends WasmInstruction {
int getPopCount() { int getPopCount() {
return op.name().startsWith( "load" ) ? 0 : 1; return op.name().startsWith( "load" ) ? 0 : 1;
} }
/**
* {@inheritDoc}
*/
@Override
AnyType[] getPopValueTypes() {
return op.name().startsWith( "load" ) ? null : new AnyType[] { type };
}
} }

View File

@ -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"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -71,4 +71,12 @@ class WasmNopInstruction extends WasmInstruction {
int getPopCount() { int getPopCount() {
return 0; return 0;
} }
/**
* {@inheritDoc}
*/
@Override
AnyType[] getPopValueTypes() {
return null;
}
} }

View File

@ -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"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -111,4 +111,26 @@ class WasmNumericInstruction extends WasmInstruction {
return 2; 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 };
}
}
} }

View File

@ -18,6 +18,7 @@ package de.inetsoftware.jwebassembly.module;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Objects;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -41,7 +42,7 @@ class WasmStructInstruction extends WasmInstruction {
@Nonnull @Nonnull
private final StructOperator op; private final StructOperator op;
private final StructType type; private StructType type;
private final NamedStorageType fieldName; private final NamedStorageType fieldName;
@ -176,6 +177,14 @@ class WasmStructInstruction extends WasmInstruction {
return type; return type;
} }
/**
* Set a new type for NULL const.
* @param type the type
*/
void setStructType( @Nonnull StructType type ) {
this.type = Objects.requireNonNull( type );
}
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@ -285,4 +294,29 @@ class WasmStructInstruction extends WasmInstruction {
throw new WasmException( "Unknown array operation: " + op, -1 ); 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 );
}
}
} }

View File

@ -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"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -85,4 +85,12 @@ class WasmTableInstruction extends WasmInstruction {
int getPopCount() { int getPopCount() {
return load ? 0 : 1; return load ? 0 : 1;
} }
/**
* {@inheritDoc}
*/
@Override
AnyType[] getPopValueTypes() {
return load ? null : new AnyType[] { ValueType.externref };
}
} }