wasm gc: implement Class.getSuperclass and Object.clone, fix issue with resource maps

This commit is contained in:
Alexey Andreev 2024-09-09 14:23:58 +02:00
parent fe0304ee67
commit 349ed8fc2d
13 changed files with 139 additions and 25 deletions

View File

@ -344,7 +344,7 @@ public class TObject {
@PluggableDependency(ObjectDependencyPlugin.class) @PluggableDependency(ObjectDependencyPlugin.class)
protected Object clone() throws TCloneNotSupportedException { protected Object clone() throws TCloneNotSupportedException {
if (PlatformDetector.isWebAssemblyGC()) { if (PlatformDetector.isWebAssemblyGC()) {
throw new TCloneNotSupportedException(); return cloneObject();
} }
if (!(this instanceof TCloneable) && Platform.getPlatformObject(this) if (!(this instanceof TCloneable) && Platform.getPlatformObject(this)
.getPlatformClass().getMetadata().getArrayItem() == null) { .getPlatformClass().getMetadata().getArrayItem() == null) {
@ -355,6 +355,8 @@ public class TObject {
return result; return result;
} }
private native TObject cloneObject();
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static RuntimeObject cloneLowLevel(RuntimeObject self) { private static RuntimeObject cloneLowLevel(RuntimeObject self) {
RuntimeClass cls = RuntimeClass.getClass(self); RuntimeClass cls = RuntimeClass.getClass(self);

View File

@ -98,7 +98,8 @@ public class WasmGCDependencies {
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "aiiobe", ArrayIndexOutOfBoundsException.class)) analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "aiiobe", ArrayIndexOutOfBoundsException.class))
.use(); .use();
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "cce", ClassCastException.class)).use(); analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "cce", ClassCastException.class)).use();
analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "cnse", CloneNotSupportedException.class)).use(); analyzer.linkMethod(new MethodReference(WasmGCSupport.class, "throwCloneNotSupportedException",
void.class)).use();
} }
private void contributeInitializerUtils() { private void contributeInitializerUtils() {

View File

@ -34,6 +34,7 @@ import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
class WasmGCVirtualTableBuilder { class WasmGCVirtualTableBuilder {
private static final MethodReference CLONE_METHOD = new MethodReference(Object.class, "clone", Object.class);
ListableClassReaderSource classes; ListableClassReaderSource classes;
Collection<MethodReference> methodsAtCallSites; Collection<MethodReference> methodsAtCallSites;
Predicate<MethodReference> isVirtual; Predicate<MethodReference> isVirtual;
@ -170,7 +171,7 @@ class WasmGCVirtualTableBuilder {
if (method.getProgram() == null && !method.hasModifier(ElementModifier.NATIVE)) { if (method.getProgram() == null && !method.hasModifier(ElementModifier.NATIVE)) {
continue; continue;
} }
if (!isVirtual.test(method.getReference())) { if (!isVirtual.test(method.getReference()) && !method.getReference().equals(CLONE_METHOD)) {
continue; continue;
} }
table.currentImplementors.put(method.getDescriptor(), method.getReference()); table.currentImplementors.put(method.getDescriptor(), method.getReference());

View File

@ -82,6 +82,7 @@ public class WasmGCDeclarationsGenerator {
classGenerator = new WasmGCClassGenerator( classGenerator = new WasmGCClassGenerator(
module, module,
classes, classes,
hierarchy,
functionTypes, functionTypes,
tags, tags,
metadataRequirements, metadataRequirements,

View File

@ -67,8 +67,11 @@ 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.WasmSignedType;
import org.teavm.backend.wasm.model.expression.WasmStructGet; import org.teavm.backend.wasm.model.expression.WasmStructGet;
import org.teavm.backend.wasm.model.expression.WasmStructNew;
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.runtime.WasmGCSupport;
import org.teavm.model.ClassHierarchy;
import org.teavm.model.ClassReaderSource; import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementModifier; import org.teavm.model.ElementModifier;
import org.teavm.model.FieldReference; import org.teavm.model.FieldReference;
@ -93,6 +96,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
private final WasmModule module; private final WasmModule module;
private ClassReaderSource classSource; private ClassReaderSource classSource;
private ClassHierarchy hierarchy;
private WasmFunctionTypes functionTypes; private WasmFunctionTypes functionTypes;
private TagRegistry tagRegistry; private TagRegistry tagRegistry;
private ClassMetadataRequirements metadataRequirements; private ClassMetadataRequirements metadataRequirements;
@ -129,6 +133,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
private int virtualTableFieldOffset; private int virtualTableFieldOffset;
private int arrayLengthOffset = -1; private int arrayLengthOffset = -1;
private int arrayGetOffset = -1; private int arrayGetOffset = -1;
private int cloneOffset = -1;
private WasmStructure arrayVirtualTableStruct; private WasmStructure arrayVirtualTableStruct;
private WasmFunction arrayGetObjectFunction; private WasmFunction arrayGetObjectFunction;
private WasmFunction arrayLengthObjectFunction; private WasmFunction arrayLengthObjectFunction;
@ -137,6 +142,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
private List<WasmStructure> nonInitializedStructures = new ArrayList<>(); private List<WasmStructure> nonInitializedStructures = new ArrayList<>();
public WasmGCClassGenerator(WasmModule module, ClassReaderSource classSource, public WasmGCClassGenerator(WasmModule module, ClassReaderSource classSource,
ClassHierarchy hierarchy,
WasmFunctionTypes functionTypes, TagRegistry tagRegistry, WasmFunctionTypes functionTypes, TagRegistry tagRegistry,
ClassMetadataRequirements metadataRequirements, WasmGCVirtualTableProvider virtualTables, ClassMetadataRequirements metadataRequirements, WasmGCVirtualTableProvider virtualTables,
BaseWasmFunctionRepository functionProvider, WasmGCNameProvider names, BaseWasmFunctionRepository functionProvider, WasmGCNameProvider names,
@ -144,6 +150,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
List<WasmGCCustomTypeMapperFactory> customTypeMapperFactories) { List<WasmGCCustomTypeMapperFactory> customTypeMapperFactories) {
this.module = module; this.module = module;
this.classSource = classSource; this.classSource = classSource;
this.hierarchy = hierarchy;
this.functionTypes = functionTypes; this.functionTypes = functionTypes;
this.tagRegistry = tagRegistry; this.tagRegistry = tagRegistry;
this.metadataRequirements = metadataRequirements; this.metadataRequirements = metadataRequirements;
@ -359,6 +366,12 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
return classEnclosingClassOffset; return classEnclosingClassOffset;
} }
@Override
public int getClassParentOffset() {
standardClasses.classClass().getStructure().init();
return classParentOffset;
}
@Override @Override
public int getClassNameOffset() { public int getClassNameOffset() {
standardClasses.classClass().getStructure().init(); standardClasses.classClass().getStructure().init();
@ -383,6 +396,12 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
return virtualTableFieldOffset; return virtualTableFieldOffset;
} }
@Override
public int getCloneOffset() {
standardClasses.classClass().getStructure().init();
return cloneOffset;
}
private void initPrimitiveClass(WasmGCClassInfo classInfo, ValueType.Primitive type) { private void initPrimitiveClass(WasmGCClassInfo classInfo, ValueType.Primitive type) {
classInfo.initializer = target -> { classInfo.initializer = target -> {
int kind; int kind;
@ -469,6 +488,17 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
var owner = getClassInfo(cls.getOwnerName()); var owner = getClassInfo(cls.getOwnerName());
target.add(setClassField(classInfo, classEnclosingClassOffset, new WasmGetGlobal(owner.pointer))); target.add(setClassField(classInfo, classEnclosingClassOffset, new WasmGetGlobal(owner.pointer)));
} }
if (metadataReq.cloneMethod()) {
WasmFunction cloneFunction;
if (hierarchy.isSuperType("java.lang.Cloneable", name, false)) {
cloneFunction = generateCloneFunction(classInfo, name);
} else {
cloneFunction = functionProvider.forStaticMethod(new MethodReference(
WasmGCSupport.class, "throwCloneNotSupportedException", void.class));
}
cloneFunction.setReferenced(true);
target.add(setClassField(classInfo, cloneOffset, new WasmFunctionReference(cloneFunction)));
}
} }
if (virtualTable != null && virtualTable.isConcrete()) { if (virtualTable != null && virtualTable.isConcrete()) {
fillVirtualTableMethods(target, classStructure, classInfo.pointer, virtualTable); fillVirtualTableMethods(target, classStructure, classInfo.pointer, virtualTable);
@ -481,6 +511,38 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
}; };
} }
private WasmFunction generateCloneFunction(WasmGCClassInfo classInfo, String className) {
var function = new WasmFunction(functionTypes.of(standardClasses.objectClass().getType(),
standardClasses.objectClass().getType()));
function.setName(names.topLevel(className + "@clone"));
module.functions.add(function);
var objLocal = new WasmLocal(standardClasses.objectClass().getType(), "obj");
var castObjLocal = new WasmLocal(classInfo.getType(), "castObj");
function.add(objLocal);
function.add(castObjLocal);
var cast = new WasmCast(new WasmGetLocal(objLocal), classInfo.getStructure().getReference());
function.getBody().add(new WasmSetLocal(castObjLocal, cast));
var copy = new WasmStructNew(classInfo.structure);
for (var i = 0; i < classInfo.structure.getFields().size(); ++i) {
if (i == MONITOR_FIELD_OFFSET) {
copy.getInitializers().add(new WasmNullConstant(WasmType.Reference.EQ));
} else {
var fieldType = classInfo.structure.getFields().get(i).getType();
var getExpr = new WasmStructGet(classInfo.structure, new WasmGetLocal(castObjLocal), i);
if (fieldType instanceof WasmStorageType.Packed) {
getExpr.setSignedType(WasmSignedType.UNSIGNED);
}
copy.getInitializers().add(getExpr);
}
}
function.getBody().add(new WasmReturn(copy));
return function;
}
private void fillVirtualTableMethods(List<WasmExpression> target, WasmStructure structure, WasmGlobal global, private void fillVirtualTableMethods(List<WasmExpression> target, WasmStructure structure, WasmGlobal global,
WasmGCVirtualTable virtualTable) { WasmGCVirtualTable virtualTable) {
var usedVt = virtualTable.getFirstUsed(); var usedVt = virtualTable.getFirstUsed();
@ -500,15 +562,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
var itemType = ((ValueType.Array) type).getItemType(); var itemType = ((ValueType.Array) type).getItemType();
for (var entry : virtualTable.getEntries()) { for (var entry : virtualTable.getEntries()) {
if (entry.getMethod().getName().equals("clone")) { fillVirtualTableEntry(target, global, structure, virtualTable, entry);
var function = generateArrayCloneMethod(objectStructure, itemType);
function.setReferenced(true);
var ref = new WasmFunctionReference(function);
var fieldIndex = virtualTableFieldOffset + entry.getIndex();
target.add(new WasmStructSet(structure, new WasmGetGlobal(global), fieldIndex, ref));
} else {
fillVirtualTableEntry(target, global, structure, virtualTable, entry);
}
} }
var info = metadataRequirements.getInfo(type); var info = metadataRequirements.getInfo(type);
@ -773,7 +827,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
var classField = new WasmField(standardClasses.classClass().getType().asStorage()); var classField = new WasmField(standardClasses.classClass().getType().asStorage());
classField.setName(names.forMemberField(FAKE_CLASS_FIELD)); classField.setName(names.forMemberField(FAKE_CLASS_FIELD));
fields.add(classField); fields.add(classField);
var monitorField = new WasmField(WasmType.Reference.ANY.asStorage()); var monitorField = new WasmField(WasmType.Reference.EQ.asStorage());
monitorField.setName(names.forMemberField(FAKE_MONITOR_FIELD)); monitorField.setName(names.forMemberField(FAKE_MONITOR_FIELD));
fields.add(monitorField); fields.add(monitorField);
} }
@ -836,6 +890,12 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
new WasmGetGlobal(itemTypeInfo.pointer) new WasmGetGlobal(itemTypeInfo.pointer)
)); ));
fillArrayVirtualTableMethods(classInfo.getValueType(), target, classInfo.pointer, classInfo.structure); fillArrayVirtualTableMethods(classInfo.getValueType(), target, classInfo.pointer, classInfo.structure);
var metadataReq = metadataRequirements.getInfo(type);
if (metadataReq.cloneMethod()) {
var cloneFunction = generateArrayCloneMethod(classInfo.structure, type.getItemType());
cloneFunction.setReferenced(true);
target.add(setClassField(classInfo, cloneOffset, new WasmFunctionReference(cloneFunction)));
}
}; };
} }
@ -983,7 +1043,10 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
classNameOffset = fields.size(); classNameOffset = fields.size();
fields.add(createClassField(standardClasses.stringClass().getType().asStorage(), "name")); fields.add(createClassField(standardClasses.stringClass().getType().asStorage(), "name"));
classSimpleNameOffset = fields.size(); classSimpleNameOffset = fields.size();
fields.add(createClassField(standardClasses.stringClass().getType().asStorage(), "simpleNAme")); fields.add(createClassField(standardClasses.stringClass().getType().asStorage(), "simpleName"));
cloneOffset = fields.size();
fields.add(createClassField(functionTypes.of(standardClasses.objectClass().getType(),
standardClasses.objectClass().getType()).getReference().asStorage(), "clone"));
virtualTableFieldOffset = fields.size(); virtualTableFieldOffset = fields.size();
} }
} }
@ -1146,7 +1209,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
standardClasses.classClass().getStructure(), standardClasses.classClass().getStructure(),
new WasmGetLocal(targetVar), new WasmGetLocal(targetVar),
classParentOffset, classParentOffset,
new WasmGetGlobal(standardClasses.classClass().pointer) new WasmGetGlobal(standardClasses.objectClass().pointer)
)); ));
return function; return function;
} }

