2018-11-04 20:28:42 +01:00
/ *
2019-01-06 16:29:26 +01:00
* Copyright 2018 - 2019 Volker Berlin ( i - net software )
2018-11-04 20:28:42 +01:00
*
* Licensed under the Apache License , Version 2 . 0 ( the " License " ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* /
package de.inetsoftware.jwebassembly.module ;
2019-08-11 13:11:22 +02:00
import java.io.IOException ;
2018-11-09 20:14:30 +01:00
import java.util.ArrayList ;
2018-11-04 20:28:42 +01:00
import java.util.List ;
2019-10-27 20:11:47 +01:00
import java.util.function.Function ;
2018-11-04 20:28:42 +01:00
2018-11-09 20:14:30 +01:00
import javax.annotation.Nonnegative ;
import javax.annotation.Nonnull ;
import javax.annotation.Nullable ;
2019-08-11 13:11:22 +02:00
import de.inetsoftware.classparser.ClassFile ;
2019-04-06 17:51:29 +02:00
import de.inetsoftware.classparser.LocalVariableTable ;
2018-11-18 12:17:08 +01:00
import de.inetsoftware.classparser.Member ;
2019-08-11 13:11:22 +02:00
import de.inetsoftware.classparser.MethodInfo ;
import de.inetsoftware.jwebassembly.WasmException ;
2019-12-23 20:56:12 +01:00
import de.inetsoftware.jwebassembly.javascript.JavaScriptSyntheticFunctionName ;
2019-08-11 13:11:22 +02:00
import de.inetsoftware.jwebassembly.javascript.NonGC ;
2019-03-03 21:33:09 +01:00
import de.inetsoftware.jwebassembly.module.WasmInstruction.Type ;
import de.inetsoftware.jwebassembly.wasm.AnyType ;
2018-12-03 21:09:22 +01:00
import de.inetsoftware.jwebassembly.wasm.ArrayOperator ;
2019-11-18 21:32:35 +01:00
import de.inetsoftware.jwebassembly.wasm.MemoryOperator ;
2019-04-21 21:33:22 +02:00
import de.inetsoftware.jwebassembly.wasm.NamedStorageType ;
2018-12-03 21:09:22 +01:00
import de.inetsoftware.jwebassembly.wasm.NumericOperator ;
2018-12-05 22:14:26 +01:00
import de.inetsoftware.jwebassembly.wasm.StructOperator ;
2018-12-03 21:09:22 +01:00
import de.inetsoftware.jwebassembly.wasm.ValueType ;
2019-04-27 21:14:55 +02:00
import de.inetsoftware.jwebassembly.wasm.ValueTypeParser ;
2019-10-05 16:15:18 +02:00
import de.inetsoftware.jwebassembly.wasm.VariableOperator ;
2018-12-03 21:09:22 +01:00
import de.inetsoftware.jwebassembly.wasm.WasmBlockOperator ;
2019-09-09 21:07:45 +02:00
import de.inetsoftware.jwebassembly.wasm.WasmOptions ;
2018-11-09 20:14:30 +01:00
2018-11-04 20:28:42 +01:00
/ * *
* Base class for Code Building .
*
* @author Volker Berlin
* /
public abstract class WasmCodeBuilder {
2019-12-23 20:56:12 +01:00
/ * *
* declare for frequently use of virtual call with non GC mode .
* /
static final SyntheticFunctionName GET_I32 = new JavaScriptSyntheticFunctionName ( " NonGC " , " get_i32 " , ( ) - > " (a,i) => a[i] " , ValueType . anyref , ValueType . i32 , null , ValueType . i32 ) ;
2018-11-09 20:14:30 +01:00
private final LocaleVariableManager localVariables = new LocaleVariableManager ( ) ;
private final List < WasmInstruction > instructions = new ArrayList < > ( ) ;
2019-01-23 20:27:57 +01:00
private TypeManager types ;
2019-09-08 13:55:22 +02:00
private FunctionManager functions ;
2019-09-09 21:07:45 +02:00
private WasmOptions options ;
2019-08-08 19:28:27 +02:00
2019-11-10 12:57:58 +01:00
private StringManager strings ;
2019-11-03 13:52:07 +01:00
2020-01-02 15:15:21 +01:00
private ClassFileLoader classFileLoader ;
2019-10-02 18:56:35 +02:00
/ * *
* Initialize the code builder ;
*
* @param types
* the type manager
* @param functions
* the function manager
2019-11-10 12:57:58 +01:00
* @param strings
* the string manager
2019-10-02 18:56:35 +02:00
* @param options
* compiler properties
* /
2020-01-02 15:15:21 +01:00
void init ( TypeManager types , FunctionManager functions , StringManager strings , WasmOptions options , ClassFileLoader classFileLoader ) {
2019-10-02 18:56:35 +02:00
this . localVariables . init ( types ) ;
this . types = types ;
this . functions = functions ;
2019-11-10 12:57:58 +01:00
this . strings = strings ;
2019-10-02 18:56:35 +02:00
this . options = options ;
2020-01-02 15:15:21 +01:00
this . classFileLoader = classFileLoader ;
2019-10-02 18:56:35 +02:00
}
2018-11-04 20:28:42 +01:00
/ * *
* Get the list of instructions
*
* @return the list
* /
2018-11-09 20:14:30 +01:00
List < WasmInstruction > getInstructions ( ) {
return instructions ;
}
2018-11-04 20:28:42 +01:00
2019-03-03 21:33:09 +01:00
/ * *
* Check if the last instruction is a return instruction
*
* @return true , if a return
* /
boolean isEndsWithReturn ( ) {
WasmInstruction instr = instructions . get ( instructions . size ( ) - 1 ) ;
if ( instr . getType ( ) = = Type . Block ) {
return ( ( WasmBlockInstruction ) instr ) . getOperation ( ) = = WasmBlockOperator . RETURN ;
}
return false ;
}
2019-01-23 20:27:57 +01:00
/ * *
2019-10-02 18:56:35 +02:00
* We need one value from the stack inside of a block . We need to find the WasmInstruction on which the block can
* start . If this a function call or numeric expression this can be complex to find the right point .
2019-01-23 20:27:57 +01:00
*
2019-10-02 18:56:35 +02:00
* @param count
* the count of values on the stack back . 1 means the last value . 2 means the penultimate value .
* @return the code position that push the last instruction
2019-01-23 20:27:57 +01:00
* /
2019-10-02 18:56:35 +02:00
int findPushInstructionCodePosition ( int count ) {
2019-10-05 16:15:18 +02:00
return findPushInstruction ( count , true ) ;
}
/ * *
* We need one value from the stack inside of a block . We need to find the WasmInstruction on which the block can
* start . If this a function call or numeric expression this can be complex to find the right point .
*
* @param count
* the count of values on the stack back . 1 means the last value . 2 means the penultimate value .
* @param codePosition
* true , get the code position ; false , get the index in the instructions
* @return the code position that push the last instruction
* /
private int findPushInstruction ( int count , boolean codePosition ) {
2019-10-02 18:56:35 +02:00
int valueCount = 0 ;
List < WasmInstruction > instructions = this . instructions ;
for ( int i = instructions . size ( ) - 1 ; i > = 0 ; i - - ) {
WasmInstruction instr = instructions . get ( i ) ;
AnyType valueType = instr . getPushValueType ( ) ;
if ( valueType ! = null ) {
valueCount + + ;
}
valueCount - = instr . getPopCount ( ) ;
if ( valueCount = = count ) {
2019-10-05 16:15:18 +02:00
return codePosition ? instr . getCodePosition ( ) : i ;
2019-10-02 18:56:35 +02:00
}
}
throw new WasmException ( " Start position not found " , - 1 ) ; // should never occur
}
/ * *
* We need the value type from the stack .
*
* @param count
* the count of values on the stack back . 1 means the last value . 2 means the penultimate value .
* @return the type of the last push value
* /
@Nonnull
AnyType findValueTypeFromStack ( int count ) {
int valueCount = 0 ;
List < WasmInstruction > instructions = this . instructions ;
for ( int i = instructions . size ( ) - 1 ; i > = 0 ; i - - ) {
WasmInstruction instr = instructions . get ( i ) ;
AnyType valueType = instr . getPushValueType ( ) ;
if ( valueType ! = null ) {
if ( + + valueCount = = count ) {
return valueType ;
}
}
valueCount - = instr . getPopCount ( ) ;
}
throw new WasmException ( " Push Value not found " , - 1 ) ; // should never occur
2019-01-23 20:27:57 +01:00
}
2018-11-04 20:28:42 +01:00
/ * *
* Get the data types of the local variables . The value is only valid until the next call .
*
* @param paramCount
* the count of method parameter which should be exclude
* @return the reused list with fresh values
* /
2019-01-20 19:58:23 +01:00
List < AnyType > getLocalTypes ( int paramCount ) {
2018-11-09 20:14:30 +01:00
return localVariables . getLocalTypes ( paramCount ) ;
}
2019-04-14 14:29:09 +02:00
/ * *
* 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 ) ;
}
2019-04-26 17:28:57 +02:00
/ * *
* Get the type manager .
*
* @return the type manager
* /
protected TypeManager getTypeManager ( ) {
return types ;
}
2018-11-09 20:14:30 +01:00
/ * *
* Reset the code builder .
2019-04-06 17:51:29 +02:00
*
* @param variableTable
* variable table of the Java method .
2019-09-23 20:33:21 +02:00
* @param method
* the method with signature as fallback for a missing variable table
2018-11-09 20:14:30 +01:00
* /
2019-09-23 20:33:21 +02:00
protected void reset ( LocalVariableTable variableTable , MethodInfo method ) {
2018-11-09 20:14:30 +01:00
instructions . clear ( ) ;
2019-09-23 20:33:21 +02:00
localVariables . reset ( variableTable , method ) ;
2018-11-09 20:14:30 +01:00
}
/ * *
* Calculate the index of the variables
* /
protected void calculateVariables ( ) {
localVariables . calculate ( ) ;
}
2018-11-04 20:28:42 +01:00
2018-11-09 20:14:30 +01:00
/ * *
* Create a WasmLoadStoreInstruction .
*
* @param valueType
* the value type
* @param load
* true : if load
2018-11-10 10:46:36 +01:00
* @param javaIdx
* the memory / slot index of the variable in Java byte code
2018-11-09 20:14:30 +01:00
* @param javaCodePos
* the code position / offset in the Java method
2019-03-31 11:23:45 +02:00
* @param lineNumber
* the line number in the Java source code
2018-11-09 20:14:30 +01:00
* /
2019-03-31 11:23:45 +02:00
protected void addLoadStoreInstruction ( AnyType valueType , boolean load , @Nonnegative int javaIdx , int javaCodePos , int lineNumber ) {
2019-04-06 17:51:29 +02:00
localVariables . use ( valueType , javaIdx , javaCodePos ) ;
2019-03-31 11:23:45 +02:00
instructions . add ( new WasmLoadStoreInstruction ( load , javaIdx , localVariables , javaCodePos , lineNumber ) ) ;
2018-11-10 10:46:36 +01:00
}
/ * *
2019-11-03 19:00:49 +01:00
* Create a WasmLoadStoreInstruction local . get / local . set .
2018-11-10 10:46:36 +01:00
*
2019-11-09 18:48:28 +01:00
* @param op
* the operation
2018-11-10 10:46:36 +01:00
* @param wasmIdx
* the index of the variable
* @param javaCodePos
* the code position / offset in the Java method
2019-03-31 11:23:45 +02:00
* @param lineNumber
* the line number in the Java source code
2018-11-10 10:46:36 +01:00
* /
2019-11-09 18:48:28 +01:00
protected void addLocalInstruction ( VariableOperator op , @Nonnegative int wasmIdx , int javaCodePos , int lineNumber ) {
2019-11-12 20:47:57 +01:00
switch ( op ) {
case set :
case tee :
AnyType valueType = findValueTypeFromStack ( 1 ) ;
localVariables . useIndex ( valueType , wasmIdx ) ;
}
2019-11-09 18:48:28 +01:00
instructions . add ( new WasmLocalInstruction ( op , wasmIdx , javaCodePos , lineNumber ) ) ;
2018-11-09 20:14:30 +01:00
}
2019-11-16 19:17:22 +01:00
/ * *
* Create a WasmDupInstruction .
*
* @param javaCodePos
* the code position / offset in the Java method
* @param lineNumber
* the line number in the Java source code
* /
protected void addDupInstruction ( int javaCodePos , int lineNumber ) {
AnyType type = findValueTypeFromStack ( 1 ) ;
int idx = getTempVariable ( type , javaCodePos , javaCodePos + 1 ) ;
instructions . add ( new WasmDupInstruction ( idx , type , localVariables , javaCodePos , lineNumber ) ) ;
// an alternative solution can be a function call with multiple return values but this seems to be slower
// new SyntheticFunctionName( "dup" + storeType, "local.get 0 local.get 0 return", storeType, null, storeType, storeType ), codePos, lineNumber )
}
2018-11-09 20:14:30 +01:00
/ * *
* Add a global instruction
*
* @param load
* true : if load
* @param ref
* reference to a static field
* @param javaCodePos
* the code position / offset in the Java method
2019-03-31 11:23:45 +02:00
* @param lineNumber
* the line number in the Java source code
2018-11-09 20:14:30 +01:00
* /
2019-03-31 11:23:45 +02:00
protected void addGlobalInstruction ( boolean load , Member ref , int javaCodePos , int lineNumber ) {
2019-04-27 21:14:55 +02:00
FunctionName name = new FunctionName ( ref ) ;
AnyType type = new ValueTypeParser ( ref . getType ( ) , types ) . next ( ) ;
instructions . add ( new WasmGlobalInstruction ( load , name , type , javaCodePos , lineNumber ) ) ;
2018-11-09 20:14:30 +01:00
}
2019-11-03 19:00:49 +01:00
/ * *
* Add a WasmTableInstruction table . get / table . set .
*
* @param load
* true : if load
* @param idx
* the index of the table
* @param javaCodePos
* the code position / offset in the Java method
* @param lineNumber
* the line number in the Java source code
* /
@Nonnull
protected void addTableInstruction ( boolean load , @Nonnegative int idx , int javaCodePos , int lineNumber ) {
instructions . add ( new WasmTableInstruction ( load , idx , javaCodePos , lineNumber ) ) ;
}
2018-11-09 20:14:30 +01:00
/ * *
* Add a constant instruction .
*
* @param value
* the value
* @param valueType
* the value type
* @param javaCodePos
* the code position / offset in the Java method
2019-03-31 11:23:45 +02:00
* @param lineNumber
* the line number in the Java source code
2018-11-09 20:14:30 +01:00
* /
2019-03-31 11:23:45 +02:00
protected void addConstInstruction ( Number value , ValueType valueType , int javaCodePos , int lineNumber ) {
instructions . add ( new WasmConstInstruction ( value , valueType , javaCodePos , lineNumber ) ) ;
2018-11-09 20:14:30 +01:00
}
/ * *
* Add a constant instruction with unknown value type .
*
* @param value
* the value
* @param javaCodePos
* the code position / offset in the Java method
2019-03-31 11:23:45 +02:00
* @param lineNumber
* the line number in the Java source code
2018-11-09 20:14:30 +01:00
* /
2019-11-03 13:52:07 +01:00
protected void addConstInstruction ( Object value , int javaCodePos , int lineNumber ) {
if ( value . getClass ( ) = = String . class ) {
Integer id = strings . get ( value ) ;
if ( id = = null ) {
strings . put ( ( String ) value , id = strings . size ( ) ) ;
}
2019-11-24 14:44:56 +01:00
FunctionName name = strings . getStringConstantFunction ( ) ;
2019-11-03 19:00:49 +01:00
instructions . add ( new WasmConstInstruction ( id , ValueType . i32 , javaCodePos , lineNumber ) ) ;
2019-11-03 13:52:07 +01:00
addCallInstruction ( name , javaCodePos , lineNumber ) ;
} else {
instructions . add ( new WasmConstInstruction ( ( Number ) value , javaCodePos , lineNumber ) ) ;
}
2018-11-09 20:14:30 +01:00
}
/ * *
* Add a numeric operation instruction
*
* @param numOp
* the operation
* @param valueType
* the value type
* @param javaCodePos
* the code position / offset in the Java method
2019-03-31 11:23:45 +02:00
* @param lineNumber
* the line number in the Java source code
2019-09-08 21:45:28 +02:00
* @return the added instruction
2018-11-09 20:14:30 +01:00
* /
2019-09-08 21:45:28 +02:00
protected WasmNumericInstruction addNumericInstruction ( @Nullable NumericOperator numOp , @Nullable ValueType valueType , int javaCodePos , int lineNumber ) {
WasmNumericInstruction numeric = new WasmNumericInstruction ( numOp , valueType , javaCodePos , lineNumber ) ;
instructions . add ( numeric ) ;
2019-09-09 21:07:45 +02:00
if ( ! options . useGC ( ) & & numOp = = NumericOperator . ref_eq ) {
2019-09-10 21:41:50 +02:00
functions . markAsNeeded ( options . ref_eq = getNonGC ( " ref_eq " , lineNumber ) , true ) ;
2019-09-08 21:45:28 +02:00
}
return numeric ;
2018-11-09 20:14:30 +01:00
}
/ * *
* Add a value convert / cast instruction .
*
* @param conversion
* the conversion
* @param javaCodePos
* the code position / offset in the Java method
2019-03-31 11:23:45 +02:00
* @param lineNumber
* the line number in the Java source code
2018-11-09 20:14:30 +01:00
* /
2019-03-31 11:23:45 +02:00
protected void addConvertInstruction ( ValueTypeConvertion conversion , int javaCodePos , int lineNumber ) {
instructions . add ( new WasmConvertInstruction ( conversion , javaCodePos , lineNumber ) ) ;
2018-11-09 20:14:30 +01:00
}
/ * *
* Add a static function call .
*
2019-01-20 10:41:33 +01:00
* @param name
* the function name that should be called
2018-11-09 20:14:30 +01:00
* @param javaCodePos
* the code position / offset in the Java method
2019-03-31 11:23:45 +02:00
* @param lineNumber
* the line number in the Java source code
2018-11-09 20:14:30 +01:00
* /
2019-03-31 11:23:45 +02:00
protected void addCallInstruction ( FunctionName name , int javaCodePos , int lineNumber ) {
2019-10-27 20:11:47 +01:00
WasmCallInstruction instruction = new WasmCallInstruction ( name , javaCodePos , lineNumber , types ) ;
if ( " <init> " . equals ( name . methodName ) ) {
2019-11-17 17:28:31 +01:00
// check if there a factory for the constructor in JavaScript then we need to do some more complex patching
2019-10-27 20:11:47 +01:00
Function < String , Object > importAnannotation = functions . getImportAnannotation ( name ) ;
2019-11-17 17:28:31 +01:00
FunctionName factoryName = null ;
if ( importAnannotation ! = null ) { // JavaScript replacement for a constructor via import
// The new signature need a return value. The <init> of Java has ever a void return value
String signature = name . signature ;
signature = signature . substring ( 0 , signature . length ( ) - 1 ) + " Ljava/lang/Object; " ;
factoryName = new ImportSyntheticFunctionName ( " String " , " init " , signature , importAnannotation ) ;
} else {
MethodInfo replace = functions . replace ( name , null ) ;
if ( replace ! = null & & ! " <init> " . equals ( replace . getName ( ) ) ) {
// the constructor was replaced with a factory method. Typical this method called then a JavaScript replacement
factoryName = new FunctionName ( replace ) ;
}
}
if ( factoryName ! = null ) {
// the constructor was replaced we need also replace the create instance instruction
2019-10-27 20:11:47 +01:00
List < WasmInstruction > instructions = this . instructions ;
for ( int i = instructions . size ( ) - 1 ; i > = 0 ; i - - ) {
WasmInstruction instr = instructions . get ( i ) ;
if ( instr . getType ( ) = = Type . Struct ) {
WasmStructInstruction struct = ( WasmStructInstruction ) instr ;
if ( struct . getOperator ( ) = = StructOperator . NEW_DEFAULT ) {
2019-11-16 19:17:22 +01:00
instructions . set ( i , new WasmNopInstruction ( struct . getCodePosition ( ) , struct . getLineNumber ( ) ) ) ; // replace NEW_DEFAULT with Nop, Nop because the code position can be needed for the branch manager
instr = instructions . get ( + + i ) ;
if ( instr . getType ( ) = = Type . Dup ) {
instructions . remove ( i ) ; // dup of the instance reference if it is later assign, missing if the object after the constructor is never assign
}
2019-10-27 20:11:47 +01:00
break ;
}
}
}
2019-11-17 17:28:31 +01:00
// the new instruction
instruction = new WasmCallInstruction ( factoryName , javaCodePos , lineNumber , types ) ;
2019-10-27 20:11:47 +01:00
}
}
instructions . add ( instruction ) ;
2018-11-09 20:14:30 +01:00
}
2019-05-14 21:47:49 +02:00
/ * *
* Add a virtual / method function call .
*
* @param name
* the function name that should be called
* @param javaCodePos
* the code position / offset in the Java method
* @param lineNumber
* the line number in the Java source code
* /
protected void addCallVirtualInstruction ( FunctionName name , int javaCodePos , int lineNumber ) {
2019-10-05 16:15:18 +02:00
WasmCallIndirectInstruction virtualCall = new WasmCallIndirectInstruction ( name , javaCodePos , lineNumber , types , options ) ;
int count = virtualCall . getPopCount ( ) ;
int idx = findPushInstruction ( count , false ) ;
WasmInstruction instr = instructions . get ( idx ) ;
int varIndex = - 1 ;
if ( instr . getType ( ) = = Type . Local ) {
WasmLocalInstruction local1 = ( WasmLocalInstruction ) instr ;
if ( local1 . getOperator ( ) = = VariableOperator . get ) {
varIndex = local1 . getIndex ( ) ;
}
}
if ( varIndex < 0 ) {
varIndex = getTempVariable ( virtualCall . getThisType ( ) , instr . getCodePosition ( ) , javaCodePos + 1 ) ;
2019-11-26 21:44:49 +01:00
idx = count = = 1 ? instructions . size ( ) : findPushInstruction ( count - 1 , false ) ;
2019-10-05 16:15:18 +02:00
instructions . add ( idx , new DupThis ( virtualCall , varIndex , javaCodePos ) ) ;
}
virtualCall . setVariableIndexOfThis ( varIndex ) ;
instructions . add ( virtualCall ) ;
2019-12-23 20:56:12 +01:00
if ( ! options . useGC ( ) ) {
functions . markAsNeeded ( GET_I32 , true ) ;
functions . markAsImport ( GET_I32 , GET_I32 . getAnnotation ( ) ) ;
}
2019-05-14 21:47:49 +02:00
}
2018-11-09 20:14:30 +01:00
/ * *
* Add a block operation .
*
* @param op
* the operation
* @param data
* extra data for some operations
* @param javaCodePos
* the code position / offset in the Java method
2019-03-31 11:23:45 +02:00
* @param lineNumber
* the line number in the Java source code
2018-11-09 20:14:30 +01:00
* /
2019-03-31 11:23:45 +02:00
protected void addBlockInstruction ( WasmBlockOperator op , @Nullable Object data , int javaCodePos , int lineNumber ) {
instructions . add ( new WasmBlockInstruction ( op , data , javaCodePos , lineNumber ) ) ;
2018-11-09 20:14:30 +01:00
}
/ * *
* Add a no operation to the instruction list as marker on the code position . This instruction will not be write to
* the output .
*
* @param javaCodePos
* the code position / offset in the Java method
2019-03-31 11:23:45 +02:00
* @param lineNumber
* the line number in the Java source code
2018-11-09 20:14:30 +01:00
* /
2019-03-31 11:23:45 +02:00
protected void addNopInstruction ( int javaCodePos , int lineNumber ) {
instructions . add ( new WasmNopInstruction ( javaCodePos , lineNumber ) ) ;
2018-11-09 20:14:30 +01:00
}
2018-12-02 19:54:59 +01:00
2019-09-08 21:45:28 +02:00
/ * *
* Get a non GC polyfill function .
* @param name the function name
* @param lineNumber the line number for a possible error
* @return the function name
* /
private FunctionName getNonGC ( String name , int lineNumber ) {
try {
2020-01-02 15:15:21 +01:00
ClassFile classFile = classFileLoader . get ( NonGC . class . getName ( ) . replace ( '.' , '/' ) ) ;
2019-09-08 21:45:28 +02:00
for ( MethodInfo method : classFile . getMethods ( ) ) {
if ( name . equals ( method . getName ( ) ) ) {
return new FunctionName ( method ) ;
}
}
} catch ( IOException ex ) {
throw WasmException . create ( ex , lineNumber ) ;
}
throw new WasmException ( " Not implemented NonGC polyfill function: " + name , lineNumber ) ;
}
2018-12-02 19:54:59 +01:00
/ * *
* Add an array operation to the instruction list as marker on the code position .
*
* @param op
* the operation
* @param type
* the array type
* @param javaCodePos
* the code position / offset in the Java method
2019-03-31 11:23:45 +02:00
* @param lineNumber
* the line number in the Java source code
2018-12-02 19:54:59 +01:00
* /
2019-03-31 11:23:45 +02:00
protected void addArrayInstruction ( ArrayOperator op , AnyType type , int javaCodePos , int lineNumber ) {
2019-09-09 21:07:45 +02:00
if ( options . useGC ( ) ) {
2019-08-27 20:41:00 +02:00
instructions . add ( new WasmArrayInstruction ( op , type , types , javaCodePos , lineNumber ) ) ;
2019-08-11 13:11:22 +02:00
} else {
2019-09-08 21:45:28 +02:00
if ( type . getCode ( ) > = 0 ) {
type = ValueType . anyref ;
2019-08-11 13:11:22 +02:00
}
2019-09-08 21:45:28 +02:00
String api = " array_ " + op . toString ( ) . toLowerCase ( ) + " _ " + type ;
FunctionName name = getNonGC ( api , lineNumber ) ;
addCallInstruction ( name , javaCodePos , lineNumber ) ;
2019-08-11 13:11:22 +02:00
}
2018-12-02 19:54:59 +01:00
}
2018-12-05 22:14:26 +01:00
/ * *
* Add an array operation to the instruction list as marker on the code position .
*
* @param op
* the operation
2019-01-06 16:29:26 +01:00
* @param typeName
* the type name
2019-01-13 11:36:07 +01:00
* @param fieldName
* the name of field if needed for the operation
2018-12-05 22:14:26 +01:00
* @param javaCodePos
* the code position / offset in the Java method
2019-03-31 11:23:45 +02:00
* @param lineNumber
* the line number in the Java source code
2018-12-05 22:14:26 +01:00
* /
2019-04-24 19:54:30 +02:00
protected void addStructInstruction ( StructOperator op , @Nonnull String typeName , @Nullable NamedStorageType fieldName , int javaCodePos , int lineNumber ) {
2019-09-08 13:55:22 +02:00
WasmStructInstruction structInst = new WasmStructInstruction ( op , typeName , fieldName , javaCodePos , lineNumber , types ) ;
instructions . add ( structInst ) ;
2019-09-09 21:07:45 +02:00
if ( ! options . useGC ( ) ) {
2019-09-08 13:55:22 +02:00
SyntheticFunctionName name = structInst . createNonGcFunction ( ) ;
if ( name ! = null ) {
functions . markAsNeeded ( name , true ) ;
functions . markAsImport ( name , name . getAnnotation ( ) ) ;
}
}
2018-12-05 22:14:26 +01:00
}
2019-11-18 21:32:35 +01:00
/ * *
* Create an instance of a load / store to the linear memory instruction
*
* @param op
* the operation
* @param type
* the type of the static field
* @param offset
* the base offset which will be added to the offset value on the stack
* @param alignment
* the alignment of the value on the linear memory ( 0 : 8 Bit ; 1 : 16 Bit ; 2 : 32 Bit )
* @param javaCodePos
* the code position / offset in the Java method
* @param lineNumber
* the line number in the Java source code
* /
protected void addMemoryInstruction ( MemoryOperator op , ValueType type , int offset , int alignment , int javaCodePos , int lineNumber ) {
instructions . add ( new WasmMemoryInstruction ( op , type , offset , alignment , javaCodePos , lineNumber ) ) ;
}
2018-11-04 20:28:42 +01:00
}