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

View File

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