2018-11-04 20:28:42 +01:00
/ *
2022-01-09 20:48:28 +01:00
* Copyright 2018 - 2022 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 ;
2021-03-28 10:56:51 +02:00
import java.util.Collections ;
2020-03-27 21:10:02 +01:00
import java.util.Iterator ;
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 ;
2021-01-23 22:16:16 +01:00
import de.inetsoftware.classparser.BootstrapMethod ;
2019-08-11 13:11:22 +02:00
import de.inetsoftware.classparser.ClassFile ;
2020-03-15 15:49:52 +01:00
import de.inetsoftware.classparser.ConstantClass ;
2022-04-16 17:31:48 +02:00
import de.inetsoftware.classparser.FieldInfo ;
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 ;
import de.inetsoftware.jwebassembly.javascript.NonGC ;
2020-03-29 18:35:01 +02:00
import de.inetsoftware.jwebassembly.module.StackInspector.StackValue ;
2021-02-28 22:20:49 +01:00
import de.inetsoftware.jwebassembly.module.TypeManager.LambdaType ;
2021-01-23 22:16:16 +01:00
import de.inetsoftware.jwebassembly.module.TypeManager.StructType ;
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 ;
2020-02-09 18:05:31 +01:00
import de.inetsoftware.jwebassembly.wasm.ArrayType ;
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 ;
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 {
2022-03-08 15:13:19 +01:00
/** Java method name of of constructor */
static final String CONSTRUCTOR = " <init> " ;
/** Java method name of static constructor or initialization method */
static final String CLASS_INIT = " <clinit> " ;
2022-02-27 20:44:42 +01:00
private final LocaleVariableManager localVariables ;
2018-11-09 20:14:30 +01:00
2022-02-27 20:44:42 +01:00
private final List < WasmInstruction > instructions ;
2018-11-09 20:14:30 +01:00
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 ;
2022-02-27 20:44:42 +01:00
/ * *
* Create a new instance of CodeBuilder
* /
protected WasmCodeBuilder ( ) {
localVariables = new LocaleVariableManager ( ) ;
instructions = new ArrayList < > ( ) ;
}
/ * *
* Create a new instance with shared resources
*
* @param codeBuilder
* other instance of CodeBuilder
* /
WasmCodeBuilder ( @Nonnull WasmCodeBuilder codeBuilder ) {
localVariables = codeBuilder . localVariables ;
instructions = codeBuilder . instructions ;
}
2019-10-02 18:56:35 +02:00
/ * *
* Initialize the code builder ;
*
* @param options
* compiler properties
2020-02-24 21:08:29 +01:00
* @param classFileLoader
* for loading the class files
2019-10-02 18:56:35 +02:00
* /
2020-02-24 21:08:29 +01:00
void init ( WasmOptions options , ClassFileLoader classFileLoader ) {
this . localVariables . init ( options . types ) ;
this . types = options . types ;
this . functions = options . functions ;
this . strings = options . 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
* /
2020-04-13 16:05:41 +02:00
@Nonnull
2018-11-09 20:14:30 +01:00
List < WasmInstruction > getInstructions ( ) {
return instructions ;
}
2018-11-04 20:28:42 +01:00
2020-04-13 16:05:41 +02:00
/ * *
* Get the manager of local variables
* @return the manager
* /
@Nonnull
LocaleVariableManager getLocalVariables ( ) {
return localVariables ;
}
2020-04-19 19:29:14 +02:00
/ * *
* Get the compiler settings
*
* @return the settings
* /
@Nonnull
WasmOptions getOptions ( ) {
return options ;
}
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
/ * *
2022-05-22 19:10:34 +02:00
* We need a value ( or several ) from the stack inside a block . We need to find the WasmInstruction where the block
* can can begin . If it is a function call or a numeric expression , it can be complicated 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 .
2022-05-22 19:10:34 +02:00
* @param instructions
* the instruction list for searching
* @param idx
* the start index for the search . Between 0 and instructions . size ( ) .
* @return the code position that push the last instruction
* /
2022-06-05 23:04:12 +02:00
static int findBlockStart ( int count , List < WasmInstruction > instructions , int idx ) {
2019-10-02 18:56:35 +02:00
int valueCount = 0 ;
2022-05-22 19:10:34 +02:00
for ( int i = idx - 1 ; i > = 0 ; i - - ) {
2019-10-02 18:56:35 +02:00
WasmInstruction instr = instructions . get ( i ) ;
AnyType valueType = instr . getPushValueType ( ) ;
if ( valueType ! = null ) {
valueCount + + ;
}
2022-06-05 23:04:12 +02:00
int popCount = instr . getPopCount ( ) ;
valueCount - = popCount ;
if ( valueCount = = count & & popCount = = 0 ) {
2022-05-26 21:50:45 +02:00
int codePos = instr . getCodePosition ( ) ;
if ( i = = 0 | | instructions . get ( i - 1 ) . getCodePosition ( ) < codePos ) {
// if the same codePos is used from multiple instructions then it is not an atomic operation in Java
2022-06-05 23:04:12 +02:00
return codePos ;
2022-05-26 21:50:45 +02:00
}
2019-10-02 18:56:35 +02:00
}
}
2022-05-22 19:10:34 +02:00
throw new WasmException ( " Block start position not found " , - 1 ) ; // should never occur
2019-10-02 18:56:35 +02:00
}
/ * *
* 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 .
2020-03-29 14:31:58 +02:00
* @param javaCodePos
* current code position for which the stack is inspected
2019-10-02 18:56:35 +02:00
* @return the type of the last push value
* /
@Nonnull
2020-03-29 14:31:58 +02:00
AnyType findValueTypeFromStack ( int count , int javaCodePos ) {
return StackInspector . findInstructionThatPushValue ( instructions , count , javaCodePos ) . instr . getPushValueType ( ) ;
2020-03-01 19:02:49 +01:00
}
2021-05-02 14:19:55 +02:00
/ * *
* Find the array component type from stack .
*
* @param count
* the count of values on the stack back . 1 means the last value . 2 means the penultimate value .
* @param javaCodePos
* current code position for which the stack is inspected
* @return
* /
@Nonnull
AnyType findArrayTypeFromStack ( int count , int javaCodePos ) {
StackValue stackValue = StackInspector . findInstructionThatPushValue ( instructions , count , javaCodePos ) ;
AnyType type = stackValue . instr . getPushValueType ( ) ;
if ( type instanceof ArrayType ) {
return ( ( ArrayType ) type ) . getArrayType ( ) ;
}
if ( stackValue . instr instanceof WasmLoadStoreInstruction ) {
int slot = ( ( WasmLoadStoreInstruction ) stackValue . instr ) . getSlot ( ) ;
ArrayType arrayType = types . arrayType ( types . valueOf ( " java/lang/Object " ) ) ;
localVariables . use ( arrayType , slot , javaCodePos ) ;
return arrayType . getArrayType ( ) ;
}
return ValueType . eqref ;
}
2020-03-01 19:02:49 +01:00
/ * *
* Find the instruction that push the x - th value to the stack .
*
* @param count
* the count of values on the stack back . 1 means the last value . 2 means the penultimate value .
2020-03-29 14:31:58 +02:00
* @param javaCodePos
* current code position for which the stack is inspected
2020-03-01 19:02:49 +01:00
* @return the instruction
* /
2021-05-23 22:12:29 +02:00
@Nonnull
2020-03-29 14:31:58 +02:00
private WasmInstruction findInstructionThatPushValue ( int count , int javaCodePos ) {
return StackInspector . findInstructionThatPushValue ( instructions , count , javaCodePos ) . instr ;
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
2020-03-27 21:10:02 +01:00
* the method with signature as fallback for a missing variable table . If null signature is used and the method must be static .
* @param signature
* alternative for method signature , can be null if method is set
2018-11-09 20:14:30 +01:00
* /
2020-03-27 21:10:02 +01:00
protected void reset ( LocalVariableTable variableTable , MethodInfo method , Iterator < AnyType > signature ) {
2018-11-09 20:14:30 +01:00
instructions . clear ( ) ;
2020-03-27 21:10:02 +01:00
localVariables . reset ( variableTable , method , signature ) ;
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 ) ;
2020-03-29 21:24:09 +02:00
instructions . add ( new WasmLoadStoreInstruction ( load ? VariableOperator . get : VariableOperator . set , 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 :
2020-03-29 14:31:58 +02:00
AnyType valueType = findValueTypeFromStack ( 1 , javaCodePos ) ;
2019-11-12 20:47:57 +01:00
localVariables . useIndex ( valueType , wasmIdx ) ;
}
2020-03-01 19:02:49 +01:00
instructions . add ( new WasmLocalInstruction ( op , wasmIdx , localVariables , javaCodePos , lineNumber ) ) ;
2018-11-09 20:14:30 +01:00
}
2019-11-16 19:17:22 +01:00
/ * *
2021-05-23 22:12:29 +02:00
* Get a possible slot from the instruction
2019-11-16 19:17:22 +01:00
*
2021-05-23 22:12:29 +02:00
* @param instr
* the instruction
* @return the slot or - 1 if there no slot
2019-11-16 19:17:22 +01:00
* /
2021-05-23 22:12:29 +02:00
private static int getPossibleSlot ( @Nonnull WasmInstruction instr ) {
2020-03-01 19:02:49 +01:00
// if it is a GET to a local variable then we can use it
if ( instr . getType ( ) = = Type . Local ) {
WasmLocalInstruction local1 = ( WasmLocalInstruction ) instr ;
2021-03-27 18:27:00 +01:00
switch ( local1 . getOperator ( ) ) {
case get :
case tee :
2021-05-23 22:12:29 +02:00
return local1 . getSlot ( ) ;
2021-03-27 18:27:00 +01:00
default :
2020-03-01 19:02:49 +01:00
}
}
2021-05-23 22:12:29 +02:00
return - 1 ;
}
/ * *
* Create a WasmDupInstruction .
*
* @param dup2
* call from dup2 instruction
* @param javaCodePos
* the code position / offset in the Java method
* @param lineNumber
* the line number in the Java source code
* /
protected void addDupInstruction ( boolean dup2 , int javaCodePos , int lineNumber ) {
WasmInstruction instr = findInstructionThatPushValue ( 1 , javaCodePos ) ;
AnyType type = instr . getPushValueType ( ) ;
int slot = getPossibleSlot ( instr ) ;
// occur with:
// int[] data = new int[x];
// data[i] |= any;
instr = dup2 & & type ! = ValueType . i64 & & type ! = ValueType . f64 ? //
findInstructionThatPushValue ( 2 , javaCodePos ) : null ;
2021-06-06 21:26:24 +02:00
int slot2 ;
if ( instr ! = null ) {
slot2 = getPossibleSlot ( instr ) ;
if ( slot2 < 0 ) {
slot2 = getTempVariable ( instr . getPushValueType ( ) , javaCodePos , javaCodePos + 1 ) ;
if ( slot < 0 ) {
slot = getTempVariable ( type , javaCodePos , javaCodePos + 1 ) ;
instructions . add ( new WasmLoadStoreInstruction ( VariableOperator . set , slot , localVariables , javaCodePos , lineNumber ) ) ;
} else {
instructions . add ( new WasmBlockInstruction ( WasmBlockOperator . DROP , null , javaCodePos , lineNumber ) ) ;
}
instructions . add ( new WasmLoadStoreInstruction ( VariableOperator . tee , slot2 , localVariables , javaCodePos , lineNumber ) ) ;
instructions . add ( new WasmLoadStoreInstruction ( VariableOperator . get , slot , localVariables , javaCodePos , lineNumber ) ) ;
}
} else {
slot2 = - 1 ; // for compiler only
}
2020-03-01 19:02:49 +01:00
//alternate we need to create a new locale variable
2021-03-27 18:27:00 +01:00
if ( slot < 0 ) {
slot = getTempVariable ( type , javaCodePos , javaCodePos + 1 ) ;
instructions . add ( new WasmLoadStoreInstruction ( VariableOperator . tee , slot , localVariables , javaCodePos , lineNumber ) ) ;
2020-03-01 19:02:49 +01:00
} else {
2021-03-27 18:27:00 +01:00
localVariables . expandUse ( slot , javaCodePos ) ;
2020-03-01 19:02:49 +01:00
}
2021-06-06 21:26:24 +02:00
if ( instr ! = null ) {
instructions . add ( new WasmLoadStoreInstruction ( VariableOperator . get , slot2 , localVariables , javaCodePos , lineNumber ) ) ;
}
instructions . add ( new WasmLoadStoreInstruction ( VariableOperator . get , slot , localVariables , javaCodePos , lineNumber ) ) ;
2019-11-16 19:17:22 +01:00
}
2020-04-25 19:31:30 +02:00
/ * *
* Simulate the dup_x1 Java byte code instruction . < p >
*
* . . . , value2 , value1 → . . . , value1 , value2 , value1
*
* @param javaCodePos
* the code position / offset in the Java method
* @param lineNumber
* the line number in the Java source code
* /
protected void addDupX1Instruction ( int javaCodePos , int lineNumber ) {
AnyType type1 = findValueTypeFromStack ( 1 , javaCodePos ) ;
AnyType type2 = findValueTypeFromStack ( 2 , javaCodePos ) ;
2022-01-09 20:48:28 +01:00
int varSlot1 = getTempVariable ( type1 , javaCodePos , javaCodePos + 1 ) ;
int varSlot2 = getTempVariable ( type2 , javaCodePos , javaCodePos + 1 ) ;
2020-04-25 19:31:30 +02:00
// save in temp variables
2022-01-09 20:48:28 +01:00
instructions . add ( new WasmLoadStoreInstruction ( VariableOperator . set , varSlot1 , localVariables , javaCodePos , lineNumber ) ) ;
instructions . add ( new WasmLoadStoreInstruction ( VariableOperator . set , varSlot2 , localVariables , javaCodePos , lineNumber ) ) ;
2020-04-25 19:31:30 +02:00
// and restore it in new order on the stack
2022-01-09 20:48:28 +01:00
instructions . add ( new WasmLoadStoreInstruction ( VariableOperator . get , varSlot1 , localVariables , javaCodePos , lineNumber ) ) ;
instructions . add ( new WasmLoadStoreInstruction ( VariableOperator . get , varSlot2 , localVariables , javaCodePos , lineNumber ) ) ;
instructions . add ( new WasmLoadStoreInstruction ( VariableOperator . get , varSlot1 , localVariables , javaCodePos , lineNumber ) ) ;
2020-04-25 22:22:18 +02:00
}
/ * *
* Simulate the dup_x2 Java byte code instruction . < p >
*
* . . . , value3 , value2 , value1 → . . . , value1 , value3 , value2 , value1
*
* @param javaCodePos
* the code position / offset in the Java method
* @param lineNumber
* the line number in the Java source code
* /
protected void addDupX2Instruction ( int javaCodePos , int lineNumber ) {
AnyType type1 = findValueTypeFromStack ( 1 , javaCodePos ) ;
AnyType type2 = findValueTypeFromStack ( 2 , javaCodePos ) ;
AnyType type3 = findValueTypeFromStack ( 3 , javaCodePos ) ;
2022-01-09 20:48:28 +01:00
int varSlot1 = getTempVariable ( type1 , javaCodePos , javaCodePos + 1 ) ;
int varSlot2 = getTempVariable ( type2 , javaCodePos , javaCodePos + 1 ) ;
int varSlot3 = getTempVariable ( type3 , javaCodePos , javaCodePos + 1 ) ;
2020-04-25 22:22:18 +02:00
// save in temp variables
2022-01-09 20:48:28 +01:00
instructions . add ( new WasmLoadStoreInstruction ( VariableOperator . set , varSlot1 , localVariables , javaCodePos , lineNumber ) ) ;
instructions . add ( new WasmLoadStoreInstruction ( VariableOperator . set , varSlot2 , localVariables , javaCodePos , lineNumber ) ) ;
instructions . add ( new WasmLoadStoreInstruction ( VariableOperator . set , varSlot3 , localVariables , javaCodePos , lineNumber ) ) ;
2020-04-25 22:22:18 +02:00
// and restore it in new order on the stack
2022-01-09 20:48:28 +01:00
instructions . add ( new WasmLoadStoreInstruction ( VariableOperator . get , varSlot1 , localVariables , javaCodePos , lineNumber ) ) ;
instructions . add ( new WasmLoadStoreInstruction ( VariableOperator . get , varSlot3 , localVariables , javaCodePos , lineNumber ) ) ;
instructions . add ( new WasmLoadStoreInstruction ( VariableOperator . get , varSlot2 , localVariables , javaCodePos , lineNumber ) ) ;
instructions . add ( new WasmLoadStoreInstruction ( VariableOperator . get , varSlot1 , localVariables , javaCodePos , lineNumber ) ) ;
2020-04-25 19:31:30 +02:00
}
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 ( ) ;
2022-03-08 15:13:19 +01:00
FunctionName clinit ;
if ( load ) {
clinit = new FunctionName ( name . className , CLASS_INIT , " ()V " ) ;
if ( ! functions . isUsed ( clinit ) ) {
clinit = null ;
}
} else {
clinit = null ;
}
addGlobalInstruction ( load , name , type , clinit , javaCodePos , lineNumber ) ;
2022-03-06 14:27:33 +01:00
}
/ * *
* Add a global instruction
*
* @param load
* true : if load
* @param name
* reference to a static field
* @param type
* the type of the static field
2022-03-13 17:54:56 +01:00
* @param clinit
* a reference to the class / static constructor which should executed before access a static field
2022-03-06 14:27:33 +01:00
* @param javaCodePos
* the code position / offset in the Java method
* @param lineNumber
* the line number in the Java source code
* /
2022-03-08 15:13:19 +01:00
protected void addGlobalInstruction ( boolean load , FunctionName name , AnyType type , FunctionName clinit , int javaCodePos , int lineNumber ) {
instructions . add ( new WasmGlobalInstruction ( load , name , type , clinit , javaCodePos , lineNumber ) ) ;
2020-04-05 21:03:13 +02:00
functions . markClassAsUsed ( name . className ) ;
2018-11-09 20:14:30 +01:00
}
2022-04-16 17:31:48 +02:00
/ * *
* Add a global field access instruction
*
* @param load
* true : if load ( get )
* @param fieldName
* the fieldName like java / lang / System . err
* @param javaCodePos
* the code position / offset in the Java method
* @param lineNumber
* the line number in the Java source code
* /
protected void addGlobalInstruction ( boolean load , String fieldName , int javaCodePos , int lineNumber ) {
try {
if ( fieldName . startsWith ( " $ " ) ) {
fieldName = fieldName . substring ( 1 ) ;
}
FunctionName name = new FunctionName ( fieldName + " ()V " ) ;
ClassFile classFile = classFileLoader . get ( name . className ) ;
FieldInfo field = classFile . getField ( name . methodName ) ;
AnyType type = new ValueTypeParser ( field . getType ( ) , types ) . next ( ) ;
addGlobalInstruction ( load , name , type , null , javaCodePos , lineNumber ) ;
2022-06-06 15:37:12 +02:00
} catch ( Throwable ex ) {
2022-04-16 17:31:48 +02:00
throw WasmException . create ( ex , lineNumber ) ;
}
}
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
* /
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 ) ;
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 ) ) ;
2020-04-26 19:47:51 +02:00
String comment = ( String ) value ;
if ( ! isAscii ( comment ) ) {
comment = null ;
}
instructions . add ( new WasmCallInstruction ( name , javaCodePos , lineNumber , types , false , comment ) ) ;
2020-02-23 17:51:32 +01:00
} else if ( value instanceof Number ) {
2019-11-03 13:52:07 +01:00
instructions . add ( new WasmConstInstruction ( ( Number ) value , javaCodePos , lineNumber ) ) ;
2020-03-15 15:49:52 +01:00
} else if ( value instanceof ConstantClass ) {
String className = ( ( ConstantClass ) value ) . getName ( ) ;
Integer id = types . valueOf ( className ) . getClassIndex ( ) ;
FunctionName name = types . getClassConstantFunction ( ) ;
instructions . add ( new WasmConstInstruction ( id , ValueType . i32 , javaCodePos , lineNumber ) ) ;
2021-04-17 20:27:28 +02:00
addCallInstruction ( name , false , javaCodePos , lineNumber ) ;
2020-02-23 17:51:32 +01:00
} else {
//TODO There can be ConstantClass, MethodType and MethodHandle
throw new WasmException ( " Class constants are not supported. : " + value , lineNumber ) ;
2019-11-03 13:52:07 +01:00
}
2018-11-09 20:14:30 +01:00
}
2020-04-26 19:47:51 +02:00
/ * *
* if the string contains only ASCCI characters
*
* @param str
* the staring
* @return true , if only ASCII
* /
private static boolean isAscii ( String str ) {
int length = str . length ( ) ;
for ( int i = 0 ; i < length ; i + + ) {
int c = str . charAt ( i ) ;
if ( c > = 0x20 & & c < 0x7F ) {
continue ;
}
return false ;
}
return true ;
}
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 ) ;
2020-02-23 20:18:57 +01:00
if ( ! options . useGC ( ) & & options . ref_eq = = null & & ( numOp = = NumericOperator . ref_eq | | numOp = = NumericOperator . ref_ne ) ) {
2021-04-17 20:27:28 +02:00
functions . markAsNeeded ( options . ref_eq = getNonGC ( " ref_eq " , lineNumber ) , false ) ;
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
2021-07-10 22:30:53 +02:00
* @param needThisParameter true , if the hidden THIS parameter is needed , If it is an instance method call .
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
* /
2021-04-17 20:27:28 +02:00
protected void addCallInstruction ( FunctionName name , boolean needThisParameter , int javaCodePos , int lineNumber ) {
name = functions . markAsNeeded ( name , needThisParameter ) ;
2020-01-11 21:48:04 +01:00
WasmCallInstruction instruction = new WasmCallInstruction ( name , javaCodePos , lineNumber , types , needThisParameter ) ;
2019-10-27 20:11:47 +01:00
2022-03-08 15:13:19 +01:00
if ( CONSTRUCTOR . 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 ) ;
2022-03-08 15:13:19 +01:00
if ( replace ! = null & & ! CONSTRUCTOR . equals ( replace . getName ( ) ) ) {
2019-11-17 17:28:31 +01:00
// 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 ) ;
2020-03-29 21:24:09 +02:00
// 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
2020-01-11 21:48:04 +01:00
instruction = new WasmCallInstruction ( factoryName , javaCodePos , lineNumber , types , false ) ;
2019-10-27 20:11:47 +01:00
}
}
instructions . add ( instruction ) ;
2020-04-05 21:03:13 +02:00
functions . markClassAsUsed ( name . className ) ;
2018-11-09 20:14:30 +01:00
}
2019-05-14 21:47:49 +02:00
/ * *
2020-02-24 18:16:36 +01:00
* Add indirect call to the instruction .
2019-05-14 21:47:49 +02:00
*
2020-02-24 18:16:36 +01:00
* @param indirectCall
* the instruction
2019-05-14 21:47:49 +02:00
* /
2020-02-24 18:16:36 +01:00
private void addCallIndirectInstruction ( WasmCallIndirectInstruction indirectCall ) {
// For access to the vtable the THIS parameter must be duplicated on stack before the function parameters
2020-03-29 18:35:01 +02:00
// find the instruction that THIS push on the stack
2020-02-24 18:16:36 +01:00
int count = indirectCall . getPopCount ( ) ;
2020-03-29 18:35:01 +02:00
int javaCodePos = indirectCall . getCodePosition ( ) ;
StackValue stackValue = StackInspector . findInstructionThatPushValue ( instructions , count , javaCodePos ) ;
WasmInstruction instr = stackValue . instr ;
2022-02-13 22:38:14 +01:00
int varSlot = - 1 ;
2020-02-24 18:16:36 +01:00
// if it is a GET to a local variable then we can use it
2019-10-05 16:15:18 +02:00
if ( instr . getType ( ) = = Type . Local ) {
WasmLocalInstruction local1 = ( WasmLocalInstruction ) instr ;
if ( local1 . getOperator ( ) = = VariableOperator . get ) {
2022-02-13 22:38:14 +01:00
varSlot = local1 . getSlot ( ) ;
2019-10-05 16:15:18 +02:00
}
}
2020-02-24 18:16:36 +01:00
//alternate we need to create a new locale variable
2022-02-13 22:38:14 +01:00
if ( varSlot < 0 ) {
varSlot = getTempVariable ( indirectCall . getThisType ( ) , instr . getCodePosition ( ) , javaCodePos + 1 ) ;
2020-03-29 18:35:01 +02:00
int idx = count = = 1 ? instructions . size ( ) : stackValue . idx + 1 ;
2022-02-13 22:38:14 +01:00
instructions . add ( idx , new DupThis ( indirectCall , varSlot , localVariables , instr . getCodePosition ( ) + 1 ) ) ;
2019-10-05 16:15:18 +02:00
}
2022-02-13 22:38:14 +01:00
indirectCall . setVariableSlotOfThis ( varSlot , localVariables ) ;
2020-02-24 18:16:36 +01:00
instructions . add ( indirectCall ) ;
2020-02-26 18:02:59 +01:00
options . registerGet_i32 ( ) ; // for later access of the vtable
2019-05-14 21:47:49 +02:00
}
2020-02-24 18:16:36 +01: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 ) {
2021-04-17 20:27:28 +02:00
name = functions . markAsNeeded ( name , true ) ;
2020-02-24 18:16:36 +01:00
addCallIndirectInstruction ( new WasmCallVirtualInstruction ( name , javaCodePos , lineNumber , types , options ) ) ;
2020-02-25 18:05:12 +01:00
options . getCallVirtual ( ) ; // mark the function as needed
2020-04-05 21:03:13 +02:00
functions . markClassAsUsed ( name . className ) ;
2020-02-24 18:16:36 +01:00
}
2020-01-25 23:42:22 +01:00
/ * *
* Add interface 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 addCallInterfaceInstruction ( FunctionName name , int javaCodePos , int lineNumber ) {
2021-04-17 20:27:28 +02:00
name = functions . markAsNeeded ( name , true ) ;
2020-02-24 18:16:36 +01:00
addCallIndirectInstruction ( new WasmCallInterfaceInstruction ( name , javaCodePos , lineNumber , types , options ) ) ;
2020-05-08 15:01:01 +02:00
options . getCallInterface ( ) ; // mark the function as needed
2020-04-05 21:03:13 +02:00
functions . markClassAsUsed ( name . className ) ;
2020-01-25 23:42:22 +01: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
2020-03-26 18:21:50 +01:00
/ * *
* Add a Jump instruction for later stack inspection
*
* @param jumpPos
* the position of the jump
* @param popCount
* the the count of values that are removed from the stack .
2020-04-12 10:44:53 +02:00
* @param pushValueType
* optional type of a push value
2020-03-26 18:21:50 +01:00
* @param javaCodePos
* the code position / offset in the Java method
* @param lineNumber
* the line number in the Java source code
* /
2020-04-12 10:44:53 +02:00
protected void addJumpPlaceholder ( int jumpPos , int popCount , AnyType pushValueType , int javaCodePos , int lineNumber ) {
instructions . add ( new JumpInstruction ( jumpPos , popCount , pushValueType , javaCodePos , lineNumber ) ) ;
2020-03-26 18:21:50 +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 ) ;
}
}
2022-06-06 15:37:12 +02:00
} catch ( Throwable ex ) {
2019-09-08 21:45:28 +02:00
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
2020-09-23 19:45:00 +02:00
* the array / component type of the array
2018-12-02 19:54:59 +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-02 19:54:59 +01:00
* /
2021-01-03 19:20:44 +01:00
protected void addArrayInstruction ( @Nonnull ArrayOperator op , @Nonnull AnyType type , int javaCodePos , int lineNumber ) {
2021-01-02 20:48:29 +01:00
boolean useGC = options . useGC ( ) ;
if ( useGC ) {
// replace the the array wrapper on the stack with the native array
int idx ;
2022-05-26 21:50:45 +02:00
int javaPos = javaCodePos ;
2021-01-02 20:48:29 +01:00
switch ( op ) {
case GET :
2021-01-02 21:43:02 +01:00
case GET_S :
case GET_U :
2022-05-26 21:50:45 +02:00
StackValue stackValue = StackInspector . findInstructionThatPushValue ( instructions , 1 , javaCodePos ) ;
idx = stackValue . idx ;
javaPos = stackValue . instr . getCodePosition ( ) ;
2021-01-02 20:48:29 +01:00
break ;
case SET :
2022-05-26 21:50:45 +02:00
stackValue = StackInspector . findInstructionThatPushValue ( instructions , 2 , javaCodePos ) ;
idx = stackValue . idx ;
javaPos = stackValue . instr . getCodePosition ( ) ;
2021-01-02 20:48:29 +01:00
break ;
case LEN :
idx = instructions . size ( ) ;
break ;
default :
idx = - 1 ;
}
if ( idx > = 0 ) {
ArrayType arrayType = types . arrayType ( type ) ;
2022-05-26 21:50:45 +02:00
instructions . add ( idx , new WasmStructInstruction ( StructOperator . GET , arrayType , arrayType . getNativeFieldName ( ) , javaPos , lineNumber , types ) ) ;
2021-01-02 20:48:29 +01:00
}
}
2020-07-05 14:08:46 +02:00
WasmArrayInstruction arrayInst = new WasmArrayInstruction ( op , type , types , javaCodePos , lineNumber ) ;
instructions . add ( arrayInst ) ;
2021-01-02 20:48:29 +01:00
SyntheticFunctionName name = arrayInst . createNonGcFunction ( useGC ) ;
2021-01-02 16:44:38 +01:00
if ( name ! = null ) {
2021-04-17 20:27:28 +02:00
functions . markAsNeeded ( name , ! name . istStatic ( ) ) ;
2021-01-02 16:44:38 +01:00
functions . markAsImport ( name , name . getAnnotation ( ) ) ;
2020-02-09 18:05:31 +01:00
}
}
/ * *
* Add a new multi dimensional array instruction
*
* @param dim
2020-02-27 11:25:41 +01:00
* the dimension of the array & gt ; = 2
2020-02-09 18:05:31 +01:00
* @param typeName
* the full type name
* @param javaCodePos
* the code position / offset in the Java method
* @param lineNumber
* the line number in the Java source code
* /
protected void addMultiNewArrayInstruction ( int dim , String typeName , int javaCodePos , int lineNumber ) {
ArrayType type = ( ArrayType ) new ValueTypeParser ( typeName , types ) . next ( ) ;
2020-07-05 14:08:46 +02:00
addMultiNewArrayInstruction ( dim , type , javaCodePos , lineNumber ) ;
}
/ * *
* Add a new multi dimensional array instruction
*
* @param dim
* the dimension of the array & gt ; = 2
* @param type
* the full type
* @param javaCodePos
* the code position / offset in the Java method
* @param lineNumber
* the line number in the Java source code
* /
protected void addMultiNewArrayInstruction ( int dim , ArrayType type , int javaCodePos , int lineNumber ) {
MultiArrayFunctionName name = new MultiArrayFunctionName ( dim , type ) ;
2021-04-17 20:27:28 +02:00
addCallInstruction ( name , false , javaCodePos , lineNumber ) ;
2018-12-02 19:54:59 +01:00
}
2018-12-05 22:14:26 +01:00
/ * *
2020-02-25 18:05:12 +01:00
* Add a struct / object operation to the instruction list .
2018-12-05 22:14:26 +01:00
*
* @param op
* the operation
2019-01-06 16:29:26 +01:00
* @param typeName
2020-09-24 20:56:54 +02:00
* the type name like " java/lang/Object "
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 ) ;
2021-01-16 17:38:11 +01:00
switch ( op ) {
case CAST :
case INSTANCEOF :
structInst . createNonGcFunction ( ) ;
break ;
case NEW_DEFAULT :
if ( options . useGC ( ) ) {
2021-05-23 22:12:29 +02:00
addDupInstruction ( false , javaCodePos , lineNumber ) ;
2021-01-16 17:38:11 +01:00
addConstInstruction ( structInst . getStructType ( ) . getVTable ( ) , javaCodePos , lineNumber ) ;
instructions . add ( new WasmStructInstruction ( StructOperator . SET , typeName , new NamedStorageType ( ValueType . i32 , " " , TypeManager . FIELD_VTABLE ) , javaCodePos , lineNumber , types ) ) ;
break ;
}
//$FALL-THROUGH$
default :
if ( ! options . useGC ( ) ) {
SyntheticFunctionName name = structInst . createNonGcFunction ( ) ;
if ( name ! = null ) {
2021-04-17 20:27:28 +02:00
functions . markAsNeeded ( name , ! name . istStatic ( ) ) ;
2021-01-16 17:38:11 +01:00
functions . markAsImport ( name , name . getAnnotation ( ) ) ;
}
}
2019-09-08 13:55:22 +02:00
}
2018-12-05 22:14:26 +01:00
}
2019-11-18 21:32:35 +01:00
2021-01-23 22:16:16 +01:00
/ * *
2021-03-28 10:56:51 +02:00
* Add invoke dynamic operation . ( Creating of a lambda expression )
2021-01-23 22:16:16 +01:00
*
* @param method
* the BootstrapMethod , described the method that should be executed
* @param factorySignature
* Get the signature of the factory method . For example " ()Ljava.lang.Runnable; " for the lamba expression
* < code > Runnable run = ( ) - & gt ; foo ( ) ; < / code >
* @param interfaceMethodName
* The simple name of the generated method of the single function interface .
* @param javaCodePos
* the code position / offset in the Java method
* @param lineNumber
* the line number in the Java source code
* /
protected void addInvokeDynamic ( BootstrapMethod method , String factorySignature , String interfaceMethodName , int javaCodePos , int lineNumber ) {
2021-03-28 10:56:51 +02:00
// Create the synthetic lambda class that hold the lambda expression.
2021-01-23 22:16:16 +01:00
ValueTypeParser parser = new ValueTypeParser ( factorySignature , types ) ;
2021-02-28 22:20:49 +01:00
ArrayList < AnyType > params = new ArrayList < > ( ) ;
do {
AnyType param = parser . next ( ) ;
if ( param = = null ) {
break ;
}
params . add ( param ) ;
} while ( true ) ;
2021-01-23 22:16:16 +01:00
StructType interfaceType = ( StructType ) parser . next ( ) ;
2021-04-03 22:06:39 +02:00
LambdaType type = types . lambdaType ( method , params , interfaceType , interfaceMethodName ) ;
2021-04-17 20:27:28 +02:00
functions . markAsNeeded ( type . getLambdaMethod ( ) , true ) ;
2021-04-03 22:06:39 +02:00
String lambdaTypeName = type . getName ( ) ;
2021-02-28 22:20:49 +01:00
2021-03-28 10:56:51 +02:00
// Create the instance of the synthetic lambda class and save the parameters in fields
ArrayList < NamedStorageType > paramFields = type . getParamFields ( ) ;
int paramCount = paramFields . size ( ) ;
if ( paramCount = = 0 ) {
addStructInstruction ( StructOperator . NEW_DEFAULT , lambdaTypeName , null , javaCodePos , lineNumber ) ;
} else {
// Lambda with parameters from the stack
int idx = StackInspector . findInstructionThatPushValue ( instructions , paramCount , javaCodePos ) . idx ;
int pos = instructions . size ( ) ;
addStructInstruction ( StructOperator . NEW_DEFAULT , lambdaTypeName , null , javaCodePos , lineNumber ) ;
2021-04-03 22:06:39 +02:00
if ( ! options . useGC ( ) ) {
2021-05-23 22:12:29 +02:00
addDupInstruction ( false , javaCodePos , lineNumber ) ;
2021-04-03 22:06:39 +02:00
}
int slot = ( ( WasmLocalInstruction ) findInstructionThatPushValue ( 1 , javaCodePos ) ) . getSlot ( ) ;
2021-03-28 10:56:51 +02:00
// move the creating of the lambda instance before the parameters on the stack
Collections . rotate ( instructions . subList ( idx , instructions . size ( ) ) , idx - pos ) ;
for ( int i = 0 ; i < paramCount ; i + + ) {
NamedStorageType field = paramFields . get ( i ) ;
idx = StackInspector . findInstructionThatPushValue ( instructions , paramCount - i , javaCodePos ) . idx ;
instructions . add ( idx , new WasmLoadStoreInstruction ( VariableOperator . get , slot , localVariables , javaCodePos , lineNumber ) ) ;
2021-04-03 22:06:39 +02:00
pos = instructions . size ( ) ;
idx = paramCount - i - 1 ;
idx = idx = = 0 ? pos : StackInspector . findInstructionThatPushValue ( instructions , idx , javaCodePos ) . idx ;
addStructInstruction ( StructOperator . SET , lambdaTypeName , field , javaCodePos , lineNumber ) ;
if ( idx < pos ) {
Collections . rotate ( instructions . subList ( idx , instructions . size ( ) ) , idx - pos ) ;
}
2021-03-28 10:56:51 +02:00
}
2021-02-28 22:20:49 +01:00
}
2021-01-23 22:16:16 +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
}