mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
wasm gc: fix generation issues, get first version that produces module that passes validation
This commit is contained in:
parent
a8d97ad387
commit
54dc7fe5f8
|
@ -57,6 +57,7 @@ public class WasmGCModuleGenerator {
|
||||||
var mainFunction = declarationsGenerator.functions().forStaticMethod(new MethodReference(entryPoint,
|
var mainFunction = declarationsGenerator.functions().forStaticMethod(new MethodReference(entryPoint,
|
||||||
"main", ValueType.parse(String[].class), ValueType.VOID));
|
"main", ValueType.parse(String[].class), ValueType.VOID));
|
||||||
var mainFunctionCaller = new WasmFunction(declarationsGenerator.functionTypes.of(null));
|
var mainFunctionCaller = new WasmFunction(declarationsGenerator.functionTypes.of(null));
|
||||||
|
declarationsGenerator.module.functions.add(mainFunctionCaller);
|
||||||
mainFunctionCaller.getBody().add(callInitializer());
|
mainFunctionCaller.getBody().add(callInitializer());
|
||||||
|
|
||||||
var tempVars = new TemporaryVariablePool(mainFunctionCaller);
|
var tempVars = new TemporaryVariablePool(mainFunctionCaller);
|
||||||
|
@ -80,6 +81,7 @@ public class WasmGCModuleGenerator {
|
||||||
}
|
}
|
||||||
var functionType = declarationsGenerator.functionTypes.of(null);
|
var functionType = declarationsGenerator.functionTypes.of(null);
|
||||||
initializer = new WasmFunction(functionType);
|
initializer = new WasmFunction(functionType);
|
||||||
|
initializer.setReferenced(true);
|
||||||
declarationsGenerator.module.functions.add(initializer);
|
declarationsGenerator.module.functions.add(initializer);
|
||||||
initializerRef = new WasmGlobal("teavm_initializer", functionType.getReference(),
|
initializerRef = new WasmGlobal("teavm_initializer", functionType.getReference(),
|
||||||
new WasmFunctionReference(initializer));
|
new WasmFunctionReference(initializer));
|
||||||
|
|
|
@ -123,10 +123,25 @@ public class WasmGCTarget implements TeaVMTarget {
|
||||||
mainFunction.setExportName(controller.getEntryPointName());
|
mainFunction.setExportName(controller.getEntryPointName());
|
||||||
mainFunction.setName(controller.getEntryPointName());
|
mainFunction.setName(controller.getEntryPointName());
|
||||||
moduleGenerator.generate();
|
moduleGenerator.generate();
|
||||||
|
adjustModuleMemory(module);
|
||||||
|
|
||||||
emitWasmFile(module, buildTarget, outputName);
|
emitWasmFile(module, buildTarget, outputName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void adjustModuleMemory(WasmModule module) {
|
||||||
|
var memorySize = 0;
|
||||||
|
for (var segment : module.getSegments()) {
|
||||||
|
memorySize = Math.max(memorySize, segment.getOffset() + segment.getLength());
|
||||||
|
}
|
||||||
|
if (memorySize == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pages = (memorySize - 1) / WasmHeap.PAGE_SIZE + 1;
|
||||||
|
module.setMinMemorySize(pages);
|
||||||
|
module.setMaxMemorySize(pages);
|
||||||
|
}
|
||||||
|
|
||||||
private void emitWasmFile(WasmModule module, BuildTarget buildTarget, String outputName) throws IOException {
|
private void emitWasmFile(WasmModule module, BuildTarget buildTarget, String outputName) throws IOException {
|
||||||
var binaryWriter = new WasmBinaryWriter();
|
var binaryWriter = new WasmBinaryWriter();
|
||||||
var binaryRenderer = new WasmBinaryRenderer(binaryWriter, WasmBinaryVersion.V_0x1, obfuscated,
|
var binaryRenderer = new WasmBinaryRenderer(binaryWriter, WasmBinaryVersion.V_0x1, obfuscated,
|
||||||
|
|
|
@ -22,8 +22,9 @@ import org.teavm.model.ValueType;
|
||||||
import org.teavm.model.analysis.BaseTypeInference;
|
import org.teavm.model.analysis.BaseTypeInference;
|
||||||
import org.teavm.model.instructions.InvocationType;
|
import org.teavm.model.instructions.InvocationType;
|
||||||
|
|
||||||
public class PreciseTypeInference extends BaseTypeInference<ValueType> {
|
public class PreciseTypeInference extends BaseTypeInference<PreciseValueType> {
|
||||||
public static final ValueType OBJECT_TYPE = ValueType.object("java.lang.Object");
|
public static final PreciseValueType OBJECT_TYPE = new PreciseValueType(ValueType.object("java.lang.Object"),
|
||||||
|
false);
|
||||||
private ClassHierarchy hierarchy;
|
private ClassHierarchy hierarchy;
|
||||||
private WasmGCMethodReturnTypes returnTypes;
|
private WasmGCMethodReturnTypes returnTypes;
|
||||||
|
|
||||||
|
@ -35,42 +36,42 @@ public class PreciseTypeInference extends BaseTypeInference<ValueType> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ValueType mapType(ValueType type) {
|
protected PreciseValueType mapType(ValueType type) {
|
||||||
return type;
|
return new PreciseValueType(type, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ValueType nullType() {
|
protected PreciseValueType nullType() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ValueType merge(ValueType a, ValueType b) {
|
protected PreciseValueType merge(PreciseValueType a, PreciseValueType b) {
|
||||||
if (a == null) {
|
if (a == null) {
|
||||||
return b;
|
return b;
|
||||||
} else if (b == null) {
|
} else if (b == null) {
|
||||||
return a;
|
return a;
|
||||||
} else {
|
} else {
|
||||||
if (a instanceof ValueType.Primitive && b instanceof ValueType.Primitive) {
|
if (a.valueType instanceof ValueType.Primitive && b.valueType instanceof ValueType.Primitive) {
|
||||||
if (a != b) {
|
if (a.valueType != b.valueType) {
|
||||||
return OBJECT_TYPE;
|
return OBJECT_TYPE;
|
||||||
} else {
|
} else {
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
} else if (a instanceof ValueType.Array) {
|
} else if (a.valueType instanceof ValueType.Array) {
|
||||||
if (b instanceof ValueType.Array) {
|
if (b.valueType instanceof ValueType.Array) {
|
||||||
var p = ((ValueType.Array) a).getItemType();
|
var p = new PreciseValueType(((ValueType.Array) a.valueType).getItemType(), false);
|
||||||
var q = ((ValueType.Array) b).getItemType();
|
var q = new PreciseValueType(((ValueType.Array) b.valueType).getItemType(), false);
|
||||||
return ValueType.arrayOf(merge(p, q));
|
return new PreciseValueType(ValueType.arrayOf(merge(p, q).valueType), a.isArrayUnwrap);
|
||||||
} else {
|
} else {
|
||||||
return OBJECT_TYPE;
|
return OBJECT_TYPE;
|
||||||
}
|
}
|
||||||
} else if (b instanceof ValueType.Array) {
|
} else if (b.valueType instanceof ValueType.Array) {
|
||||||
return OBJECT_TYPE;
|
return OBJECT_TYPE;
|
||||||
} else if (a instanceof ValueType.Object) {
|
} else if (a.valueType instanceof ValueType.Object) {
|
||||||
if (b instanceof ValueType.Object) {
|
if (b.valueType instanceof ValueType.Object) {
|
||||||
var p = ((ValueType.Object) a).getClassName();
|
var p = ((ValueType.Object) a.valueType).getClassName();
|
||||||
var q = ((ValueType.Object) b).getClassName();
|
var q = ((ValueType.Object) b.valueType).getClassName();
|
||||||
if (p.equals(q)) {
|
if (p.equals(q)) {
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
@ -87,7 +88,8 @@ public class PreciseTypeInference extends BaseTypeInference<ValueType> {
|
||||||
} else if (hierarchy.isSuperType(q, p, false)) {
|
} else if (hierarchy.isSuperType(q, p, false)) {
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
return ValueType.object(WasmGCUtil.findCommonSuperclass(hierarchy, first, second));
|
var result = ValueType.object(WasmGCUtil.findCommonSuperclass(hierarchy, first, second));
|
||||||
|
return new PreciseValueType(result, false);
|
||||||
} else {
|
} else {
|
||||||
return OBJECT_TYPE;
|
return OBJECT_TYPE;
|
||||||
}
|
}
|
||||||
|
@ -97,15 +99,20 @@ public class PreciseTypeInference extends BaseTypeInference<ValueType> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected ValueType elementType(ValueType valueType) {
|
protected PreciseValueType elementType(PreciseValueType valueType) {
|
||||||
return ((ValueType.Array) valueType).getItemType();
|
return new PreciseValueType(((ValueType.Array) valueType.valueType).getItemType(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ValueType methodReturnType(InvocationType invocationType, MethodReference methodRef) {
|
protected PreciseValueType methodReturnType(InvocationType invocationType, MethodReference methodRef) {
|
||||||
if (invocationType == InvocationType.SPECIAL) {
|
if (invocationType == InvocationType.SPECIAL) {
|
||||||
return returnTypes.returnTypeOf(methodRef);
|
return new PreciseValueType(returnTypes.returnTypeOf(methodRef), false);
|
||||||
}
|
}
|
||||||
return super.methodReturnType(invocationType, methodRef);
|
return super.methodReturnType(invocationType, methodRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PreciseValueType arrayUnwrapType(PreciseValueType type) {
|
||||||
|
return new PreciseValueType(type.valueType, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* 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 org.teavm.backend.wasm.gc;
|
||||||
|
|
||||||
|
import org.teavm.model.ValueType;
|
||||||
|
|
||||||
|
public class PreciseValueType {
|
||||||
|
public final ValueType valueType;
|
||||||
|
public final boolean isArrayUnwrap;
|
||||||
|
|
||||||
|
public PreciseValueType(ValueType valueType, boolean isArrayUnwrap) {
|
||||||
|
this.valueType = valueType;
|
||||||
|
this.isArrayUnwrap = isArrayUnwrap;
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,7 +17,6 @@ package org.teavm.backend.wasm.gc;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import org.teavm.backend.wasm.WasmRuntime;
|
import org.teavm.backend.wasm.WasmRuntime;
|
||||||
import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringPool;
|
|
||||||
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
||||||
import org.teavm.dependency.DependencyAnalyzer;
|
import org.teavm.dependency.DependencyAnalyzer;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
@ -52,12 +51,14 @@ public class WasmGCDependencies {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void contributeExceptionUtils() {
|
private void contributeExceptionUtils() {
|
||||||
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "npe", NullPointerException.class));
|
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "npe", NullPointerException.class))
|
||||||
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "aiiobe", ArrayIndexOutOfBoundsException.class));
|
.use();
|
||||||
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "cce", ClassCastException.class));
|
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "aiiobe", ArrayIndexOutOfBoundsException.class))
|
||||||
|
.use();
|
||||||
|
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "cce", ClassCastException.class)).use();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void contributeInitializerUtils() {
|
private void contributeInitializerUtils() {
|
||||||
analyzer.linkMethod(new MethodReference(WasmGCStringPool.class, "nextCharArray", char[].class));
|
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "nextCharArray", char[].class)).use();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ public class WasmGCVariableCategoryProvider implements VariableCategoryProvider
|
||||||
@Override
|
@Override
|
||||||
public Object[] getCategories(Program program, MethodReference method) {
|
public Object[] getCategories(Program program, MethodReference method) {
|
||||||
inference = new PreciseTypeInference(program, method, hierarchy, returnTypes);
|
inference = new PreciseTypeInference(program, method, hierarchy, returnTypes);
|
||||||
|
inference.setPhisSkipped(true);
|
||||||
var result = new Object[program.variableCount()];
|
var result = new Object[program.variableCount()];
|
||||||
for (int i = 0; i < program.variableCount(); ++i) {
|
for (int i = 0; i < program.variableCount(); ++i) {
|
||||||
var type = inference.typeOf(program.variableAt(i));
|
var type = inference.typeOf(program.variableAt(i));
|
||||||
|
|
|
@ -95,7 +95,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
|
|
||||||
private int classTagOffset;
|
private int classTagOffset;
|
||||||
private int classFlagsOffset;
|
private int classFlagsOffset;
|
||||||
private int classNameOffset;
|
private int classNameOffset = -1;
|
||||||
private int classParentOffset;
|
private int classParentOffset;
|
||||||
private int classArrayOffset;
|
private int classArrayOffset;
|
||||||
private int classArrayItemOffset;
|
private int classArrayItemOffset;
|
||||||
|
@ -141,7 +141,10 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
@Override
|
@Override
|
||||||
public void contributeToInitializerDefinitions(WasmFunction function) {
|
public void contributeToInitializerDefinitions(WasmFunction function) {
|
||||||
for (var classInfo : classInfoMap.values()) {
|
for (var classInfo : classInfoMap.values()) {
|
||||||
var newStruct = new WasmStructNewDefault(standardClasses.classClass().getStructure());
|
var classInstanceType = classInfo.virtualTableStructure != null
|
||||||
|
? classInfo.virtualTableStructure
|
||||||
|
: standardClasses.classClass().getStructure();
|
||||||
|
var newStruct = new WasmStructNewDefault(classInstanceType);
|
||||||
function.getBody().add(new WasmSetGlobal(classInfo.pointer, newStruct));
|
function.getBody().add(new WasmSetGlobal(classInfo.pointer, newStruct));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,6 +156,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
initializerFunctionStatements.clear();
|
initializerFunctionStatements.clear();
|
||||||
for (var classInfo : classInfoMap.values()) {
|
for (var classInfo : classInfoMap.values()) {
|
||||||
var supertypeFunction = supertypeGenerator.getIsSupertypeFunction(classInfo.getValueType());
|
var supertypeFunction = supertypeGenerator.getIsSupertypeFunction(classInfo.getValueType());
|
||||||
|
supertypeFunction.setReferenced(true);
|
||||||
function.getBody().add(setClassField(classInfo, classSupertypeFunctionOffset,
|
function.getBody().add(setClassField(classInfo, classSupertypeFunctionOffset,
|
||||||
new WasmFunctionReference(supertypeFunction)));
|
new WasmFunctionReference(supertypeFunction)));
|
||||||
function.getBody().add(setClassField(classInfo, CLASS_FIELD_OFFSET,
|
function.getBody().add(setClassField(classInfo, CLASS_FIELD_OFFSET,
|
||||||
|
@ -161,6 +165,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
var className = ((ValueType.Object) classInfo.getValueType()).getClassName();
|
var className = ((ValueType.Object) classInfo.getValueType()).getClassName();
|
||||||
var initFunction = functionProvider.forStaticMethod(new MethodReference(className,
|
var initFunction = functionProvider.forStaticMethod(new MethodReference(className,
|
||||||
CLINIT_METHOD_DESC));
|
CLINIT_METHOD_DESC));
|
||||||
|
initFunction.setReferenced(true);
|
||||||
function.getBody().add(new WasmSetGlobal(classInfo.initializerPointer,
|
function.getBody().add(new WasmSetGlobal(classInfo.initializerPointer,
|
||||||
new WasmFunctionReference(initFunction)));
|
new WasmFunctionReference(initFunction)));
|
||||||
}
|
}
|
||||||
|
@ -191,7 +196,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
classInfo.structure.setSupertype(standardClasses.objectClass().structure);
|
classInfo.structure.setSupertype(standardClasses.objectClass().structure);
|
||||||
}
|
}
|
||||||
module.types.add(classInfo.structure);
|
module.types.add(classInfo.structure);
|
||||||
fillFields(classInfo.structure.getFields(), type);
|
fillFields(classInfo, type);
|
||||||
}
|
}
|
||||||
var pointerName = names.forClassInstance(type);
|
var pointerName = names.forClassInstance(type);
|
||||||
var classStructure = type instanceof ValueType.Object
|
var classStructure = type instanceof ValueType.Object
|
||||||
|
@ -331,6 +336,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
}
|
}
|
||||||
wrapperFunction.getLocalVariables().addAll(List.of(params));
|
wrapperFunction.getLocalVariables().addAll(List.of(params));
|
||||||
}
|
}
|
||||||
|
function.setReferenced(true);
|
||||||
var ref = new WasmFunctionReference(function);
|
var ref = new WasmFunctionReference(function);
|
||||||
target.add(new WasmStructSet(structure, new WasmGetGlobal(global), index, ref));
|
target.add(new WasmStructSet(structure, new WasmGetGlobal(global), index, ref));
|
||||||
}
|
}
|
||||||
|
@ -439,13 +445,14 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillFields(List<WasmStorageType> fields, ValueType type) {
|
private void fillFields(WasmGCClassInfo classInfo, ValueType type) {
|
||||||
|
var fields = classInfo.structure.getFields();
|
||||||
fields.add(standardClasses.classClass().getType().asStorage());
|
fields.add(standardClasses.classClass().getType().asStorage());
|
||||||
fields.add(WasmType.Reference.ANY.asStorage());
|
fields.add(WasmType.Reference.ANY.asStorage());
|
||||||
if (type instanceof ValueType.Object) {
|
if (type instanceof ValueType.Object) {
|
||||||
fillClassFields(fields, ((ValueType.Object) type).getClassName());
|
fillClassFields(fields, ((ValueType.Object) type).getClassName());
|
||||||
} else if (type instanceof ValueType.Array) {
|
} else if (type instanceof ValueType.Array) {
|
||||||
fillArrayField(fields, ((ValueType.Array) type).getItemType());
|
fillArrayField(classInfo, ((ValueType.Array) type).getItemType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,14 +494,15 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
classSupertypeFunctionOffset = fields.size();
|
classSupertypeFunctionOffset = fields.size();
|
||||||
fields.add(supertypeGenerator.getFunctionType().getReference().asStorage());
|
fields.add(supertypeGenerator.getFunctionType().getReference().asStorage());
|
||||||
virtualTableFieldOffset = fields.size();
|
virtualTableFieldOffset = fields.size();
|
||||||
classNameOffset = fieldIndexes.get(new FieldReference(className, "name"));
|
classNameOffset = fieldIndexes.getOrDefault(new FieldReference(className, "name"), -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillArrayField(List<WasmStorageType> fields, ValueType elementType) {
|
private void fillArrayField(WasmGCClassInfo classInfo, ValueType elementType) {
|
||||||
var wasmArray = new WasmArray(null, () -> typeMapper.mapStorageType(elementType));
|
var wasmArray = new WasmArray(null, () -> typeMapper.mapStorageType(elementType));
|
||||||
module.types.add(wasmArray);
|
module.types.add(wasmArray);
|
||||||
fields.add(wasmArray.getReference().asStorage());
|
classInfo.structure.getFields().add(wasmArray.getReference().asStorage());
|
||||||
|
classInfo.array = wasmArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
private WasmFunction getCreatePrimitiveClassFunction() {
|
private WasmFunction getCreatePrimitiveClassFunction() {
|
||||||
|
@ -512,11 +520,11 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
WasmType.INT32
|
WasmType.INT32
|
||||||
);
|
);
|
||||||
var function = new WasmFunction(functionType);
|
var function = new WasmFunction(functionType);
|
||||||
function.setName("_teavm_fill_primitive_class_");
|
function.setName("teavm_fill_primitive_class");
|
||||||
module.functions.add(function);
|
module.functions.add(function);
|
||||||
|
|
||||||
var targetVar = new WasmLocal(standardClasses.classClass().getType(), "target");
|
var targetVar = new WasmLocal(standardClasses.classClass().getType(), "target");
|
||||||
var nameVar = new WasmLocal(standardClasses.objectClass().getType(), "name");
|
var nameVar = new WasmLocal(standardClasses.stringClass().getType(), "name");
|
||||||
var kindVar = new WasmLocal(WasmType.INT32, "kind");
|
var kindVar = new WasmLocal(WasmType.INT32, "kind");
|
||||||
function.add(targetVar);
|
function.add(targetVar);
|
||||||
function.add(nameVar);
|
function.add(nameVar);
|
||||||
|
@ -540,12 +548,14 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
classFlagsOffset,
|
classFlagsOffset,
|
||||||
flagsExpr
|
flagsExpr
|
||||||
));
|
));
|
||||||
function.getBody().add(new WasmStructSet(
|
if (classNameOffset >= 0) {
|
||||||
standardClasses.classClass().getStructure(),
|
function.getBody().add(new WasmStructSet(
|
||||||
new WasmGetLocal(targetVar),
|
standardClasses.classClass().getStructure(),
|
||||||
classNameOffset,
|
new WasmGetLocal(targetVar),
|
||||||
new WasmGetLocal(nameVar)
|
classNameOffset,
|
||||||
));
|
new WasmGetLocal(nameVar)
|
||||||
|
));
|
||||||
|
}
|
||||||
function.getBody().add(new WasmStructSet(
|
function.getBody().add(new WasmStructSet(
|
||||||
standardClasses.classClass().getStructure(),
|
standardClasses.classClass().getStructure(),
|
||||||
new WasmGetLocal(targetVar),
|
new WasmGetLocal(targetVar),
|
||||||
|
@ -559,7 +569,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
if (createArrayClassFunction == null) {
|
if (createArrayClassFunction == null) {
|
||||||
createArrayClassFunction = createCreateArrayClassFunction();
|
createArrayClassFunction = createCreateArrayClassFunction();
|
||||||
}
|
}
|
||||||
return createCreateArrayClassFunction();
|
return createArrayClassFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
private WasmFunction createCreateArrayClassFunction() {
|
private WasmFunction createCreateArrayClassFunction() {
|
||||||
|
@ -570,7 +580,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
);
|
);
|
||||||
var function = new WasmFunction(functionType);
|
var function = new WasmFunction(functionType);
|
||||||
module.functions.add(function);
|
module.functions.add(function);
|
||||||
function.setName("_teavm_fill_array_class_");
|
function.setName("teavm_fill_array_class");
|
||||||
|
|
||||||
var targetVar = new WasmLocal(standardClasses.classClass().getType(), "target");
|
var targetVar = new WasmLocal(standardClasses.classClass().getType(), "target");
|
||||||
var itemVar = new WasmLocal(standardClasses.classClass().getType(), "item");
|
var itemVar = new WasmLocal(standardClasses.classClass().getType(), "item");
|
||||||
|
|
|
@ -17,6 +17,7 @@ package org.teavm.backend.wasm.generate.gc.classes;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import org.teavm.backend.wasm.model.WasmArray;
|
||||||
import org.teavm.backend.wasm.model.WasmGlobal;
|
import org.teavm.backend.wasm.model.WasmGlobal;
|
||||||
import org.teavm.backend.wasm.model.WasmStructure;
|
import org.teavm.backend.wasm.model.WasmStructure;
|
||||||
import org.teavm.backend.wasm.model.WasmType;
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
|
@ -26,6 +27,7 @@ import org.teavm.model.ValueType;
|
||||||
public class WasmGCClassInfo {
|
public class WasmGCClassInfo {
|
||||||
private ValueType valueType;
|
private ValueType valueType;
|
||||||
WasmStructure structure;
|
WasmStructure structure;
|
||||||
|
WasmArray array;
|
||||||
WasmStructure virtualTableStructure;
|
WasmStructure virtualTableStructure;
|
||||||
WasmGlobal pointer;
|
WasmGlobal pointer;
|
||||||
WasmGlobal initializerPointer;
|
WasmGlobal initializerPointer;
|
||||||
|
@ -43,6 +45,10 @@ public class WasmGCClassInfo {
|
||||||
return structure;
|
return structure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public WasmArray getArray() {
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
public WasmStructure getVirtualTableStructure() {
|
public WasmStructure getVirtualTableStructure() {
|
||||||
return virtualTableStructure;
|
return virtualTableStructure;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,8 +35,8 @@ import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntUnary;
|
import org.teavm.backend.wasm.model.expression.WasmNullConstant;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmIntUnaryOperation;
|
import org.teavm.backend.wasm.model.expression.WasmReferencesEqual;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmReturn;
|
import org.teavm.backend.wasm.model.expression.WasmReturn;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmSetLocal;
|
import org.teavm.backend.wasm.model.expression.WasmSetLocal;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStructGet;
|
import org.teavm.backend.wasm.model.expression.WasmStructGet;
|
||||||
|
@ -79,27 +79,27 @@ public class WasmGCSupertypeFunctionGenerator implements WasmGCSupertypeFunction
|
||||||
private WasmFunction generateIsSupertypeFunction(ValueType type) {
|
private WasmFunction generateIsSupertypeFunction(ValueType type) {
|
||||||
var function = new WasmFunction(getFunctionType());
|
var function = new WasmFunction(getFunctionType());
|
||||||
function.setName(nameProvider.forSupertypeFunction(type));
|
function.setName(nameProvider.forSupertypeFunction(type));
|
||||||
var subtypeVar = new WasmLocal(WasmType.INT32, "subtype");
|
var subtypeVar = new WasmLocal(classGenerator.standardClasses.classClass().getType(), "subtype");
|
||||||
function.add(subtypeVar);
|
function.add(subtypeVar);
|
||||||
module.functions.add(function);
|
module.functions.add(function);
|
||||||
|
|
||||||
if (type instanceof ValueType.Object) {
|
if (type instanceof ValueType.Object) {
|
||||||
var className = ((ValueType.Object) type).getClassName();
|
var className = ((ValueType.Object) type).getClassName();
|
||||||
generateIsClass(subtypeVar, className, function.getBody());
|
generateIsClass(subtypeVar, className, function);
|
||||||
} else if (type instanceof ValueType.Array) {
|
} else if (type instanceof ValueType.Array) {
|
||||||
ValueType itemType = ((ValueType.Array) type).getItemType();
|
ValueType itemType = ((ValueType.Array) type).getItemType();
|
||||||
generateIsArray(subtypeVar, itemType, function.getBody());
|
generateIsArray(subtypeVar, itemType, function.getBody());
|
||||||
} else {
|
} else {
|
||||||
var expected = classGenerator.getClassInfo(type).pointer;
|
var expected = classGenerator.getClassInfo(type).pointer;
|
||||||
var condition = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.EQ,
|
var condition = new WasmReferencesEqual(new WasmGetLocal(subtypeVar), new WasmGetGlobal(expected));
|
||||||
new WasmGetLocal(subtypeVar), new WasmGetGlobal(expected));
|
|
||||||
function.getBody().add(new WasmReturn(condition));
|
function.getBody().add(new WasmReturn(condition));
|
||||||
}
|
}
|
||||||
|
|
||||||
return function;
|
return function;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generateIsClass(WasmLocal subtypeVar, String className, List<WasmExpression> body) {
|
private void generateIsClass(WasmLocal subtypeVar, String className, WasmFunction function) {
|
||||||
|
var body = function.getBody();
|
||||||
var ranges = tagRegistry.getRanges(className);
|
var ranges = tagRegistry.getRanges(className);
|
||||||
if (ranges.isEmpty()) {
|
if (ranges.isEmpty()) {
|
||||||
body.add(new WasmReturn(new WasmInt32Constant(0)));
|
body.add(new WasmReturn(new WasmInt32Constant(0)));
|
||||||
|
@ -108,8 +108,10 @@ public class WasmGCSupertypeFunctionGenerator implements WasmGCSupertypeFunction
|
||||||
|
|
||||||
int tagOffset = classGenerator.getClassTagOffset();
|
int tagOffset = classGenerator.getClassTagOffset();
|
||||||
|
|
||||||
|
var tagVar = new WasmLocal(WasmType.INT32, "tag");
|
||||||
|
function.add(tagVar);
|
||||||
var tagExpression = getClassField(new WasmGetLocal(subtypeVar), tagOffset);
|
var tagExpression = getClassField(new WasmGetLocal(subtypeVar), tagOffset);
|
||||||
body.add(new WasmSetLocal(subtypeVar, tagExpression));
|
body.add(new WasmSetLocal(tagVar, tagExpression));
|
||||||
|
|
||||||
ranges.sort(Comparator.comparingInt(range -> range.lower));
|
ranges.sort(Comparator.comparingInt(range -> range.lower));
|
||||||
|
|
||||||
|
@ -117,13 +119,13 @@ public class WasmGCSupertypeFunctionGenerator implements WasmGCSupertypeFunction
|
||||||
int upper = ranges.get(ranges.size() - 1).upper;
|
int upper = ranges.get(ranges.size() - 1).upper;
|
||||||
|
|
||||||
var lowerCondition = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.LT_SIGNED,
|
var lowerCondition = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.LT_SIGNED,
|
||||||
new WasmGetLocal(subtypeVar), new WasmInt32Constant(lower));
|
new WasmGetLocal(tagVar), new WasmInt32Constant(lower));
|
||||||
var testLower = new WasmConditional(lowerCondition);
|
var testLower = new WasmConditional(lowerCondition);
|
||||||
testLower.getThenBlock().getBody().add(new WasmReturn(new WasmInt32Constant(0)));
|
testLower.getThenBlock().getBody().add(new WasmReturn(new WasmInt32Constant(0)));
|
||||||
body.add(testLower);
|
body.add(testLower);
|
||||||
|
|
||||||
var upperCondition = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.GE_SIGNED,
|
var upperCondition = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.GE_SIGNED,
|
||||||
new WasmGetLocal(subtypeVar), new WasmInt32Constant(upper));
|
new WasmGetLocal(tagVar), new WasmInt32Constant(upper));
|
||||||
var testUpper = new WasmConditional(upperCondition);
|
var testUpper = new WasmConditional(upperCondition);
|
||||||
testUpper.getThenBlock().getBody().add(new WasmReturn(new WasmInt32Constant(0)));
|
testUpper.getThenBlock().getBody().add(new WasmReturn(new WasmInt32Constant(0)));
|
||||||
body.add(testUpper);
|
body.add(testUpper);
|
||||||
|
@ -133,12 +135,12 @@ public class WasmGCSupertypeFunctionGenerator implements WasmGCSupertypeFunction
|
||||||
int upperHole = ranges.get(i).lower;
|
int upperHole = ranges.get(i).lower;
|
||||||
|
|
||||||
lowerCondition = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.GE_SIGNED,
|
lowerCondition = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.GE_SIGNED,
|
||||||
new WasmGetLocal(subtypeVar), new WasmInt32Constant(lowerHole));
|
new WasmGetLocal(tagVar), new WasmInt32Constant(lowerHole));
|
||||||
testLower = new WasmConditional(lowerCondition);
|
testLower = new WasmConditional(lowerCondition);
|
||||||
body.add(testLower);
|
body.add(testLower);
|
||||||
|
|
||||||
upperCondition = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.LT_SIGNED,
|
upperCondition = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.LT_SIGNED,
|
||||||
new WasmGetLocal(subtypeVar), new WasmInt32Constant(upperHole));
|
new WasmGetLocal(tagVar), new WasmInt32Constant(upperHole));
|
||||||
testUpper = new WasmConditional(upperCondition);
|
testUpper = new WasmConditional(upperCondition);
|
||||||
testUpper.getThenBlock().getBody().add(new WasmReturn(new WasmInt32Constant(0)));
|
testUpper.getThenBlock().getBody().add(new WasmReturn(new WasmInt32Constant(0)));
|
||||||
|
|
||||||
|
@ -154,8 +156,8 @@ public class WasmGCSupertypeFunctionGenerator implements WasmGCSupertypeFunction
|
||||||
var itemExpression = getClassField(new WasmGetLocal(subtypeVar), itemOffset);
|
var itemExpression = getClassField(new WasmGetLocal(subtypeVar), itemOffset);
|
||||||
body.add(new WasmSetLocal(subtypeVar, itemExpression));
|
body.add(new WasmSetLocal(subtypeVar, itemExpression));
|
||||||
|
|
||||||
var itemTest = new WasmConditional(new WasmIntUnary(WasmIntType.INT32, WasmIntUnaryOperation.EQZ,
|
var itemTest = new WasmConditional(new WasmReferencesEqual(new WasmGetLocal(subtypeVar),
|
||||||
new WasmGetLocal(subtypeVar)));
|
new WasmNullConstant(WasmType.Reference.STRUCT)));
|
||||||
itemTest.setType(WasmType.INT32);
|
itemTest.setType(WasmType.INT32);
|
||||||
itemTest.getThenBlock().getBody().add(new WasmInt32Constant(0));
|
itemTest.getThenBlock().getBody().add(new WasmInt32Constant(0));
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ import org.teavm.backend.wasm.model.expression.WasmNullConstant;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmReferencesEqual;
|
import org.teavm.backend.wasm.model.expression.WasmReferencesEqual;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmSetGlobal;
|
import org.teavm.backend.wasm.model.expression.WasmSetGlobal;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmSetLocal;
|
import org.teavm.backend.wasm.model.expression.WasmSetLocal;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmSignedType;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStructGet;
|
import org.teavm.backend.wasm.model.expression.WasmStructGet;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStructNewDefault;
|
import org.teavm.backend.wasm.model.expression.WasmStructNewDefault;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
||||||
|
@ -340,7 +341,7 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
@Override
|
@Override
|
||||||
public void visit(SubscriptExpr expr) {
|
public void visit(SubscriptExpr expr) {
|
||||||
accept(expr.getArray());
|
accept(expr.getArray());
|
||||||
var arrayData = unwrapArray(result);
|
var arrayData = result;
|
||||||
arrayData.acceptVisitor(typeInference);
|
arrayData.acceptVisitor(typeInference);
|
||||||
var arrayTypeRef = (WasmType.CompositeReference) typeInference.getResult();
|
var arrayTypeRef = (WasmType.CompositeReference) typeInference.getResult();
|
||||||
var arrayType = (WasmArray) arrayTypeRef.composite;
|
var arrayType = (WasmArray) arrayTypeRef.composite;
|
||||||
|
@ -348,8 +349,22 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
accept(expr.getIndex());
|
accept(expr.getIndex());
|
||||||
var index = result;
|
var index = result;
|
||||||
|
|
||||||
result = new WasmArrayGet(arrayType, arrayData, index);
|
var arrayGet = new WasmArrayGet(arrayType, arrayData, index);
|
||||||
result.setLocation(expr.getLocation());
|
switch (expr.getType()) {
|
||||||
|
case BYTE:
|
||||||
|
arrayGet.setSignedType(WasmSignedType.SIGNED);
|
||||||
|
break;
|
||||||
|
case SHORT:
|
||||||
|
arrayGet.setSignedType(WasmSignedType.SIGNED);
|
||||||
|
break;
|
||||||
|
case CHAR:
|
||||||
|
arrayGet.setSignedType(WasmSignedType.UNSIGNED);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
arrayGet.setLocation(expr.getLocation());
|
||||||
|
result = arrayGet;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -395,11 +410,32 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
target.acceptVisitor(typeInference);
|
target.acceptVisitor(typeInference);
|
||||||
var type = (WasmType.CompositeReference) typeInference.getResult();
|
var type = (WasmType.CompositeReference) typeInference.getResult();
|
||||||
var struct = (WasmStructure) type.composite;
|
var struct = (WasmStructure) type.composite;
|
||||||
|
|
||||||
var fieldIndex = context.classInfoProvider().getFieldIndex(expr.getField());
|
var fieldIndex = context.classInfoProvider().getFieldIndex(expr.getField());
|
||||||
|
var structGet = new WasmStructGet(struct, target, fieldIndex);
|
||||||
result = new WasmStructGet(struct, target, fieldIndex);
|
var cls = context.classes().get(expr.getField().getClassName());
|
||||||
result.setLocation(expr.getLocation());
|
if (cls != null) {
|
||||||
|
var field = cls.getField(expr.getField().getFieldName());
|
||||||
|
if (field != null) {
|
||||||
|
var fieldType = field.getType();
|
||||||
|
if (fieldType instanceof ValueType.Primitive) {
|
||||||
|
switch (((ValueType.Primitive) fieldType).getKind()) {
|
||||||
|
case BYTE:
|
||||||
|
structGet.setSignedType(WasmSignedType.SIGNED);
|
||||||
|
break;
|
||||||
|
case SHORT:
|
||||||
|
structGet.setSignedType(WasmSignedType.SIGNED);
|
||||||
|
break;
|
||||||
|
case CHARACTER:
|
||||||
|
structGet.setSignedType(WasmSignedType.UNSIGNED);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
structGet.setLocation(expr.getLocation());
|
||||||
|
result = structGet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -240,7 +240,10 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
|
||||||
for (var i = firstVar; i < ast.getVariables().size(); ++i) {
|
for (var i = firstVar; i < ast.getVariables().size(); ++i) {
|
||||||
var localVar = ast.getVariables().get(i);
|
var localVar = ast.getVariables().get(i);
|
||||||
var representative = method.getProgram().variableAt(variableRepresentatives[i]);
|
var representative = method.getProgram().variableAt(variableRepresentatives[i]);
|
||||||
var type = typeMapper.mapType(typeInference.typeOf(representative));
|
var inferredType = typeInference.typeOf(representative);
|
||||||
|
var type = !inferredType.isArrayUnwrap
|
||||||
|
? typeMapper.mapType(inferredType.valueType)
|
||||||
|
: classInfoProvider.getClassInfo(inferredType.valueType).getArray().getReference();
|
||||||
var wasmLocal = new WasmLocal(type, localVar.getName());
|
var wasmLocal = new WasmLocal(type, localVar.getName());
|
||||||
function.add(wasmLocal);
|
function.add(wasmLocal);
|
||||||
}
|
}
|
||||||
|
@ -304,6 +307,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
|
||||||
dummyInitializer = new WasmFunction(functionTypes.of(null));
|
dummyInitializer = new WasmFunction(functionTypes.of(null));
|
||||||
dummyInitializer.getBody().add(new WasmReturn());
|
dummyInitializer.getBody().add(new WasmReturn());
|
||||||
dummyInitializer.setName("teavm_dummy_initializer");
|
dummyInitializer.setName("teavm_dummy_initializer");
|
||||||
|
dummyInitializer.setReferenced(true);
|
||||||
module.functions.add(dummyInitializer);
|
module.functions.add(dummyInitializer);
|
||||||
}
|
}
|
||||||
return dummyInitializer;
|
return dummyInitializer;
|
||||||
|
|
|
@ -33,6 +33,7 @@ import org.teavm.backend.wasm.model.expression.WasmSetGlobal;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStructNewDefault;
|
import org.teavm.backend.wasm.model.expression.WasmStructNewDefault;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
import org.teavm.backend.wasm.model.expression.WasmStructSet;
|
||||||
import org.teavm.backend.wasm.render.WasmBinaryWriter;
|
import org.teavm.backend.wasm.render.WasmBinaryWriter;
|
||||||
|
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
public class WasmGCStringPool implements WasmGCStringProvider, WasmGCInitializerContributor {
|
public class WasmGCStringPool implements WasmGCStringProvider, WasmGCInitializerContributor {
|
||||||
|
@ -41,6 +42,7 @@ public class WasmGCStringPool implements WasmGCStringProvider, WasmGCInitializer
|
||||||
private WasmBinaryWriter binaryWriter = new WasmBinaryWriter();
|
private WasmBinaryWriter binaryWriter = new WasmBinaryWriter();
|
||||||
private Map<String, WasmGCStringConstant> stringMap = new LinkedHashMap<>();
|
private Map<String, WasmGCStringConstant> stringMap = new LinkedHashMap<>();
|
||||||
private BaseWasmFunctionRepository functionProvider;
|
private BaseWasmFunctionRepository functionProvider;
|
||||||
|
private WasmFunction nextCharArrayFunction;
|
||||||
|
|
||||||
public WasmGCStringPool(WasmGCStandardClasses standardClasses, WasmModule module,
|
public WasmGCStringPool(WasmGCStandardClasses standardClasses, WasmModule module,
|
||||||
BaseWasmFunctionRepository functionProvider) {
|
BaseWasmFunctionRepository functionProvider) {
|
||||||
|
@ -62,8 +64,9 @@ public class WasmGCStringPool implements WasmGCStringProvider, WasmGCInitializer
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void contributeToInitializer(WasmFunction function) {
|
public void contributeToInitializer(WasmFunction function) {
|
||||||
var nextCharArrayFunction = functionProvider.forStaticMethod(new MethodReference(WasmGCStringPool.class,
|
if (nextCharArrayFunction == null) {
|
||||||
"nextCharArray", char[].class));
|
return;
|
||||||
|
}
|
||||||
var stringStruct = standardClasses.stringClass().getStructure();
|
var stringStruct = standardClasses.stringClass().getStructure();
|
||||||
for (var str : stringMap.values()) {
|
for (var str : stringMap.values()) {
|
||||||
var value = new WasmCall(nextCharArrayFunction);
|
var value = new WasmCall(nextCharArrayFunction);
|
||||||
|
@ -75,9 +78,12 @@ public class WasmGCStringPool implements WasmGCStringProvider, WasmGCInitializer
|
||||||
@Override
|
@Override
|
||||||
public WasmGCStringConstant getStringConstant(String string) {
|
public WasmGCStringConstant getStringConstant(String string) {
|
||||||
return stringMap.computeIfAbsent(string, s -> {
|
return stringMap.computeIfAbsent(string, s -> {
|
||||||
|
if (nextCharArrayFunction == null) {
|
||||||
|
initNextCharArrayFunction();
|
||||||
|
}
|
||||||
binaryWriter.writeInt32(string.length());
|
binaryWriter.writeInt32(string.length());
|
||||||
binaryWriter.writeBytes(string.getBytes(StandardCharsets.UTF_8));
|
binaryWriter.writeBytes(string.getBytes(StandardCharsets.UTF_8));
|
||||||
var globalName = "_teavm_java_string_" + stringMap.size();
|
var globalName = "teavm_java_string_" + stringMap.size();
|
||||||
var globalType = standardClasses.stringClass().getType();
|
var globalType = standardClasses.stringClass().getType();
|
||||||
var global = new WasmGlobal(globalName, globalType, WasmExpression.defaultValueOfType(globalType));
|
var global = new WasmGlobal(globalName, globalType, WasmExpression.defaultValueOfType(globalType));
|
||||||
module.globals.add(global);
|
module.globals.add(global);
|
||||||
|
@ -85,50 +91,8 @@ public class WasmGCStringPool implements WasmGCStringProvider, WasmGCInitializer
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static char[] nextCharArray() {
|
private void initNextCharArrayFunction() {
|
||||||
var length = nextLEB();
|
nextCharArrayFunction = functionProvider.forStaticMethod(new MethodReference(WasmGCSupport.class,
|
||||||
var result = new char[length];
|
"nextCharArray", char[].class));
|
||||||
var pos = 0;
|
|
||||||
while (pos < length) {
|
|
||||||
var b = nextByte();
|
|
||||||
if ((b & 0x80) == 0) {
|
|
||||||
result[pos++] = (char) b;
|
|
||||||
} else if ((b & 0xE0) == 0xC0) {
|
|
||||||
var b2 = nextByte();
|
|
||||||
result[pos++] = (char) (((b & 0x1F) << 6) | (b2 & 0x3F));
|
|
||||||
} else if ((b & 0xF0) == 0xE0) {
|
|
||||||
var b2 = nextByte();
|
|
||||||
var b3 = nextByte();
|
|
||||||
var c = (char) (((b & 0x0F) << 12) | ((b2 & 0x3f) << 6) | (b3 & 0x3F));
|
|
||||||
result[pos++] = c;
|
|
||||||
} else if ((b & 0xF8) == 0xF0) {
|
|
||||||
var b2 = nextByte();
|
|
||||||
var b3 = nextByte();
|
|
||||||
var b4 = nextByte();
|
|
||||||
var code = ((b & 0x07) << 18) | ((b2 & 0x3f) << 12) | ((b3 & 0x3F) << 6) | (b4 & 0x3F);
|
|
||||||
result[pos++] = Character.highSurrogate(code);
|
|
||||||
result[pos++] = Character.lowSurrogate(code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int nextLEB() {
|
|
||||||
var shift = 0;
|
|
||||||
var result = 0;
|
|
||||||
while (true) {
|
|
||||||
var b = nextByte();
|
|
||||||
var digit = b & 0x7F;
|
|
||||||
result |= digit << shift;
|
|
||||||
if ((b & 0x80) == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
shift += 7;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native byte nextByte();
|
|
||||||
|
|
||||||
private static native void error();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ package org.teavm.backend.wasm.generators.gc;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.teavm.backend.wasm.generate.gc.methods.WasmGCCustomGeneratorProvider;
|
import org.teavm.backend.wasm.generate.gc.methods.WasmGCCustomGeneratorProvider;
|
||||||
import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringPool;
|
import org.teavm.backend.wasm.runtime.WasmGCSupport;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
public class WasmGCCustomGenerators implements WasmGCCustomGeneratorProvider {
|
public class WasmGCCustomGenerators implements WasmGCCustomGeneratorProvider {
|
||||||
|
@ -30,7 +30,7 @@ public class WasmGCCustomGenerators implements WasmGCCustomGeneratorProvider {
|
||||||
|
|
||||||
private void fillStringPool() {
|
private void fillStringPool() {
|
||||||
generators.put(
|
generators.put(
|
||||||
new MethodReference(WasmGCStringPool.class, "nextByte", byte.class),
|
new MethodReference(WasmGCSupport.class, "nextByte", byte.class),
|
||||||
new WasmGCStringPoolGenerator()
|
new WasmGCStringPoolGenerator()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ public class WasmFunction extends WasmEntity {
|
||||||
private String exportName;
|
private String exportName;
|
||||||
private String importName;
|
private String importName;
|
||||||
private String importModule;
|
private String importModule;
|
||||||
|
private boolean referenced;
|
||||||
private WasmFunctionType type;
|
private WasmFunctionType type;
|
||||||
private List<WasmLocal> localVariables = new ArrayList<>();
|
private List<WasmLocal> localVariables = new ArrayList<>();
|
||||||
private List<WasmLocal> readonlyLocalVariables = Collections.unmodifiableList(localVariables);
|
private List<WasmLocal> readonlyLocalVariables = Collections.unmodifiableList(localVariables);
|
||||||
|
@ -70,6 +71,14 @@ public class WasmFunction extends WasmEntity {
|
||||||
this.importModule = importModule;
|
this.importModule = importModule;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isReferenced() {
|
||||||
|
return referenced;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReferenced(boolean referenced) {
|
||||||
|
this.referenced = referenced;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
boolean isImported() {
|
boolean isImported() {
|
||||||
return importName != null;
|
return importName != null;
|
||||||
|
|
|
@ -265,19 +265,39 @@ public class WasmBinaryRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderElement(WasmModule module) {
|
private void renderElement(WasmModule module) {
|
||||||
if (module.getFunctionTable().isEmpty()) {
|
var count = 0;
|
||||||
|
if (!module.getFunctionTable().isEmpty()) {
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
if (module.functions.stream().anyMatch(WasmFunction::isReferenced)) {
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
if (count == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WasmBinaryWriter section = new WasmBinaryWriter();
|
WasmBinaryWriter section = new WasmBinaryWriter();
|
||||||
section.writeLEB(1);
|
section.writeLEB(count);
|
||||||
section.writeLEB(0);
|
|
||||||
|
|
||||||
renderInitializer(section, 0);
|
if (!module.getFunctionTable().isEmpty()) {
|
||||||
|
section.writeLEB(0);
|
||||||
|
renderInitializer(section, 0);
|
||||||
|
section.writeLEB(module.getFunctionTable().size());
|
||||||
|
for (var function : module.getFunctionTable()) {
|
||||||
|
section.writeLEB(module.functions.indexOf(function));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
section.writeLEB(module.getFunctionTable().size());
|
var referencedFunctions = module.functions.stream()
|
||||||
for (var function : module.getFunctionTable()) {
|
.filter(WasmFunction::isReferenced)
|
||||||
section.writeLEB(module.functions.indexOf(function));
|
.collect(Collectors.toList());
|
||||||
|
if (!referencedFunctions.isEmpty()) {
|
||||||
|
section.writeLEB(3);
|
||||||
|
section.writeByte(0);
|
||||||
|
section.writeLEB(referencedFunctions.size());
|
||||||
|
for (var function : referencedFunctions) {
|
||||||
|
section.writeLEB(module.functions.indexOf(function));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writeSection(SECTION_ELEMENT, "element", section.getData());
|
writeSection(SECTION_ELEMENT, "element", section.getData());
|
||||||
|
|
|
@ -38,4 +38,51 @@ public class WasmGCSupport {
|
||||||
|
|
||||||
@Import(name = "putcharStderr")
|
@Import(name = "putcharStderr")
|
||||||
public static native void putCharStderr(char c);
|
public static native void putCharStderr(char c);
|
||||||
|
|
||||||
|
public static char[] nextCharArray() {
|
||||||
|
var length = nextLEB();
|
||||||
|
var result = new char[length];
|
||||||
|
var pos = 0;
|
||||||
|
while (pos < length) {
|
||||||
|
var b = nextByte();
|
||||||
|
if ((b & 0x80) == 0) {
|
||||||
|
result[pos++] = (char) b;
|
||||||
|
} else if ((b & 0xE0) == 0xC0) {
|
||||||
|
var b2 = nextByte();
|
||||||
|
result[pos++] = (char) (((b & 0x1F) << 6) | (b2 & 0x3F));
|
||||||
|
} else if ((b & 0xF0) == 0xE0) {
|
||||||
|
var b2 = nextByte();
|
||||||
|
var b3 = nextByte();
|
||||||
|
var c = (char) (((b & 0x0F) << 12) | ((b2 & 0x3f) << 6) | (b3 & 0x3F));
|
||||||
|
result[pos++] = c;
|
||||||
|
} else if ((b & 0xF8) == 0xF0) {
|
||||||
|
var b2 = nextByte();
|
||||||
|
var b3 = nextByte();
|
||||||
|
var b4 = nextByte();
|
||||||
|
var code = ((b & 0x07) << 18) | ((b2 & 0x3f) << 12) | ((b3 & 0x3F) << 6) | (b4 & 0x3F);
|
||||||
|
result[pos++] = Character.highSurrogate(code);
|
||||||
|
result[pos++] = Character.lowSurrogate(code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int nextLEB() {
|
||||||
|
var shift = 0;
|
||||||
|
var result = 0;
|
||||||
|
while (true) {
|
||||||
|
var b = nextByte();
|
||||||
|
var digit = b & 0x7F;
|
||||||
|
result |= digit << shift;
|
||||||
|
if ((b & 0x80) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
shift += 7;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static native byte nextByte();
|
||||||
|
|
||||||
|
private static native void error();
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,12 +60,18 @@ public abstract class BaseTypeInference<T> {
|
||||||
private Object[] types;
|
private Object[] types;
|
||||||
private Graph graph;
|
private Graph graph;
|
||||||
private Graph arrayGraph;
|
private Graph arrayGraph;
|
||||||
|
private Graph arrayUnwrapGraph;
|
||||||
|
private boolean phisSkipped;
|
||||||
|
|
||||||
public BaseTypeInference(Program program, MethodReference reference) {
|
public BaseTypeInference(Program program, MethodReference reference) {
|
||||||
this.program = program;
|
this.program = program;
|
||||||
this.reference = reference;
|
this.reference = reference;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPhisSkipped(boolean phisSkipped) {
|
||||||
|
this.phisSkipped = phisSkipped;
|
||||||
|
}
|
||||||
|
|
||||||
private void prepare() {
|
private void prepare() {
|
||||||
types = new Object[program.variableCount()];
|
types = new Object[program.variableCount()];
|
||||||
var visitor = new InitialTypeVisitor(program.variableCount());
|
var visitor = new InitialTypeVisitor(program.variableCount());
|
||||||
|
@ -78,9 +84,11 @@ public abstract class BaseTypeInference<T> {
|
||||||
for (var insn : block) {
|
for (var insn : block) {
|
||||||
insn.acceptVisitor(visitor);
|
insn.acceptVisitor(visitor);
|
||||||
}
|
}
|
||||||
for (var phi : block.getPhis()) {
|
if (!phisSkipped) {
|
||||||
for (var incoming : phi.getIncomings()) {
|
for (var phi : block.getPhis()) {
|
||||||
visitor.graphBuilder.addEdge(incoming.getValue().getIndex(), phi.getReceiver().getIndex());
|
for (var incoming : phi.getIncomings()) {
|
||||||
|
visitor.graphBuilder.addEdge(incoming.getValue().getIndex(), phi.getReceiver().getIndex());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (var tryCatch : block.getTryCatchBlocks()) {
|
for (var tryCatch : block.getTryCatchBlocks()) {
|
||||||
|
@ -95,6 +103,7 @@ public abstract class BaseTypeInference<T> {
|
||||||
}
|
}
|
||||||
graph = visitor.graphBuilder.build();
|
graph = visitor.graphBuilder.build();
|
||||||
arrayGraph = visitor.arrayGraphBuilder.build();
|
arrayGraph = visitor.arrayGraphBuilder.build();
|
||||||
|
arrayUnwrapGraph = visitor.arrayUnwrapGraphBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -126,6 +135,12 @@ public abstract class BaseTypeInference<T> {
|
||||||
typeStack.push(type);
|
typeStack.push(type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (var succ : arrayUnwrapGraph.outgoingEdges(variable)) {
|
||||||
|
if (!Objects.equals(types[succ], type)) {
|
||||||
|
stack.push(succ);
|
||||||
|
typeStack.push(arrayUnwrapType(type));
|
||||||
|
}
|
||||||
|
}
|
||||||
if (arrayGraph.outgoingEdgesCount(variable) > 0) {
|
if (arrayGraph.outgoingEdgesCount(variable) > 0) {
|
||||||
var elementType = elementType(type);
|
var elementType = elementType(type);
|
||||||
for (var succ : arrayGraph.outgoingEdges(variable)) {
|
for (var succ : arrayGraph.outgoingEdges(variable)) {
|
||||||
|
@ -174,13 +189,19 @@ public abstract class BaseTypeInference<T> {
|
||||||
return mapType(methodRef.getReturnType());
|
return mapType(methodRef.getReturnType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected T arrayUnwrapType(T type) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
private class InitialTypeVisitor extends AbstractInstructionVisitor {
|
private class InitialTypeVisitor extends AbstractInstructionVisitor {
|
||||||
private GraphBuilder graphBuilder;
|
private GraphBuilder graphBuilder;
|
||||||
private GraphBuilder arrayGraphBuilder;
|
private GraphBuilder arrayGraphBuilder;
|
||||||
|
private GraphBuilder arrayUnwrapGraphBuilder;
|
||||||
|
|
||||||
InitialTypeVisitor(int size) {
|
InitialTypeVisitor(int size) {
|
||||||
graphBuilder = new GraphBuilder(size);
|
graphBuilder = new GraphBuilder(size);
|
||||||
arrayGraphBuilder = new GraphBuilder(size);
|
arrayGraphBuilder = new GraphBuilder(size);
|
||||||
|
arrayUnwrapGraphBuilder = new GraphBuilder(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -309,7 +330,7 @@ public abstract class BaseTypeInference<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(UnwrapArrayInstruction insn) {
|
public void visit(UnwrapArrayInstruction insn) {
|
||||||
graphBuilder.addEdge(insn.getArray().getIndex(), insn.getReceiver().getIndex());
|
arrayUnwrapGraphBuilder.addEdge(insn.getArray().getIndex(), insn.getReceiver().getIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in New Issue
Block a user