The needThis flag must be set already on marking a function as needing. If it will set on scan it is to late for stack calculation.

This commit is contained in:
Volker Berlin 2021-04-17 20:27:28 +02:00
parent d271ac1a2f
commit b35279a960
9 changed files with 45 additions and 49 deletions

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.
@ -135,7 +135,7 @@ class FunctionManager {
states.remove( name ); states.remove( name );
states.put( name, state ); states.put( name, state );
} }
markAsNeeded( name ); markAsNeeded( name, !name.istStatic() );
} }
/** /**
@ -143,15 +143,18 @@ class FunctionManager {
* *
* @param name * @param name
* the function name * the function name
* @param needThisParameter
* if this function need additional to the parameter of the signature an extra "this" parameter
* @return the real function name * @return the real function name
*/ */
FunctionName markAsNeeded( @Nonnull FunctionName name ) { FunctionName markAsNeeded( @Nonnull FunctionName name, boolean needThisParameter ) {
FunctionState state = getOrCreate( name ); FunctionState state = getOrCreate( name );
if( state.state == State.None ) { if( state.state == State.None ) {
if( isFinish ) { if( isFinish ) {
throw new WasmException( "Prepare was already finish: " + name.signatureName, -1 ); throw new WasmException( "Prepare was already finish: " + name.signatureName, -1 );
} }
state.state = State.Needed; state.state = State.Needed;
state.needThisParameter = needThisParameter;
JWebAssembly.LOGGER.fine( "\t\tcall: " + name.signatureName ); JWebAssembly.LOGGER.fine( "\t\tcall: " + name.signatureName );
usedClasses.add( name.className ); usedClasses.add( name.className );
} }
@ -163,10 +166,8 @@ class FunctionManager {
* *
* @param name * @param name
* the function name * the function name
* @param needThisParameter
* if this function need additional to the parameter of the signature an extra "this" parameter
*/ */
void markAsScanned( @Nonnull FunctionName name, boolean needThisParameter ) { void markAsScanned( @Nonnull FunctionName name ) {
FunctionState state = getOrCreate( name ); FunctionState state = getOrCreate( name );
switch( state.state ) { switch( state.state ) {
case None: case None:
@ -174,7 +175,6 @@ class FunctionManager {
state.state = State.Scanned; state.state = State.Scanned;
break; break;
} }
state.needThisParameter = needThisParameter;
} }
/** /**

View File

@ -362,14 +362,14 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
break; break;
case 108: // idiv case 108: // idiv
if( getOptions().useEH() ) { if( getOptions().useEH() ) {
addCallInstruction( new FunctionName( "de/inetsoftware/jwebassembly/module/WasmEmbbeddedCode", "idiv", "(II)I" ), codePos, lineNumber ); addCallInstruction( new FunctionName( "de/inetsoftware/jwebassembly/module/WasmEmbbeddedCode", "idiv", "(II)I" ), false, codePos, lineNumber );
} else { } else {
addNumericInstruction( NumericOperator.div, ValueType.i32, codePos, lineNumber ); addNumericInstruction( NumericOperator.div, ValueType.i32, codePos, lineNumber );
} }
break; break;
case 109: // ldiv case 109: // ldiv
if( getOptions().useEH() ) { if( getOptions().useEH() ) {
addCallInstruction( new FunctionName( "de/inetsoftware/jwebassembly/module/WasmEmbbeddedCode", "ldiv", "(JJ)J" ), codePos, lineNumber ); addCallInstruction( new FunctionName( "de/inetsoftware/jwebassembly/module/WasmEmbbeddedCode", "ldiv", "(JJ)J" ), false, codePos, lineNumber );
} else { } else {
addNumericInstruction( NumericOperator.div, ValueType.i64, codePos, lineNumber ); addNumericInstruction( NumericOperator.div, ValueType.i64, codePos, lineNumber );
} }
@ -388,11 +388,11 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
break; break;
case 114: // frem case 114: // frem
//helper function like: (a - (int)(a / b) * (float)b) //helper function like: (a - (int)(a / b) * (float)b)
addCallInstruction( new WatCodeSyntheticFunctionName( "frem", "local.get 0 local.get 0 local.get 1 f32.div i32.trunc_sat_f32_s f32.convert_i32_s local.get 1 f32.mul f32.sub return", ValueType.f32, ValueType.f32, null, ValueType.f32 ), codePos, lineNumber ); addCallInstruction( new WatCodeSyntheticFunctionName( "frem", "local.get 0 local.get 0 local.get 1 f32.div i32.trunc_sat_f32_s f32.convert_i32_s local.get 1 f32.mul f32.sub return", ValueType.f32, ValueType.f32, null, ValueType.f32 ), false, codePos, lineNumber );
break; break;
case 115: // drem case 115: // drem
//helper function like: (a - (long)(a / b) * (double)b) //helper function like: (a - (long)(a / b) * (double)b)
addCallInstruction( new WatCodeSyntheticFunctionName( "drem", "local.get 0 local.get 0 local.get 1 f64.div i64.trunc_sat_f64_s f64.convert_i64_s local.get 1 f64.mul f64.sub return", ValueType.f64, ValueType.f64, null, ValueType.f64 ), codePos, lineNumber ); addCallInstruction( new WatCodeSyntheticFunctionName( "drem", "local.get 0 local.get 0 local.get 1 f64.div i64.trunc_sat_f64_s f64.convert_i64_s local.get 1 f64.mul f64.sub return", ValueType.f64, ValueType.f64, null, ValueType.f64 ), false, codePos, lineNumber );
break; break;
case 116: // ineg case 116: // ineg
addConstInstruction( -1, ValueType.i32, codePos, lineNumber ); addConstInstruction( -1, ValueType.i32, codePos, lineNumber );
@ -621,10 +621,10 @@ class JavaMethodWasmCodeBuilder extends WasmCodeBuilder {
addCallVirtualInstruction( funcName, codePos, lineNumber ); addCallVirtualInstruction( funcName, codePos, lineNumber );
break; break;
case 183: case 183:
addCallInstruction( funcName, codePos, lineNumber ); addCallInstruction( funcName, true, codePos, lineNumber );
break; break;
case 184: case 184:
addCallInstruction( funcName, codePos, lineNumber ); addCallInstruction( funcName, false, codePos, lineNumber );
break; break;
case 185: case 185:
addCallInterfaceInstruction( funcName, codePos, lineNumber ); addCallInterfaceInstruction( funcName, codePos, lineNumber );

View File

@ -208,7 +208,7 @@ public class ModuleGenerator {
} else { } else {
functions.markAsImport( synth, synth.getAnnotation() ); functions.markAsImport( synth, synth.getAnnotation() );
} }
functions.markAsScanned( next, !synth.istStatic() ); functions.markAsScanned( next );
continue; continue;
} }
@ -224,11 +224,8 @@ public class ModuleGenerator {
} }
if( method != null ) { if( method != null ) {
createInstructions( functions.replace( next, method ) ); createInstructions( functions.replace( next, method ) );
boolean needThisParameter = !method.isStatic() // if not static there is a not declared THIS parameter functions.markAsScanned( next );
|| "<init>".equals( method.getName() ) // constructor method need also the THIS parameter also if marked as static if( functions.needThisParameter( next ) ) {
/*|| (method.isLambda() )*/; // lambda functions are static but will call with a THIS parameter which need be removed from stack
functions.markAsScanned( next, needThisParameter );
if( needThisParameter ) {
types.valueOf( next.className ); // for the case that the type unknown yet types.valueOf( next.className ); // for the case that the type unknown yet
} }
continue; continue;
@ -240,7 +237,7 @@ public class ModuleGenerator {
method = superClassFile.getMethod( next.methodName, next.signature ); method = superClassFile.getMethod( next.methodName, next.signature );
if( method != null ) { if( method != null ) {
FunctionName name = new FunctionName( method ); FunctionName name = new FunctionName( method );
functions.markAsNeeded( name ); functions.markAsNeeded( name, !method.isStatic() );
functions.setAlias( next, name ); functions.setAlias( next, name );
continue NEXT; // we have found a super method continue NEXT; // we have found a super method
} }
@ -256,7 +253,7 @@ public class ModuleGenerator {
method = iClassFile.getMethod( next.methodName, next.signature ); method = iClassFile.getMethod( next.methodName, next.signature );
if( method != null ) { if( method != null ) {
FunctionName name = new FunctionName( method ); FunctionName name = new FunctionName( method );
functions.markAsNeeded( name ); functions.markAsNeeded( name, !method.isStatic() );
functions.setAlias( next, name ); functions.setAlias( next, name );
continue NEXT; // we have found a super method continue NEXT; // we have found a super method
} }
@ -344,7 +341,7 @@ public class ModuleGenerator {
if( classFile != null ) { if( classFile != null ) {
MethodInfo method = classFile.getMethod( "<clinit>", "()V" ); MethodInfo method = classFile.getMethod( "<clinit>", "()V" );
if( method != null ) { if( method != null ) {
functions.markAsNeeded( new FunctionName( method ) ); functions.markAsNeeded( new FunctionName( method ), false );
} }
} }
} }
@ -360,7 +357,7 @@ public class ModuleGenerator {
// add the start function/section only if there are static code // add the start function/section only if there are static code
if( functions.getWriteLaterClinit().hasNext() ) { if( functions.getWriteLaterClinit().hasNext() ) {
FunctionName start = new StaticCodeBuilder( writer.options, classFileLoader, javaCodeBuilder ).createStartFunction(); FunctionName start = new StaticCodeBuilder( writer.options, classFileLoader, javaCodeBuilder ).createStartFunction();
functions.markAsNeeded( start ); functions.markAsNeeded( start, false );
writeMethodSignature( start, FunctionType.Start, null ); writeMethodSignature( start, FunctionType.Start, null );
} }
} }
@ -474,7 +471,7 @@ public class ModuleGenerator {
if( !method.isStatic() ) { if( !method.isStatic() ) {
throw new WasmException( "Export method must be static: " + name.fullName, -1 ); throw new WasmException( "Export method must be static: " + name.fullName, -1 );
} }
functions.markAsNeeded( name ); functions.markAsNeeded( name, false );
return; return;
} }
} catch( Exception ioex ) { } catch( Exception ioex ) {

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.
@ -85,7 +85,7 @@ class StaticCodeBuilder {
while( !clinits.isEmpty() ) { while( !clinits.isEmpty() ) {
FunctionName name = clinits.pop(); FunctionName name = clinits.pop();
watParser.addCallInstruction( name, 0, -1 ); watParser.addCallInstruction( name, false, 0, -1 );
scanAndPatchIfNeeded( name ); scanAndPatchIfNeeded( name );
} }
return watParser; return watParser;

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2019 - 2020 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.
@ -84,7 +84,7 @@ public class StringManager extends LinkedHashMap<String, Integer> {
} }
}; };
functions.markAsNeededAndReplaceIfExists( offsetFunction ); functions.markAsNeededAndReplaceIfExists( offsetFunction );
functions.markAsNeeded( stringConstantFunction ); functions.markAsNeeded( stringConstantFunction, false );
} }
return stringConstantFunction; return stringConstantFunction;

