diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/ClassDependencyListener.java b/classlib/src/main/java/org/teavm/classlib/java/lang/ClassDependencyListener.java index 3731d985f..c493fb3c5 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/ClassDependencyListener.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/ClassDependencyListener.java @@ -34,6 +34,8 @@ public class ClassDependencyListener implements DependencyPlugin { }); break; case "getSimpleNameCacheLowLevel": + case "getCanonicalNameCacheLowLevel": + case "getNameCacheLowLevel": method.getResult().propagate(agent.getType("java.lang.String")); break; } diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java index 516e65f73..2159c490c 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java @@ -106,7 +106,21 @@ public class TClass extends TObject implements TAnnotatedElement { @Unmanaged public String getName() { if (PlatformDetector.isLowLevel()) { - return Platform.getName(platformClass); + String result = getNameCache(this); + if (result == null) { + result = Platform.getName(platformClass); + if (result == null) { + if (isArray()) { + TClass componentType = getComponentType(); + String componentName = componentType.getName(); + if (componentName != null) { + result = componentType.isArray() ? "[" + componentName : "[L" + componentName + ";"; + } + } + } + setNameCache(this, result); + } + return result; } else { if (name == null) { name = Platform.getName(platformClass); @@ -167,6 +181,27 @@ public class TClass extends TObject implements TAnnotatedElement { self.simpleNameCache = object; } + @DelegateTo("getNameCacheLowLevel") + private static String getNameCache(TClass self) { + return self.name; + } + + @Unmanaged + @PluggableDependency(ClassDependencyListener.class) + private static RuntimeObject getNameCacheLowLevel(RuntimeClass self) { + return self.nameCache; + } + + @DelegateTo("setNameCacheLowLevel") + private static void setNameCache(TClass self, String value) { + self.name = value; + } + + @Unmanaged + private static void setNameCacheLowLevel(RuntimeClass self, RuntimeObject object) { + self.nameCache = object; + } + public String getCanonicalName() { String result = getCanonicalNameCache(); if (result == null) { diff --git a/core/src/main/java/org/teavm/backend/c/generate/CNameProvider.java b/core/src/main/java/org/teavm/backend/c/generate/CNameProvider.java index 9db839354..72ec32233 100644 --- a/core/src/main/java/org/teavm/backend/c/generate/CNameProvider.java +++ b/core/src/main/java/org/teavm/backend/c/generate/CNameProvider.java @@ -64,7 +64,8 @@ public class CNameProvider extends LowLevelNameProvider { preserveFieldNames(RuntimeClass.class.getName(), "size", "flags", "tag", "canary", "name", "itemType", "arrayType", "isSupertypeOf", "init", "enumValues", "layout", "simpleName", "superinterfaceCount", - "superinterfaces", "simpleNameCache", "declaringClass", "enclosingClass", "canonicalName"); + "superinterfaces", "simpleNameCache", "declaringClass", "enclosingClass", "canonicalName", + "nameCache"); memberFieldNames.put(new FieldReference(RuntimeClass.class.getName(), "parent"), "superclass"); preserveFieldNames(RuntimeReference.class.getName(), "queue", "object", "next"); preserveFieldNames(RuntimeReferenceQueue.class.getName(), "first", "last"); diff --git a/core/src/main/java/org/teavm/backend/c/generate/ClassGenerator.java b/core/src/main/java/org/teavm/backend/c/generate/ClassGenerator.java index fd09f18b9..4d683e6ab 100644 --- a/core/src/main/java/org/teavm/backend/c/generate/ClassGenerator.java +++ b/core/src/main/java/org/teavm/backend/c/generate/ClassGenerator.java @@ -58,6 +58,7 @@ import org.teavm.model.MethodReader; import org.teavm.model.MethodReference; import org.teavm.model.Program; import org.teavm.model.ValueType; +import org.teavm.model.analysis.ClassMetadataRequirements; import org.teavm.model.classes.TagRegistry; import org.teavm.model.classes.VirtualTable; import org.teavm.model.classes.VirtualTableEntry; @@ -104,6 +105,7 @@ public class ClassGenerator { private MethodNodeCache astCache = EmptyMethodNodeCache.INSTANCE; private AstDependencyExtractor dependencyExtractor = new AstDependencyExtractor(); private List callSites; + private ClassMetadataRequirements metadataRequirements; public ClassGenerator(GenerationContext context, TagRegistry tagRegistry, Decompiler decompiler, CacheStatus cacheStatus) { @@ -111,6 +113,7 @@ public class ClassGenerator { this.tagRegistry = tagRegistry; this.decompiler = decompiler; this.cacheStatus = cacheStatus; + metadataRequirements = new ClassMetadataRequirements(context.getDependencies()); } public void setAstCache(MethodNodeCache astCache) { @@ -778,7 +781,10 @@ public class ClassGenerator { itemTypeExpr = "NULL"; } - int nameRef = context.getStringPool().getStringIndex(nameOfType(type)); + String metadataName = nameOfType(type); + String nameRef = metadataName != null + ? "(TeaVM_Object**) &TEAVM_GET_STRING(" + context.getStringPool().getStringIndex(metadataName) + ")" + : "NULL"; String superTypeFunction = context.getNames().forSupertypeFunction(type); ValueType arrayType = ValueType.arrayOf(type); @@ -802,7 +808,7 @@ public class ClassGenerator { codeWriter.println(".flags = " + flags + ","); codeWriter.println(".tag = " + tag + ","); codeWriter.println(".canary = 0,"); - codeWriter.println(".name = (TeaVM_Object**) &TEAVM_GET_STRING(" + nameRef + "),"); + codeWriter.println(".name = " + nameRef + ","); codeWriter.println(".simpleName = " + simpleName + ","); codeWriter.println(".arrayType = " + arrayTypeExpr + ","); codeWriter.println(".itemType = " + itemTypeExpr + ","); @@ -1168,7 +1174,7 @@ public class ClassGenerator { return true; } - public static String nameOfType(ValueType type) { + public String nameOfType(ValueType type) { if (type instanceof ValueType.Primitive) { switch (((ValueType.Primitive) type).getKind()) { case BOOLEAN: @@ -1191,16 +1197,28 @@ public class ClassGenerator { throw new AssertionError(); } } else if (type instanceof ValueType.Array) { - return type.toString().replace('/', '.'); + if (isArrayOfPrimitives(type)) { + return type.toString().replace('/', '.'); + } else { + return null; + } } else if (type == ValueType.VOID) { return "void"; } else if (type instanceof ValueType.Object) { - return ((ValueType.Object) type).getClassName(); + String name = ((ValueType.Object) type).getClassName(); + return metadataRequirements.getInfo(name).name() ? name : null; } else { throw new AssertionError(); } } + private static boolean isArrayOfPrimitives(ValueType type) { + while (type instanceof ValueType.Array) { + type = ((ValueType.Array) type).getItemType(); + } + return type instanceof ValueType.Primitive || type == ValueType.VOID; + } + private void generateIsSupertypeFunction(ValueType type) { String name = context.getNames().forSupertypeFunction(type); headerWriter.println("extern int32_t " + name + "(TeaVM_Class*);"); diff --git a/core/src/main/java/org/teavm/backend/c/intrinsic/PlatformClassMetadataIntrinsic.java b/core/src/main/java/org/teavm/backend/c/intrinsic/PlatformClassMetadataIntrinsic.java index e3f0ea8fa..82a4a7ea8 100644 --- a/core/src/main/java/org/teavm/backend/c/intrinsic/PlatformClassMetadataIntrinsic.java +++ b/core/src/main/java/org/teavm/backend/c/intrinsic/PlatformClassMetadataIntrinsic.java @@ -62,8 +62,11 @@ public class PlatformClassMetadataIntrinsic implements Intrinsic { printFieldAccess(context, invocation, SUPERCLASS_FIELD); break; case "getName": - context.writer().print("*"); + context.writer().print("("); printFieldAccess(context, invocation, NAME_FIELD); + context.writer().print(" ? *"); + printFieldAccess(context, invocation, NAME_FIELD); + context.writer().print(" : NULL)"); break; case "getSimpleName": context.writer().print("("); diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java b/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java index 555436473..e74416b9b 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java @@ -45,7 +45,6 @@ import org.teavm.common.ServiceRepository; import org.teavm.debugging.information.DebugInformationEmitter; import org.teavm.debugging.information.DummyDebugInformationEmitter; import org.teavm.dependency.DependencyInfo; -import org.teavm.dependency.MethodDependencyInfo; import org.teavm.diagnostics.Diagnostics; import org.teavm.model.ClassReader; import org.teavm.model.ClassReaderSource; @@ -57,6 +56,7 @@ import org.teavm.model.MethodDescriptor; import org.teavm.model.MethodReader; import org.teavm.model.MethodReference; import org.teavm.model.ValueType; +import org.teavm.model.analysis.ClassMetadataRequirements; import org.teavm.vm.RenderingException; import org.teavm.vm.TeaVMProgressFeedback; @@ -475,17 +475,17 @@ public class Renderer implements RenderingManager { return; } - Map classesRequiringName = findRequiredClassMetadata(); + ClassMetadataRequirements metadataRequirements = new ClassMetadataRequirements(context.getDependencyInfo()); int start = writer.getOffset(); try { writer.append("$rt_packages(["); - ObjectIntMap packageIndexes = generatePackageMetadata(classes, classesRequiringName); + ObjectIntMap packageIndexes = generatePackageMetadata(classes, metadataRequirements); writer.append("]);").newLine(); for (int i = 0; i < classes.size(); i += 50) { int j = Math.min(i + 50, classes.size()); - renderClassMetadataPortion(classes.subList(i, j), packageIndexes, classesRequiringName); + renderClassMetadataPortion(classes.subList(i, j), packageIndexes, metadataRequirements); } } catch (IOException e) { @@ -496,7 +496,7 @@ public class Renderer implements RenderingManager { } private void renderClassMetadataPortion(List classes, ObjectIntMap packageIndexes, - Map metadataRequirements) throws IOException { + ClassMetadataRequirements metadataRequirements) throws IOException { writer.append("$rt_metadata(["); boolean first = true; for (PreparedClass cls : classes) { @@ -507,8 +507,8 @@ public class Renderer implements RenderingManager { debugEmitter.emitClass(cls.getName()); writer.appendClass(cls.getName()).append(",").ws(); - RequiredClassMetadata requiredMetadata = metadataRequirements.get(cls.getName()); - if (requiredMetadata != null && requiredMetadata.name) { + ClassMetadataRequirements.Info requiredMetadata = metadataRequirements.getInfo(cls.getName()); + if (requiredMetadata.name()) { String className = cls.getName(); int dotIndex = className.lastIndexOf('.') + 1; String packageName = className.substring(0, dotIndex); @@ -540,24 +540,24 @@ public class Renderer implements RenderingManager { writer.append(ElementModifier.pack(cls.getClassHolder().getModifiers())).append(',').ws(); writer.append(cls.getClassHolder().getLevel().ordinal()).append(',').ws(); - if (requiredMetadata == null || !(requiredMetadata.enclosingClass - || requiredMetadata.declaringClass || requiredMetadata.simpleName)) { + if (!requiredMetadata.enclosingClass() && !requiredMetadata.declaringClass() + && !requiredMetadata.simpleName()) { writer.append("0"); } else { writer.append('['); - if (requiredMetadata.enclosingClass && cls.getClassHolder().getOwnerName() != null) { + if (requiredMetadata.enclosingClass() && cls.getClassHolder().getOwnerName() != null) { writer.appendClass(cls.getClassHolder().getOwnerName()); } else { writer.append('0'); } writer.append(','); - if (requiredMetadata.declaringClass && cls.getClassHolder().getDeclaringClassName() != null) { + if (requiredMetadata.declaringClass() && cls.getClassHolder().getDeclaringClassName() != null) { writer.appendClass(cls.getClassHolder().getDeclaringClassName()); } else { writer.append('0'); } writer.append(','); - if (requiredMetadata.simpleName && cls.getClassHolder().getSimpleName() != null) { + if (requiredMetadata.simpleName() && cls.getClassHolder().getSimpleName() != null) { writer.append("\"").append(RenderingUtil.escapeString(cls.getClassHolder().getSimpleName())) .append("\""); } else { @@ -590,13 +590,13 @@ public class Renderer implements RenderingManager { } private ObjectIntMap generatePackageMetadata(List classes, - Map metadataRequirements) throws IOException { + ClassMetadataRequirements metadataRequirements) throws IOException { PackageNode root = new PackageNode(null); for (PreparedClass classNode : classes) { String className = classNode.getName(); - RequiredClassMetadata requiredMetadata = metadataRequirements.get(className); - if (requiredMetadata == null || !requiredMetadata.name) { + ClassMetadataRequirements.Info requiredMetadata = metadataRequirements.getInfo(className); + if (!requiredMetadata.name()) { continue; } @@ -655,65 +655,6 @@ public class Renderer implements RenderingManager { } } - private Map findRequiredClassMetadata() { - Map requirements = new HashMap<>(); - - MethodDependencyInfo getNameMethod = context.getDependencyInfo().getMethod( - new MethodReference(Class.class, "getName", String.class)); - if (getNameMethod != null) { - addClassesRequiringName(requirements, getNameMethod.getVariable(0).getClassValueNode().getTypes()); - } - - MethodDependencyInfo getSimpleNameMethod = context.getDependencyInfo().getMethod( - new MethodReference(Class.class, "getSimpleName", String.class)); - if (getSimpleNameMethod != null) { - String[] classNames = getSimpleNameMethod.getVariable(0).getClassValueNode().getTypes(); - addClassesRequiringName(requirements, classNames); - for (String className : classNames) { - RequiredClassMetadata requiredMetadata = requirements.computeIfAbsent(className, - k -> new RequiredClassMetadata()); - requiredMetadata.simpleName = true; - requiredMetadata.enclosingClass = true; - } - } - - MethodDependencyInfo getDeclaringClassMethod = context.getDependencyInfo().getMethod( - new MethodReference(Class.class, "getDeclaringClass", Class.class)); - if (getDeclaringClassMethod != null) { - String[] classNames = getDeclaringClassMethod.getVariable(0).getClassValueNode().getTypes(); - for (String className : classNames) { - requirements.computeIfAbsent(className, k -> new RequiredClassMetadata()).declaringClass = true; - } - } - - MethodDependencyInfo getEnclosingClassMethod = context.getDependencyInfo().getMethod( - new MethodReference(Class.class, "getEnclosingClass", Class.class)); - if (getEnclosingClassMethod != null) { - String[] classNames = getEnclosingClassMethod.getVariable(0).getClassValueNode().getTypes(); - for (String className : classNames) { - requirements.computeIfAbsent(className, k -> new RequiredClassMetadata()).enclosingClass = true; - } - } - - return requirements; - } - - private void addClassesRequiringName(Map 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 RequiredClassMetadata()).name = true; - } - } - private void collectMethodsToCopyFromInterfaces(ClassReader cls, List targetList) { Set implementedMethods = new HashSet<>(); implementedMethods.addAll(targetList.stream().map(method -> method.getDescriptor()) @@ -1217,11 +1158,4 @@ public class Renderer implements RenderingManager { private boolean isVirtual(MethodReference method) { return context.isVirtual(method); } - - static class RequiredClassMetadata { - boolean name; - boolean simpleName; - boolean declaringClass; - boolean enclosingClass; - } } diff --git a/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java b/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java index 3859c37ef..8103d9a62 100644 --- a/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java +++ b/core/src/main/java/org/teavm/backend/wasm/generate/WasmClassGenerator.java @@ -72,6 +72,7 @@ public class WasmClassGenerator { DataPrimitives.INT, /* tag */ DataPrimitives.INT, /* canary */ DataPrimitives.ADDRESS, /* name */ + DataPrimitives.ADDRESS, /* name cache */ DataPrimitives.ADDRESS, /* item type */ DataPrimitives.ADDRESS, /* array type */ DataPrimitives.ADDRESS, /* declaring class */ @@ -96,16 +97,16 @@ public class WasmClassGenerator { private static final int CLASS_TAG = 3; private static final int CLASS_CANARY = 4; private static final int CLASS_NAME = 5; - private static final int CLASS_ITEM_TYPE = 6; - private static final int CLASS_ARRAY_TYPE = 7; - private static final int CLASS_DECLARING_CLASS = 8; - private static final int CLASS_ENCLOSING_CLASS = 9; - private static final int CLASS_IS_INSTANCE = 10; - private static final int CLASS_INIT = 11; - private static final int CLASS_PARENT = 12; - private static final int CLASS_ENUM_VALUES = 15; - private static final int CLASS_LAYOUT = 16; - private static final int CLASS_SIMPLE_NAME = 17; + private static final int CLASS_ITEM_TYPE = 7; + private static final int CLASS_ARRAY_TYPE = 8; + private static final int CLASS_DECLARING_CLASS = 9; + private static final int CLASS_ENCLOSING_CLASS = 10; + private static final int CLASS_IS_INSTANCE = 11; + private static final int CLASS_INIT = 12; + private static final int CLASS_PARENT = 13; + private static final int CLASS_ENUM_VALUES = 16; + private static final int CLASS_LAYOUT = 17; + private static final int CLASS_SIMPLE_NAME = 18; public WasmClassGenerator(ClassReaderSource processedClassSource, ClassReaderSource classSource, VirtualTableProvider vtableProvider, TagRegistry tagRegistry, BinaryWriter binaryWriter, diff --git a/core/src/main/java/org/teavm/model/analysis/ClassMetadataRequirements.java b/core/src/main/java/org/teavm/model/analysis/ClassMetadataRequirements.java new file mode 100644 index 000000000..c3742d3f4 --- /dev/null +++ b/core/src/main/java/org/teavm/model/analysis/ClassMetadataRequirements.java @@ -0,0 +1,129 @@ +/* + * Copyright 2019 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.model.analysis; + +import java.util.HashMap; +import java.util.Map; +import org.teavm.dependency.DependencyInfo; +import org.teavm.dependency.MethodDependencyInfo; +import org.teavm.model.MethodReference; + +public class ClassMetadataRequirements { + private static final MethodReference GET_NAME_METHOD = new MethodReference(Class.class, "getName", String.class); + private static final MethodReference GET_SIMPLE_NAME_METHOD = new MethodReference(Class.class, + "getSimpleName", String.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 requirements = new HashMap<>(); + + public ClassMetadataRequirements(DependencyInfo dependencyInfo) { + MethodDependencyInfo getNameMethod = dependencyInfo.getMethod(GET_NAME_METHOD); + if (getNameMethod != null) { + addClassesRequiringName(requirements, getNameMethod.getVariable(0).getClassValueNode().getTypes()); + } + + MethodDependencyInfo getSimpleNameMethod = dependencyInfo.getMethod(GET_SIMPLE_NAME_METHOD); + if (getSimpleNameMethod != null) { + String[] classNames = getSimpleNameMethod.getVariable(0).getClassValueNode().getTypes(); + addClassesRequiringName(requirements, classNames); + for (String className : classNames) { + ClassInfo classInfo = requirements.computeIfAbsent(className, k -> new ClassInfo()); + classInfo.simpleName = true; + classInfo.enclosingClass = true; + } + } + + MethodDependencyInfo getDeclaringClassMethod = dependencyInfo.getMethod(GET_DECLARING_CLASS_METHOD); + if (getDeclaringClassMethod != null) { + String[] classNames = getDeclaringClassMethod.getVariable(0).getClassValueNode().getTypes(); + for (String className : classNames) { + requirements.computeIfAbsent(className, k -> new ClassInfo()).declaringClass = true; + } + } + + MethodDependencyInfo getEnclosingClassMethod = dependencyInfo.getMethod(GET_ENCLOSING_CLASS_METHOD); + if (getEnclosingClassMethod != null) { + String[] classNames = getEnclosingClassMethod.getVariable(0).getClassValueNode().getTypes(); + for (String className : classNames) { + requirements.computeIfAbsent(className, k -> new ClassInfo()).enclosingClass = true; + } + } + } + + public Info getInfo(String className) { + ClassInfo result = requirements.get(className); + if (result == null) { + result = EMPTY_INFO; + } + return result; + } + + private void addClassesRequiringName(Map 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; + } + } + + static class ClassInfo implements Info { + boolean name; + boolean simpleName; + boolean declaringClass; + boolean enclosingClass; + + @Override + public boolean name() { + return name; + } + + @Override + public boolean simpleName() { + return simpleName; + } + + @Override + public boolean declaringClass() { + return declaringClass; + } + + @Override + public boolean enclosingClass() { + return enclosingClass; + } + } + + public interface Info { + boolean name(); + + boolean simpleName(); + + boolean declaringClass(); + + boolean enclosingClass(); + } +} diff --git a/core/src/main/java/org/teavm/runtime/GC.java b/core/src/main/java/org/teavm/runtime/GC.java index acd9644b5..e96feda9d 100644 --- a/core/src/main/java/org/teavm/runtime/GC.java +++ b/core/src/main/java/org/teavm/runtime/GC.java @@ -208,6 +208,9 @@ public final class GC { if (cls.canonicalName != null) { mark(cls.canonicalName); } + if (cls.nameCache != null) { + mark(cls.nameCache); + } classPtr = classPtr.add(Address.sizeOf()); } @@ -582,6 +585,9 @@ public final class GC { if (cls.canonicalName != null) { cls.canonicalName = updatePointer(cls.canonicalName.toAddress()).toStructure(); } + if (cls.nameCache != null) { + cls.nameCache = updatePointer(cls.nameCache.toAddress()).toStructure(); + } classPtr = classPtr.add(Address.sizeOf()); } } diff --git a/core/src/main/java/org/teavm/runtime/RuntimeClass.java b/core/src/main/java/org/teavm/runtime/RuntimeClass.java index 8bff02a36..ae6fede67 100644 --- a/core/src/main/java/org/teavm/runtime/RuntimeClass.java +++ b/core/src/main/java/org/teavm/runtime/RuntimeClass.java @@ -48,6 +48,7 @@ public class RuntimeClass extends RuntimeObject { public int tag; public int canary; public RuntimeObjectPtr name; + public RuntimeObject nameCache; public RuntimeClass itemType; public RuntimeClass arrayType; public RuntimeClass declaringClass; diff --git a/core/src/main/resources/org/teavm/backend/c/core.h b/core/src/main/resources/org/teavm/backend/c/core.h index de53f1ec4..f706f6dc2 100644 --- a/core/src/main/resources/org/teavm/backend/c/core.h +++ b/core/src/main/resources/org/teavm/backend/c/core.h @@ -28,6 +28,7 @@ typedef struct TeaVM_Class { int32_t tag; int32_t canary; TeaVM_Object** name; + TeaVM_Object* nameCache; struct TeaVM_Class* itemType; struct TeaVM_Class* arrayType; struct TeaVM_Class* declaringClass;