mirror of
https://github.com/konsoletyper/teavm.git
synced 2024-11-21 01:00:54 +08:00
wasm gc: support Array.newInstance
This commit is contained in:
parent
40fbce0ddd
commit
199032d48a
@ -16,6 +16,7 @@
|
||||
package org.teavm.classlib.java.lang.reflect;
|
||||
|
||||
import org.teavm.backend.javascript.spi.GeneratedBy;
|
||||
import org.teavm.classlib.PlatformDetector;
|
||||
import org.teavm.classlib.java.lang.TArrayIndexOutOfBoundsException;
|
||||
import org.teavm.classlib.java.lang.TClass;
|
||||
import org.teavm.classlib.java.lang.TIllegalArgumentException;
|
||||
@ -59,9 +60,15 @@ public final class TArray extends TObject {
|
||||
if (length < 0) {
|
||||
throw new TNegativeArraySizeException();
|
||||
}
|
||||
return newInstanceImpl(((TClass<?>) (Object) componentType).getPlatformClass(), length);
|
||||
if (PlatformDetector.isWebAssemblyGC()) {
|
||||
return newInstanceImpl(componentType, length);
|
||||
} else {
|
||||
return newInstanceImpl(((TClass<?>) (Object) componentType).getPlatformClass(), length);
|
||||
}
|
||||
}
|
||||
|
||||
private static native TObject newInstanceImpl(Class<?> componentType, int length);
|
||||
|
||||
@GeneratedBy(ArrayNativeGenerator.class)
|
||||
@DelegateTo("newInstanceLowLevel")
|
||||
@NoSideEffects
|
||||
|
@ -304,6 +304,11 @@ public class WasmGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||
return new WasmInt32Constant(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WasmExpression nullLiteral(WasmType type) {
|
||||
return new WasmInt32Constant(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WasmExpression genIsNull(WasmExpression value) {
|
||||
return new WasmIntUnary(WasmIntType.INT32, WasmIntUnaryOperation.EQZ, value);
|
||||
|
@ -575,6 +575,8 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||
|
||||
protected abstract WasmExpression nullLiteral(Expr expr);
|
||||
|
||||
protected abstract WasmExpression nullLiteral(WasmType type);
|
||||
|
||||
protected abstract WasmExpression stringLiteral(String s);
|
||||
|
||||
protected abstract WasmExpression classLiteral(ValueType type);
|
||||
@ -1179,13 +1181,13 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||
var valueToCast = exprCache.create(result, wasmSourceType, expr.getLocation(), block.getBody());
|
||||
|
||||
var nullCheck = new WasmBranch(genIsNull(valueToCast.expr()), block);
|
||||
nullCheck.setResult(valueToCast.expr());
|
||||
nullCheck.setResult(nullLiteral(wasmTargetType));
|
||||
block.getBody().add(new WasmDrop(nullCheck));
|
||||
|
||||
var supertypeCall = generateInstanceOf(valueToCast.expr(), expr.getTarget());
|
||||
|
||||
var breakIfPassed = new WasmBranch(supertypeCall, block);
|
||||
breakIfPassed.setResult(valueToCast.expr());
|
||||
breakIfPassed.setResult(generateCast(valueToCast.expr(), wasmTargetType));
|
||||
block.getBody().add(new WasmDrop(breakIfPassed));
|
||||
|
||||
var callSiteId = generateCallSiteId(expr.getLocation());
|
||||
@ -1194,7 +1196,7 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
|
||||
callSiteId.generateThrow(block.getBody(), expr.getLocation());
|
||||
|
||||
valueToCast.release();
|
||||
result = generateCast(block, wasmTargetType);
|
||||
result = block;
|
||||
}
|
||||
|
||||
protected abstract WasmExpression generateCast(WasmExpression value, WasmType targetType);
|
||||
|
@ -96,6 +96,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||
private WasmFunction createPrimitiveClassFunction;
|
||||
private WasmFunction createArrayClassFunction;
|
||||
private final WasmGCSupertypeFunctionGenerator supertypeGenerator;
|
||||
private final WasmGCNewArrayFunctionGenerator newArrayGenerator;
|
||||
|
||||
private int classTagOffset;
|
||||
private int classFlagsOffset;
|
||||
@ -103,6 +104,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||
private int classParentOffset;
|
||||
private int classArrayOffset;
|
||||
private int classArrayItemOffset;
|
||||
private int classNewArrayOffset;
|
||||
private int classSupertypeFunctionOffset;
|
||||
private int virtualTableFieldOffset;
|
||||
|
||||
@ -123,6 +125,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||
standardClasses = new WasmGCStandardClasses(this);
|
||||
strings = new WasmGCStringPool(standardClasses, module, functionProvider);
|
||||
supertypeGenerator = new WasmGCSupertypeFunctionGenerator(module, this, names, tagRegistry, functionTypes);
|
||||
newArrayGenerator = new WasmGCNewArrayFunctionGenerator(module, functionTypes, this);
|
||||
typeMapper = new WasmGCTypeMapper(this, functionTypes, module);
|
||||
}
|
||||
|
||||
@ -190,11 +193,19 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||
initializerFunctionStatements.clear();
|
||||
for (var classInfo : classInfoMap.values()) {
|
||||
var req = metadataRequirements.getInfo(classInfo.getValueType());
|
||||
if (req != null && req.isAssignable()) {
|
||||
var supertypeFunction = supertypeGenerator.getIsSupertypeFunction(classInfo.getValueType());
|
||||
supertypeFunction.setReferenced(true);
|
||||
function.getBody().add(setClassField(classInfo, classSupertypeFunctionOffset,
|
||||
new WasmFunctionReference(supertypeFunction)));
|
||||
if (req != null) {
|
||||
if (req.isAssignable()) {
|
||||
var supertypeFunction = supertypeGenerator.getIsSupertypeFunction(classInfo.getValueType());
|
||||
supertypeFunction.setReferenced(true);
|
||||
function.getBody().add(setClassField(classInfo, classSupertypeFunctionOffset,
|
||||
new WasmFunctionReference(supertypeFunction)));
|
||||
}
|
||||
if (req.newArray()) {
|
||||
var newArrayFunction = newArrayGenerator.generateNewArrayFunction(classInfo.getValueType());
|
||||
newArrayFunction.setReferenced(true);
|
||||
function.getBody().add(setClassField(classInfo, classNewArrayOffset,
|
||||
new WasmFunctionReference(newArrayFunction)));
|
||||
}
|
||||
}
|
||||
function.getBody().add(setClassField(classInfo, CLASS_FIELD_OFFSET,
|
||||
new WasmGetGlobal(classClass.pointer)));
|
||||
@ -275,6 +286,16 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||
return classSupertypeFunctionOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getClassNameOffset() {
|
||||
return classNameOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNewArrayFunctionOffset() {
|
||||
return classNewArrayOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVirtualMethodsOffset() {
|
||||
return virtualTableFieldOffset;
|
||||
@ -546,6 +567,8 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||
fields.add(standardClasses.classClass().getType().asStorage());
|
||||
classSupertypeFunctionOffset = fields.size();
|
||||
fields.add(supertypeGenerator.getFunctionType().getReference().asStorage());
|
||||
classNewArrayOffset = fields.size();
|
||||
fields.add(newArrayGenerator.getNewArrayFunctionType().getReference().asStorage());
|
||||
virtualTableFieldOffset = fields.size();
|
||||
classNameOffset = fieldIndexes.getOrDefault(new FieldReference(className, "name"), -1);
|
||||
}
|
||||
|
@ -37,6 +37,10 @@ public interface WasmGCClassInfoProvider {
|
||||
|
||||
int getClassSupertypeFunctionOffset();
|
||||
|
||||
int getNewArrayFunctionOffset();
|
||||
|
||||
int getClassNameOffset();
|
||||
|
||||
default WasmGCClassInfo getClassInfo(String name) {
|
||||
return getClassInfo(ValueType.object(name));
|
||||
}
|
||||
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.generate.gc.classes;
|
||||
|
||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||
import org.teavm.backend.wasm.generate.TemporaryVariablePool;
|
||||
import org.teavm.backend.wasm.generate.gc.methods.WasmGCGenerationUtil;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmFunctionType;
|
||||
import org.teavm.backend.wasm.model.WasmLocal;
|
||||
import org.teavm.backend.wasm.model.WasmModule;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmReturn;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
class WasmGCNewArrayFunctionGenerator {
|
||||
private WasmModule module;
|
||||
private WasmFunctionTypes functionTypes;
|
||||
private WasmGCClassInfoProvider classInfoProvider;
|
||||
private WasmFunctionType newArrayFunctionType;
|
||||
|
||||
WasmGCNewArrayFunctionGenerator(WasmModule module, WasmFunctionTypes functionTypes,
|
||||
WasmGCClassInfoProvider classInfoProvider) {
|
||||
this.module = module;
|
||||
this.functionTypes = functionTypes;
|
||||
this.classInfoProvider = classInfoProvider;
|
||||
}
|
||||
|
||||
WasmFunction generateNewArrayFunction(ValueType itemType) {
|
||||
var function = new WasmFunction(getNewArrayFunctionType());
|
||||
module.functions.add(function);
|
||||
var sizeLocal = new WasmLocal(WasmType.INT32);
|
||||
function.add(sizeLocal);
|
||||
var tempVars = new TemporaryVariablePool(function);
|
||||
var genUtil = new WasmGCGenerationUtil(classInfoProvider, tempVars);
|
||||
var targetVar = new WasmLocal(classInfoProvider.getClassInfo(ValueType.arrayOf(itemType)).getType());
|
||||
function.add(targetVar);
|
||||
genUtil.allocateArray(itemType, new WasmGetLocal(sizeLocal), null, targetVar, function.getBody());
|
||||
function.getBody().add(new WasmReturn(new WasmGetLocal(targetVar)));
|
||||
return function;
|
||||
}
|
||||
|
||||
WasmFunctionType getNewArrayFunctionType() {
|
||||
if (newArrayFunctionType == null) {
|
||||
newArrayFunctionType = functionTypes.of(classInfoProvider.getClassInfo("java.lang.Object").getType(),
|
||||
WasmType.INT32);
|
||||
}
|
||||
return newArrayFunctionType;
|
||||
}
|
||||
}
|
@ -211,6 +211,11 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||
: WasmType.Reference.STRUCT);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WasmExpression nullLiteral(WasmType type) {
|
||||
return new WasmNullConstant((WasmType.Reference) type);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WasmExpression genIsNull(WasmExpression value) {
|
||||
return new WasmReferencesEqual(value, new WasmNullConstant(WasmType.Reference.STRUCT));
|
||||
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.generators.gc;
|
||||
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
import org.teavm.backend.wasm.model.WasmLocal;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCallReference;
|
||||
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
|
||||
import org.teavm.backend.wasm.model.expression.WasmReturn;
|
||||
import org.teavm.backend.wasm.model.expression.WasmStructGet;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class ArrayGenerator implements WasmGCCustomGenerator {
|
||||
@Override
|
||||
public void apply(MethodReference method, WasmFunction function, WasmGCCustomGeneratorContext context) {
|
||||
var clsStruct = context.classInfoProvider().getClassInfo("java.lang.Class").getStructure();
|
||||
var classLocal = new WasmLocal(clsStruct.getReference());
|
||||
var sizeLocal = new WasmLocal(WasmType.INT32);
|
||||
function.add(classLocal);
|
||||
function.add(sizeLocal);
|
||||
var constructorRef = new WasmStructGet(clsStruct, new WasmGetLocal(classLocal),
|
||||
context.classInfoProvider().getNewArrayFunctionOffset());
|
||||
var functionType = context.functionTypes().of(
|
||||
context.classInfoProvider().getClassInfo("java.lang.Object").getType(),
|
||||
WasmType.INT32
|
||||
);
|
||||
var result = new WasmCallReference(constructorRef, functionType);
|
||||
result.getArguments().add(new WasmGetLocal(sizeLocal));
|
||||
function.getBody().add(new WasmReturn(result));
|
||||
}
|
||||
}
|
@ -36,6 +36,9 @@ public class ClassGenerators implements WasmGCCustomGenerator {
|
||||
case "isInstance":
|
||||
generateIsInstance(function, context);
|
||||
break;
|
||||
case "getName":
|
||||
generateGetName(function, context);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported method: " + method);
|
||||
}
|
||||
@ -65,4 +68,14 @@ public class ClassGenerators implements WasmGCCustomGenerator {
|
||||
|
||||
function.getBody().add(new WasmReturn(conditional));
|
||||
}
|
||||
|
||||
private void generateGetName(WasmFunction function, WasmGCCustomGeneratorContext context) {
|
||||
var classCls = context.classInfoProvider().getClassInfo("java.lang.Class");
|
||||
var thisVar = new WasmLocal(classCls.getType());
|
||||
function.add(thisVar);
|
||||
|
||||
var nameRef = new WasmStructGet(classCls.getStructure(), new WasmGetLocal(thisVar),
|
||||
context.classInfoProvider().getClassNameOffset());
|
||||
function.getBody().add(new WasmReturn(nameRef));
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.teavm.backend.wasm.generators.gc;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.teavm.backend.wasm.generate.gc.methods.WasmGCCustomGeneratorProvider;
|
||||
@ -28,11 +29,13 @@ public class WasmGCCustomGenerators implements WasmGCCustomGeneratorProvider {
|
||||
fillClass();
|
||||
fillStringPool();
|
||||
fillSystem();
|
||||
fillArray();
|
||||
}
|
||||
|
||||
private void fillClass() {
|
||||
var classGenerators = new ClassGenerators();
|
||||
generators.put(new MethodReference(Class.class, "isInstance", Object.class, boolean.class), classGenerators);
|
||||
generators.put(new MethodReference(Class.class, "getName", String.class), classGenerators);
|
||||
}
|
||||
|
||||
private void fillStringPool() {
|
||||
@ -50,6 +53,12 @@ public class WasmGCCustomGenerators implements WasmGCCustomGeneratorProvider {
|
||||
);
|
||||
}
|
||||
|
||||
private void fillArray() {
|
||||
var arrayGenerator = new ArrayGenerator();
|
||||
generators.put(new MethodReference(Array.class, "newInstanceImpl", Class.class, int.class, Object.class),
|
||||
arrayGenerator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WasmGCCustomGenerator get(MethodReference method) {
|
||||
return generators.get(method);
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.teavm.model.analysis;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.teavm.dependency.DependencyInfo;
|
||||
@ -34,6 +35,8 @@ public class ClassMetadataRequirements {
|
||||
"getDeclaringClass", Class.class);
|
||||
private static final MethodReference GET_ENCLOSING_CLASS_METHOD = new MethodReference(Class.class,
|
||||
"getEnclosingClass", Class.class);
|
||||
private static final MethodReference NEW_ARRAY = new MethodReference(Array.class,
|
||||
"newInstance", Class.class, int.class, Object.class);
|
||||
private static final ClassInfo EMPTY_INFO = new ClassInfo();
|
||||
private Map<ValueType, ClassInfo> requirements = new HashMap<>();
|
||||
|
||||
@ -85,6 +88,14 @@ public class ClassMetadataRequirements {
|
||||
requirements.computeIfAbsent(decodeType(className), k -> new ClassInfo()).enclosingClass = true;
|
||||
}
|
||||
}
|
||||
|
||||
var newArrayMethod = dependencyInfo.getMethod(NEW_ARRAY);
|
||||
if (newArrayMethod != null) {
|
||||
var classNames = newArrayMethod.getVariable(1).getClassValueNode().getTypes();
|
||||
for (var className : classNames) {
|
||||
requirements.computeIfAbsent(decodeType(className), k -> new ClassInfo()).newArray = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Info getInfo(String className) {
|
||||
@ -122,6 +133,7 @@ public class ClassMetadataRequirements {
|
||||
boolean enclosingClass;
|
||||
boolean superclass;
|
||||
boolean isAssignable;
|
||||
boolean newArray;
|
||||
|
||||
@Override
|
||||
public boolean name() {
|
||||
@ -152,6 +164,11 @@ public class ClassMetadataRequirements {
|
||||
public boolean isAssignable() {
|
||||
return isAssignable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean newArray() {
|
||||
return newArray;
|
||||
}
|
||||
}
|
||||
|
||||
public interface Info {
|
||||
@ -166,5 +183,7 @@ public class ClassMetadataRequirements {
|
||||
boolean superclass();
|
||||
|
||||
boolean isAssignable();
|
||||
|
||||
boolean newArray();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user