View File

@ -254,7 +254,7 @@ public class TypeManager {
return "i32.const " + typeTableOffset; return "i32.const " + typeTableOffset;
} }
}; };
options.functions.markAsNeeded( offsetFunction ); options.functions.markAsNeeded( offsetFunction, !offsetFunction.istStatic() );
return offsetFunction; return offsetFunction;
} }
@ -804,7 +804,7 @@ public class TypeManager {
if( func.methodName.equals( funcName.methodName ) && func.signature.equals( funcName.signature ) ) { if( func.methodName.equals( funcName.methodName ) && func.signature.equals( funcName.signature ) ) {
if( !isDefault || functions.getITableIndex( func ) >= 0 ) { if( !isDefault || functions.getITableIndex( func ) >= 0 ) {
vtable.set( idx, funcName ); // use the override method vtable.set( idx, funcName ); // use the override method
functions.markAsNeeded( funcName ); // mark all overridden methods also as needed if the super method is used functions.markAsNeeded( funcName, true ); // mark all overridden methods also as needed if the super method is used
} }
break; break;
} }
@ -891,7 +891,7 @@ public class TypeManager {
if( method != null ) { if( method != null ) {
FunctionName methodName = new FunctionName( method ); FunctionName methodName = new FunctionName( method );
functions.markAsNeeded( methodName ); functions.markAsNeeded( methodName, !method.isStatic() );
if( iMethods == null ) { if( iMethods == null ) {
interfaceMethods.put( type, iMethods = new ArrayList<>() ); interfaceMethods.put( type, iMethods = new ArrayList<>() );
} }
@ -1210,7 +1210,7 @@ public class TypeManager {
codebuilder.addStructInstruction( StructOperator.GET, name, paramFields.get( i ), 0, -1 ); codebuilder.addStructInstruction( StructOperator.GET, name, paramFields.get( i ), 0, -1 );
} }
codebuilder.addCallInstruction( syntheticLambdaFunctionName, 0, -1 ); codebuilder.addCallInstruction( syntheticLambdaFunctionName, false, 0, -1 );
return watParser; return watParser;
} }
}; };