View File

@ -42,6 +42,8 @@ public interface WasmGCClassInfoProvider {
int getClassEnclosingClassOffset(); int getClassEnclosingClassOffset();
int getClassParentOffset();
int getNewArrayFunctionOffset(); int getNewArrayFunctionOffset();
int getClassNameOffset(); int getClassNameOffset();
@ -52,6 +54,8 @@ public interface WasmGCClassInfoProvider {
int getArrayLengthOffset(); int getArrayLengthOffset();
int getCloneOffset();
default WasmGCClassInfo getClassInfo(String name) { default WasmGCClassInfo getClassInfo(String name) {
return getClassInfo(ValueType.object(name)); return getClassInfo(ValueType.object(name));
} }

View File

@ -40,6 +40,14 @@ public class ClassIntrinsic implements WasmGCIntrinsic {
result.setLocation(invocation.getLocation()); result.setLocation(invocation.getLocation());
return result; return result;
} }
case "getSuperclass": {
var cls = context.generate(invocation.getArguments().get(0));
var clsStruct = context.classInfoProvider().getClassInfo("java.lang.Class").getStructure();
var result = new WasmStructGet(clsStruct, cls,
context.classInfoProvider().getClassParentOffset());
result.setLocation(invocation.getLocation());
return result;
}
case "getNameImpl": case "getNameImpl":
return generateGetName(invocation, context); return generateGetName(invocation, context);
case "setNameImpl": case "setNameImpl":

View File

@ -20,6 +20,7 @@ import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
import org.teavm.backend.wasm.model.WasmType; import org.teavm.backend.wasm.model.WasmType;
import org.teavm.backend.wasm.model.expression.WasmBlock; import org.teavm.backend.wasm.model.expression.WasmBlock;
import org.teavm.backend.wasm.model.expression.WasmBranch; import org.teavm.backend.wasm.model.expression.WasmBranch;
import org.teavm.backend.wasm.model.expression.WasmCallReference;
import org.teavm.backend.wasm.model.expression.WasmCast; import org.teavm.backend.wasm.model.expression.WasmCast;
import org.teavm.backend.wasm.model.expression.WasmDrop; import org.teavm.backend.wasm.model.expression.WasmDrop;
import org.teavm.backend.wasm.model.expression.WasmExpression; import org.teavm.backend.wasm.model.expression.WasmExpression;
@ -52,6 +53,8 @@ public class ObjectIntrinsic implements WasmGCIntrinsic {
return generateGetIdentity(invocation, context); return generateGetIdentity(invocation, context);
case "setWasmGCIdentity": case "setWasmGCIdentity":
return generateSetIdentity(invocation, context); return generateSetIdentity(invocation, context);
case "cloneObject":
return generateClone(invocation, context);
default: default:
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
@ -130,4 +133,23 @@ public class ObjectIntrinsic implements WasmGCIntrinsic {
return new WasmStructSet(objectStruct, instance, WasmGCClassInfoProvider.MONITOR_FIELD_OFFSET, return new WasmStructSet(objectStruct, instance, WasmGCClassInfoProvider.MONITOR_FIELD_OFFSET,
identityWrapper); identityWrapper);
} }
private WasmExpression generateClone(InvocationExpr invocation, WasmGCIntrinsicContext context) {
var objectStruct = context.classInfoProvider().getClassInfo("java.lang.Object").getStructure();
var classStruct = context.classInfoProvider().getClassInfo("java.lang.Class").getStructure();
var block = new WasmBlock(false);
block.setType(objectStruct.getReference());
var obj = context.exprCache().create(context.generate(invocation.getArguments().get(0)),
objectStruct.getReference(), invocation.getLocation(), block.getBody());
var cls = new WasmStructGet(objectStruct, obj.expr(), WasmGCClassInfoProvider.CLASS_FIELD_OFFSET);
var functionRef = new WasmStructGet(classStruct, cls, context.classInfoProvider().getCloneOffset());
var call = new WasmCallReference(functionRef, context.functionTypes().of(
objectStruct.getReference(), objectStruct.getReference()));
call.getArguments().add(obj.expr());
block.getBody().add(call);
obj.release();
return block;
}
} }

