wasm gc: avoid generation of unnecessary supertype functions

This commit is contained in:
Alexey Andreev 2024-08-02 15:03:29 +02:00
parent 8e483245f5
commit 8d276f2efd
2 changed files with 56 additions and 25 deletions

View File

@ -157,10 +157,13 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
function.getBody().addAll(initializerFunctionStatements);
initializerFunctionStatements.clear();
for (var classInfo : classInfoMap.values()) {
var supertypeFunction = supertypeGenerator.getIsSupertypeFunction(classInfo.getValueType());
supertypeFunction.setReferenced(true);
function.getBody().add(setClassField(classInfo, classSupertypeFunctionOffset,
new WasmFunctionReference(supertypeFunction)));
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)));
}
function.getBody().add(setClassField(classInfo, CLASS_FIELD_OFFSET,
new WasmGetGlobal(classClass.pointer)));
if (classInfo.initializerPointer != null) {
@ -265,9 +268,11 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
default:
throw new IllegalArgumentException();
}
var req = metadataRequirements.getInfo(type);
var name = req != null && req.name() ? ReflectionUtil.typeName(type.getKind()) : null;
target.add(fillPrimitiveClass(
classInfo.pointer,
ReflectionUtil.typeName(type.getKind()),
name,
kind
));
};
@ -401,10 +406,13 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
}
private WasmExpression fillPrimitiveClass(WasmGlobal global, String name, int kind) {
var str = name != null
? new WasmGetGlobal(strings.getStringConstant(name).global)
: new WasmNullConstant(standardClasses.stringClass().getType());
return new WasmCall(
getCreatePrimitiveClassFunction(),
new WasmGetGlobal(global),
new WasmGetGlobal(strings.getStringConstant(name).global),
str,
new WasmInt32Constant(kind)
);
}

View File

@ -20,6 +20,7 @@ import java.util.Map;
import org.teavm.dependency.DependencyInfo;
import org.teavm.dependency.MethodDependencyInfo;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
public class ClassMetadataRequirements {
private static final MethodReference GET_NAME_METHOD = new MethodReference(Class.class, "getName", String.class);
@ -27,12 +28,14 @@ public class ClassMetadataRequirements {
"getSimpleName", String.class);
private static final MethodReference GET_SUPERCLASS_METHOD = new MethodReference(Class.class, "getSuperclass",
Class.class);
private static final MethodReference IS_ASSIGNABLE_METHOD = new MethodReference(Class.class, "isAssignableFrom",
Class.class, boolean.class);
private static final MethodReference GET_DECLARING_CLASS_METHOD = new MethodReference(Class.class,
"getDeclaringClass", Class.class);
private static final MethodReference GET_ENCLOSING_CLASS_METHOD = new MethodReference(Class.class,
"getEnclosingClass", Class.class);
private static final ClassInfo EMPTY_INFO = new ClassInfo();
private Map<String, ClassInfo> requirements = new HashMap<>();
private Map<ValueType, ClassInfo> requirements = new HashMap<>();
public ClassMetadataRequirements(DependencyInfo dependencyInfo) {
MethodDependencyInfo getNameMethod = dependencyInfo.getMethod(GET_NAME_METHOD);
@ -45,7 +48,7 @@ public class ClassMetadataRequirements {
String[] classNames = getSimpleNameMethod.getVariable(0).getClassValueNode().getTypes();
addClassesRequiringName(requirements, classNames);
for (String className : classNames) {
ClassInfo classInfo = requirements.computeIfAbsent(className, k -> new ClassInfo());
ClassInfo classInfo = requirements.computeIfAbsent(decodeType(className), k -> new ClassInfo());
classInfo.simpleName = true;
classInfo.enclosingClass = true;
}
@ -53,9 +56,17 @@ public class ClassMetadataRequirements {
var getSuperclassMethod = dependencyInfo.getMethod(GET_SUPERCLASS_METHOD);
if (getSuperclassMethod != null) {
String[] classNames = getSuperclassMethod.getVariable(0).getClassValueNode().getTypes();
for (String className : classNames) {
requirements.computeIfAbsent(className, k -> new ClassInfo()).declaringClass = true;
var classNames = getSuperclassMethod.getVariable(0).getClassValueNode().getTypes();
for (var className : classNames) {
requirements.computeIfAbsent(decodeType(className), k -> new ClassInfo()).declaringClass = true;
}
}
var isAssignableMethod = dependencyInfo.getMethod(IS_ASSIGNABLE_METHOD);
if (isAssignableMethod != null) {
var classNames = getSuperclassMethod.getVariable(0).getClassValueNode().getTypes();
for (var className : classNames) {
requirements.computeIfAbsent(decodeType(className), k -> new ClassInfo()).isAssignable = true;
}
}
@ -63,7 +74,7 @@ public class ClassMetadataRequirements {
if (getDeclaringClassMethod != null) {
String[] classNames = getDeclaringClassMethod.getVariable(0).getClassValueNode().getTypes();
for (String className : classNames) {
requirements.computeIfAbsent(className, k -> new ClassInfo()).declaringClass = true;
requirements.computeIfAbsent(decodeType(className), k -> new ClassInfo()).declaringClass = true;
}
}
@ -71,12 +82,16 @@ public class ClassMetadataRequirements {
if (getEnclosingClassMethod != null) {
String[] classNames = getEnclosingClassMethod.getVariable(0).getClassValueNode().getTypes();
for (String className : classNames) {
requirements.computeIfAbsent(className, k -> new ClassInfo()).enclosingClass = true;
requirements.computeIfAbsent(decodeType(className), k -> new ClassInfo()).enclosingClass = true;
}
}
}
public Info getInfo(String className) {
return getInfo(ValueType.object(className));
}
public Info getInfo(ValueType className) {
ClassInfo result = requirements.get(className);
if (result == null) {
result = EMPTY_INFO;
@ -84,19 +99,19 @@ public class ClassMetadataRequirements {
return result;
}
private void addClassesRequiringName(Map<String, ClassInfo> target, String[] source) {
private void addClassesRequiringName(Map<ValueType, ClassInfo> target, String[] source) {
for (String typeName : source) {
if (typeName.startsWith("[")) {
if (!typeName.endsWith(";")) {
continue;
}
int index = 0;
while (typeName.charAt(index) == '[') {
++index;
}
typeName = typeName.substring(index, typeName.length() - 1).replace('/', '.');
}
target.computeIfAbsent(typeName, k -> new ClassInfo()).name = true;
target.computeIfAbsent(decodeType(typeName), k -> new ClassInfo()).name = true;
}
}
private ValueType decodeType(String typeName) {
if (typeName.startsWith("[")) {
return ValueType.parseIfPossible(typeName);
} else if (typeName.startsWith("~")) {
return ValueType.parseIfPossible(typeName.substring(1));
} else {
return ValueType.object(typeName);
}
}
@ -106,6 +121,7 @@ public class ClassMetadataRequirements {
boolean declaringClass;
boolean enclosingClass;
boolean superclass;
boolean isAssignable;
@Override
public boolean name() {
@ -131,6 +147,11 @@ public class ClassMetadataRequirements {
public boolean superclass() {
return superclass;
}
@Override
public boolean isAssignable() {
return isAssignable;
}
}
public interface Info {
@ -143,5 +164,7 @@ public class ClassMetadataRequirements {
boolean enclosingClass();
boolean superclass();
boolean isAssignable();
}
}