View File

@ -477,7 +477,7 @@ public abstract class WasmCodeBuilder {
Integer id = types.valueOf( className ).getClassIndex(); Integer id = types.valueOf( className ).getClassIndex();
FunctionName name = types.getClassConstantFunction(); FunctionName name = types.getClassConstantFunction();
instructions.add( new WasmConstInstruction( id, ValueType.i32, javaCodePos, lineNumber ) ); instructions.add( new WasmConstInstruction( id, ValueType.i32, javaCodePos, lineNumber ) );
addCallInstruction( name, javaCodePos, lineNumber ); addCallInstruction( name, false, javaCodePos, lineNumber );
} else { } else {
//TODO There can be ConstantClass, MethodType and MethodHandle //TODO There can be ConstantClass, MethodType and MethodHandle
throw new WasmException( "Class constants are not supported. : " + value, lineNumber ); throw new WasmException( "Class constants are not supported. : " + value, lineNumber );
@ -520,7 +520,7 @@ public abstract class WasmCodeBuilder {
WasmNumericInstruction numeric = new WasmNumericInstruction( numOp, valueType, javaCodePos, lineNumber ); WasmNumericInstruction numeric = new WasmNumericInstruction( numOp, valueType, javaCodePos, lineNumber );
instructions.add( numeric ); instructions.add( numeric );
if( !options.useGC() && options.ref_eq == null && (numOp == NumericOperator.ref_eq || numOp == NumericOperator.ref_ne ) ) { if( !options.useGC() && options.ref_eq == null && (numOp == NumericOperator.ref_eq || numOp == NumericOperator.ref_ne ) ) {
functions.markAsNeeded( options.ref_eq = getNonGC( "ref_eq", lineNumber ) ); functions.markAsNeeded( options.ref_eq = getNonGC( "ref_eq", lineNumber ), false );
} }
return numeric; return numeric;
} }
@ -549,9 +549,8 @@ public abstract class WasmCodeBuilder {
* @param lineNumber * @param lineNumber
* the line number in the Java source code * the line number in the Java source code
*/ */
protected void addCallInstruction( FunctionName name, int javaCodePos, int lineNumber ) { protected void addCallInstruction( FunctionName name, boolean needThisParameter, int javaCodePos, int lineNumber ) {
name = functions.markAsNeeded( name ); name = functions.markAsNeeded( name, needThisParameter );
boolean needThisParameter = functions.needThisParameter( name );
WasmCallInstruction instruction = new WasmCallInstruction( name, javaCodePos, lineNumber, types, needThisParameter ); WasmCallInstruction instruction = new WasmCallInstruction( name, javaCodePos, lineNumber, types, needThisParameter );
if( "<init>".equals( name.methodName ) ) { if( "<init>".equals( name.methodName ) ) {
@ -642,7 +641,7 @@ public abstract class WasmCodeBuilder {
* the line number in the Java source code * the line number in the Java source code
*/ */
protected void addCallVirtualInstruction( FunctionName name, int javaCodePos, int lineNumber ) { protected void addCallVirtualInstruction( FunctionName name, int javaCodePos, int lineNumber ) {
name = functions.markAsNeeded( name ); name = functions.markAsNeeded( name, true );
addCallIndirectInstruction( new WasmCallVirtualInstruction( name, javaCodePos, lineNumber, types, options ) ); addCallIndirectInstruction( new WasmCallVirtualInstruction( name, javaCodePos, lineNumber, types, options ) );
options.getCallVirtual(); // mark the function as needed options.getCallVirtual(); // mark the function as needed
functions.markClassAsUsed( name.className ); functions.markClassAsUsed( name.className );
@ -658,7 +657,7 @@ public abstract class WasmCodeBuilder {
* the line number in the Java source code * the line number in the Java source code
*/ */
protected void addCallInterfaceInstruction( FunctionName name, int javaCodePos, int lineNumber ) { protected void addCallInterfaceInstruction( FunctionName name, int javaCodePos, int lineNumber ) {
name = functions.markAsNeeded( name ); name = functions.markAsNeeded( name, true );
addCallIndirectInstruction( new WasmCallInterfaceInstruction( name, javaCodePos, lineNumber, types, options ) ); addCallIndirectInstruction( new WasmCallInterfaceInstruction( name, javaCodePos, lineNumber, types, options ) );
options.getCallInterface(); // mark the function as needed options.getCallInterface(); // mark the function as needed
functions.markClassAsUsed( name.className ); functions.markClassAsUsed( name.className );
@ -773,7 +772,7 @@ public abstract class WasmCodeBuilder {
instructions.add( arrayInst ); instructions.add( arrayInst );
SyntheticFunctionName name = arrayInst.createNonGcFunction( useGC ); SyntheticFunctionName name = arrayInst.createNonGcFunction( useGC );
if( name != null ) { if( name != null ) {
functions.markAsNeeded( name ); functions.markAsNeeded( name, !name.istStatic() );
functions.markAsImport( name, name.getAnnotation() ); functions.markAsImport( name, name.getAnnotation() );
} }
} }
@ -809,7 +808,7 @@ public abstract class WasmCodeBuilder {
*/ */
protected void addMultiNewArrayInstruction( int dim, ArrayType type, int javaCodePos, int lineNumber ) { protected void addMultiNewArrayInstruction( int dim, ArrayType type, int javaCodePos, int lineNumber ) {
MultiArrayFunctionName name = new MultiArrayFunctionName( dim, type ); MultiArrayFunctionName name = new MultiArrayFunctionName( dim, type );
addCallInstruction( name, javaCodePos, lineNumber ); addCallInstruction( name, false, javaCodePos, lineNumber );
} }
/** /**
@ -846,7 +845,7 @@ public abstract class WasmCodeBuilder {
if( !options.useGC() ) { if( !options.useGC() ) {
SyntheticFunctionName name = structInst.createNonGcFunction(); SyntheticFunctionName name = structInst.createNonGcFunction();
if( name != null ) { if( name != null ) {
functions.markAsNeeded( name ); functions.markAsNeeded( name, !name.istStatic() );
functions.markAsImport( name, name.getAnnotation() ); functions.markAsImport( name, name.getAnnotation() );
} }
} }
@ -881,7 +880,7 @@ public abstract class WasmCodeBuilder {
} while( true ); } while( true );
StructType interfaceType = (StructType)parser.next(); StructType interfaceType = (StructType)parser.next();
LambdaType type = types.lambdaType( method, params, interfaceType, interfaceMethodName ); LambdaType type = types.lambdaType( method, params, interfaceType, interfaceMethodName );
functions.markAsNeeded( type.getLambdaMethod() ); functions.markAsNeeded( type.getLambdaMethod(), true );
String lambdaTypeName = type.getName(); String lambdaTypeName = type.getName();
// Create the instance of the synthetic lambda class and save the parameters in fields // Create the instance of the synthetic lambda class and save the parameters in fields

View File

@ -126,7 +126,7 @@ public class WasmOptions {
if( get_i32 == null ) { if( get_i32 == null ) {
SyntheticFunctionName name; SyntheticFunctionName name;
get_i32 = name = new JavaScriptSyntheticFunctionName( "NonGC", "get_i32", () -> "(a,i) => a[i]", ValueType.externref, ValueType.i32, null, ValueType.i32 ); get_i32 = name = new JavaScriptSyntheticFunctionName( "NonGC", "get_i32", () -> "(a,i) => a[i]", ValueType.externref, ValueType.i32, null, ValueType.i32 );
functions.markAsNeeded( name ); functions.markAsNeeded( name, !name.istStatic() );
functions.markAsImport( name, name.getAnnotation() ); functions.markAsImport( name, name.getAnnotation() );
} }
} }
@ -142,7 +142,7 @@ public class WasmOptions {
FunctionName name = callVirtual; FunctionName name = callVirtual;
if( name == null ) { if( name == null ) {
callVirtual = name = types.createCallVirtual(); callVirtual = name = types.createCallVirtual();
functions.markAsNeeded( name ); functions.markAsNeeded( name, false );
registerGet_i32(); registerGet_i32();
} }
return name; return name;
@ -159,7 +159,7 @@ public class WasmOptions {
FunctionName name = callInterface; FunctionName name = callInterface;
if( name == null ) { if( name == null ) {
callInterface = name = types.createCallInterface(); callInterface = name = types.createCallInterface();
functions.markAsNeeded( name ); functions.markAsNeeded( name, false );
registerGet_i32(); registerGet_i32();
} }
return name; return name;
@ -176,7 +176,7 @@ public class WasmOptions {
SyntheticFunctionName name = instanceOf; SyntheticFunctionName name = instanceOf;
if( name == null ) { if( name == null ) {
instanceOf = name = types.createInstanceOf(); instanceOf = name = types.createInstanceOf();
functions.markAsNeeded( name ); functions.markAsNeeded( name, !name.istStatic() );
registerGet_i32(); registerGet_i32();
} }
return name; return name;
@ -193,7 +193,7 @@ public class WasmOptions {
SyntheticFunctionName name = cast; SyntheticFunctionName name = cast;
if( name == null ) { if( name == null ) {
cast = name = types.createCast(); cast = name = types.createCast();
functions.markAsNeeded( name ); functions.markAsNeeded( name, !name.istStatic() );
getInstanceOf(); getInstanceOf();
} }
return name; return name;

View File

@ -234,7 +234,7 @@ public class WatParser extends WasmCodeBuilder {
} while ( !")".equals( str ) ); } while ( !")".equals( str ) );
builder.append( get( tokens, ++i ) ); builder.append( get( tokens, ++i ) );
FunctionName name = new FunctionName( builder.substring( 1 ) ); FunctionName name = new FunctionName( builder.substring( 1 ) );
addCallInstruction( name, javaCodePos, lineNumber ); addCallInstruction( name, false, javaCodePos, lineNumber );
} catch( Exception ex ) { } catch( Exception ex ) {
throw WasmException.create( "The syntax for a function name is $package.ClassName.methodName(paramSignature)returnSignature", ex ); throw WasmException.create( "The syntax for a function name is $package.ClassName.methodName(paramSignature)returnSignature", ex );
} }