View File

@ -68,6 +68,7 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
private void fillObject() { private void fillObject() {
var intrinsic = new ObjectIntrinsic(); var intrinsic = new ObjectIntrinsic();
add(new MethodReference(Object.class, "getClass", Class.class), intrinsic); add(new MethodReference(Object.class, "getClass", Class.class), intrinsic);
add(new MethodReference(Object.class, "cloneObject", Object.class), intrinsic);
add(new MethodReference(Object.class.getName(), "getMonitor", add(new MethodReference(Object.class.getName(), "getMonitor",
ValueType.object("java.lang.Object$Monitor")), intrinsic); ValueType.object("java.lang.Object$Monitor")), intrinsic);
add(new MethodReference(Object.class.getName(), "setMonitor", add(new MethodReference(Object.class.getName(), "setMonitor",
@ -83,6 +84,7 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
add(new MethodReference(Class.class, "getNameImpl", String.class), intrinsic); add(new MethodReference(Class.class, "getNameImpl", String.class), intrinsic);
add(new MethodReference(Class.class, "setNameImpl", String.class, void.class), intrinsic); add(new MethodReference(Class.class, "setNameImpl", String.class, void.class), intrinsic);
add(new MethodReference(Class.class, "getEnclosingClass", Class.class), intrinsic); add(new MethodReference(Class.class, "getEnclosingClass", Class.class), intrinsic);
add(new MethodReference(Class.class, "getSuperclass", Class.class), intrinsic);
add(new MethodReference(Class.class, "getSimpleNameCache", Class.class, String.class), intrinsic); add(new MethodReference(Class.class, "getSimpleNameCache", Class.class, String.class), intrinsic);
add(new MethodReference(Class.class, "setSimpleNameCache", Class.class, String.class, void.class), intrinsic); add(new MethodReference(Class.class, "setSimpleNameCache", Class.class, String.class, void.class), intrinsic);
} }

View File

@ -35,8 +35,8 @@ public class WasmGCSupport {
return new ClassCastException(); return new ClassCastException();
} }
public static CloneNotSupportedException cnse() { public static void throwCloneNotSupportedException() throws CloneNotSupportedException {
return new CloneNotSupportedException(); throw new CloneNotSupportedException();
} }
public static int nextObjectId() { public static int nextObjectId() {

View File

@ -15,7 +15,6 @@
*/ */
package org.teavm.backend.wasm.transformation.gc; package org.teavm.backend.wasm.transformation.gc;
import org.teavm.backend.wasm.runtime.WasmGCSupport;
import org.teavm.interop.Import; import org.teavm.interop.Import;
import org.teavm.model.AccessLevel; import org.teavm.model.AccessLevel;
import org.teavm.model.AnnotationHolder; import org.teavm.model.AnnotationHolder;
@ -29,7 +28,6 @@ import org.teavm.model.MethodHolder;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.Program; import org.teavm.model.Program;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
import org.teavm.model.emit.ProgramEmitter;
import org.teavm.model.instructions.GetFieldInstruction; import org.teavm.model.instructions.GetFieldInstruction;
import org.teavm.model.instructions.InvocationType; import org.teavm.model.instructions.InvocationType;
import org.teavm.model.instructions.InvokeInstruction; import org.teavm.model.instructions.InvokeInstruction;
@ -51,11 +49,6 @@ public class BaseClassesTransformation implements ClassHolderTransformer {
method.setProgram(null); method.setProgram(null);
method.getModifiers().add(ElementModifier.NATIVE); method.getModifiers().add(ElementModifier.NATIVE);
break; break;
case "clone": {
var em = ProgramEmitter.create(method, context.getHierarchy());
em.invoke(WasmGCSupport.class, "cnse", CloneNotSupportedException.class).raise();
break;
}
default: default:
if (method.getProgram() != null) { if (method.getProgram() != null) {
transformMonitorFieldAccess(method.getProgram()); transformMonitorFieldAccess(method.getProgram());
@ -80,6 +73,7 @@ public class BaseClassesTransformation implements ClassHolderTransformer {
case "getEnclosingClass": case "getEnclosingClass":
case "getSimpleNameCache": case "getSimpleNameCache":
case "setSimpleNameCache": case "setSimpleNameCache":
case "getSuperclass":
method.setProgram(null); method.setProgram(null);
method.getModifiers().add(ElementModifier.NATIVE); method.getModifiers().add(ElementModifier.NATIVE);
break; break;

View File

@ -120,6 +120,14 @@ public class ClassMetadataRequirements {
requirements.computeIfAbsent(decodeType(className), k -> new ClassInfo()).arrayLength = true; requirements.computeIfAbsent(decodeType(className), k -> new ClassInfo()).arrayLength = true;
} }
} }
var clone = dependencyInfo.getMethod(new MethodReference(Object.class, "cloneObject", Object.class));
if (clone != null) {
var classNames = clone.getVariable(0).getTypes();
for (var className : classNames) {
requirements.computeIfAbsent(decodeType(className), k -> new ClassInfo()).cloneMethod = true;
}
}
} }
public Info getInfo(String className) { public Info getInfo(String className) {
@ -168,6 +176,7 @@ public class ClassMetadataRequirements {
boolean newArray; boolean newArray;
boolean arrayLength; boolean arrayLength;
boolean arrayGet; boolean arrayGet;
boolean cloneMethod;
@Override @Override
public boolean name() { public boolean name() {
@ -213,6 +222,11 @@ public class ClassMetadataRequirements {
public boolean arrayGet() { public boolean arrayGet() {
return arrayGet; return arrayGet;
} }
@Override
public boolean cloneMethod() {
return cloneMethod;
}
} }
public interface Info { public interface Info {
@ -233,5 +247,7 @@ public class ClassMetadataRequirements {
boolean arrayLength(); boolean arrayLength();
boolean arrayGet(); boolean arrayGet();
boolean cloneMethod();
} }
} }

View File

@ -28,7 +28,7 @@ public final class ResourceMapHelper {
public static Resource get(ResourceMap<?> map, String key) { public static Resource get(ResourceMap<?> map, String key) {
var count = entryCount(map); var count = entryCount(map);
var initialIndex = Math.abs(key.hashCode()) % count; var initialIndex = Integer.remainderUnsigned(key.hashCode(), count);
for (var i = initialIndex; i < count; ++i) { for (var i = initialIndex; i < count; ++i) {
var entry = entry(map, i); var entry = entry(map, i);
if (entry == null) { if (entry == null) {