mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
wasm gc: general implementation of System.arraycopy
This commit is contained in:
parent
dd24425de0
commit
b9f406dcaa
|
@ -870,6 +870,15 @@ public class DisassemblyCodeListener extends BaseDisassemblyListener implements
|
||||||
writer.eol();
|
writer.eol();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void arrayCopy(int targetTypeIndex, int sourceTypeIndex) {
|
||||||
|
writer.address().write("array.copy ");
|
||||||
|
writeTypeRef(targetTypeIndex);
|
||||||
|
writer.write(" ");
|
||||||
|
writeTypeRef(sourceTypeIndex);
|
||||||
|
writer.eol();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void functionReference(int functionIndex) {
|
public void functionReference(int functionIndex) {
|
||||||
writer.address().write("ref.func ");
|
writer.address().write("ref.func ");
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* 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.gc;
|
||||||
|
|
||||||
|
import org.teavm.dependency.AbstractDependencyListener;
|
||||||
|
import org.teavm.dependency.DependencyAgent;
|
||||||
|
import org.teavm.dependency.MethodDependency;
|
||||||
|
import org.teavm.model.MethodReference;
|
||||||
|
|
||||||
|
public class SystemArrayCopyDependencySupport extends AbstractDependencyListener {
|
||||||
|
private static final MethodReference COPY_METHOD = new MethodReference(System.class,
|
||||||
|
"arraycopy", Object.class, int.class, Object.class, int.class, int.class, void.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void methodReached(DependencyAgent agent, MethodDependency method) {
|
||||||
|
if (method.getMethod().getReference().equals(COPY_METHOD)) {
|
||||||
|
var implMethod = agent.linkMethod(new MethodReference(System.class,
|
||||||
|
"arrayCopyImpl", Object.class, int.class, Object.class, int.class, int.class, void.class));
|
||||||
|
method.getVariable(1).connect(implMethod.getVariable(1));
|
||||||
|
method.getVariable(3).connect(implMethod.getVariable(3));
|
||||||
|
implMethod.use();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,6 +38,7 @@ public class WasmGCDependencies {
|
||||||
contributeString();
|
contributeString();
|
||||||
analyzer.addDependencyListener(new WasmGCReferenceQueueDependency());
|
analyzer.addDependencyListener(new WasmGCReferenceQueueDependency());
|
||||||
analyzer.addDependencyListener(new WasmGCResourceDependency());
|
analyzer.addDependencyListener(new WasmGCResourceDependency());
|
||||||
|
analyzer.addDependencyListener(new SystemArrayCopyDependencySupport());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void contributeStandardExports() {
|
public void contributeStandardExports() {
|
||||||
|
|
|
@ -145,13 +145,16 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
private int enumConstantsFunctionOffset;
|
private int enumConstantsFunctionOffset;
|
||||||
private int arrayLengthOffset = -1;
|
private int arrayLengthOffset = -1;
|
||||||
private int arrayGetOffset = -1;
|
private int arrayGetOffset = -1;
|
||||||
|
private int arrayCopyOffset = -1;
|
||||||
private int cloneOffset = -1;
|
private int cloneOffset = -1;
|
||||||
private int servicesOffset = -1;
|
private int servicesOffset = -1;
|
||||||
private WasmStructure arrayVirtualTableStruct;
|
private WasmStructure arrayVirtualTableStruct;
|
||||||
private WasmFunction arrayGetObjectFunction;
|
private WasmFunction arrayGetObjectFunction;
|
||||||
private WasmFunction arrayLengthObjectFunction;
|
private WasmFunction arrayLengthObjectFunction;
|
||||||
|
private WasmFunction arrayCopyObjectFunction;
|
||||||
private WasmFunctionType arrayGetType;
|
private WasmFunctionType arrayGetType;
|
||||||
private WasmFunctionType arrayLengthType;
|
private WasmFunctionType arrayLengthType;
|
||||||
|
private WasmFunctionType arrayCopyType;
|
||||||
private List<WasmStructure> nonInitializedStructures = new ArrayList<>();
|
private List<WasmStructure> nonInitializedStructures = new ArrayList<>();
|
||||||
private WasmArray objectArrayType;
|
private WasmArray objectArrayType;
|
||||||
private boolean hasLoadServices;
|
private boolean hasLoadServices;
|
||||||
|
@ -176,7 +179,8 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
standardClasses = new WasmGCStandardClasses(this);
|
standardClasses = new WasmGCStandardClasses(this);
|
||||||
strings = new WasmGCStringPool(standardClasses, module, functionProvider, names, functionTypes,
|
strings = new WasmGCStringPool(standardClasses, module, functionProvider, names, functionTypes,
|
||||||
dependencyInfo);
|
dependencyInfo);
|
||||||
supertypeGenerator = new WasmGCSupertypeFunctionGenerator(module, this, names, tagRegistry, functionTypes);
|
supertypeGenerator = new WasmGCSupertypeFunctionGenerator(module, this, names, tagRegistry, functionTypes,
|
||||||
|
queue);
|
||||||
newArrayGenerator = new WasmGCNewArrayFunctionGenerator(module, functionTypes, this, names, queue);
|
newArrayGenerator = new WasmGCNewArrayFunctionGenerator(module, functionTypes, this, names, queue);
|
||||||
typeMapper = new WasmGCTypeMapper(classSource, this, functionTypes, module);
|
typeMapper = new WasmGCTypeMapper(classSource, this, functionTypes, module);
|
||||||
var customTypeMapperFactoryContext = customTypeMapperFactoryContext();
|
var customTypeMapperFactoryContext = customTypeMapperFactoryContext();
|
||||||
|
@ -664,6 +668,7 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
WasmStructure objectStructure) {
|
WasmStructure objectStructure) {
|
||||||
var virtualTable = virtualTables.lookup("java.lang.Object");
|
var virtualTable = virtualTables.lookup("java.lang.Object");
|
||||||
var structure = getArrayVirtualTableStructure();
|
var structure = getArrayVirtualTableStructure();
|
||||||
|
structure.init();
|
||||||
var itemType = ((ValueType.Array) type).getItemType();
|
var itemType = ((ValueType.Array) type).getItemType();
|
||||||
|
|
||||||
for (var entry : virtualTable.getEntries()) {
|
for (var entry : virtualTable.getEntries()) {
|
||||||
|
@ -681,8 +686,12 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
target.add(new WasmStructSet(structure, new WasmGetGlobal(global), arrayGetOffset,
|
target.add(new WasmStructSet(structure, new WasmGetGlobal(global), arrayGetOffset,
|
||||||
new WasmFunctionReference(getFunction)));
|
new WasmFunctionReference(getFunction)));
|
||||||
}
|
}
|
||||||
|
if (info.arrayCopy()) {
|
||||||
|
var copyFunction = getArrayCopyFunction(itemType);
|
||||||
|
target.add(new WasmStructSet(structure, new WasmGetGlobal(global), arrayCopyOffset,
|
||||||
|
new WasmFunctionReference(copyFunction)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private WasmFunction getArrayLengthFunction(WasmStructure objectStructure) {
|
private WasmFunction getArrayLengthFunction(WasmStructure objectStructure) {
|
||||||
var arrayTypeRef = (WasmType.CompositeReference) objectStructure.getFields().get(ARRAY_DATA_FIELD_OFFSET)
|
var arrayTypeRef = (WasmType.CompositeReference) objectStructure.getFields().get(ARRAY_DATA_FIELD_OFFSET)
|
||||||
|
@ -815,6 +824,53 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
return function;
|
return function;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private WasmFunction getArrayCopyFunction(ValueType itemType) {
|
||||||
|
if (itemType instanceof ValueType.Primitive) {
|
||||||
|
return createArrayCopyFunction(itemType);
|
||||||
|
}
|
||||||
|
return getArrayCopyObjectFunction();
|
||||||
|
}
|
||||||
|
|
||||||
|
private WasmFunction getArrayCopyObjectFunction() {
|
||||||
|
if (arrayCopyObjectFunction == null) {
|
||||||
|
arrayCopyObjectFunction = createArrayCopyFunction(OBJECT_TYPE);
|
||||||
|
}
|
||||||
|
return arrayCopyObjectFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
private WasmFunction createArrayCopyFunction(ValueType type) {
|
||||||
|
var function = new WasmFunction(getArrayCopyType());
|
||||||
|
function.setName(names.topLevel("Array<" + names.suggestForType(type) + ">::copy"));
|
||||||
|
module.functions.add(function);
|
||||||
|
function.setReferenced(true);
|
||||||
|
|
||||||
|
var arrayStruct = getClassInfo(ValueType.arrayOf(type)).structure;
|
||||||
|
var arrayDataTypeRef = (WasmType.CompositeReference) arrayStruct.getFields()
|
||||||
|
.get(ARRAY_DATA_FIELD_OFFSET).getUnpackedType();
|
||||||
|
var arrayDataType = (WasmArray) arrayDataTypeRef.composite;
|
||||||
|
var sourceLocal = new WasmLocal(standardClasses.objectClass().getType(), "source");
|
||||||
|
var sourceIndexLocal = new WasmLocal(WasmType.INT32, "sourceIndex");
|
||||||
|
var targetLocal = new WasmLocal(standardClasses.objectClass().getType(), "target");
|
||||||
|
var targetIndexLocal = new WasmLocal(WasmType.INT32, "targetIndex");
|
||||||
|
var countLocal = new WasmLocal(WasmType.INT32, "count");
|
||||||
|
function.add(sourceLocal);
|
||||||
|
function.add(sourceIndexLocal);
|
||||||
|
function.add(targetLocal);
|
||||||
|
function.add(targetIndexLocal);
|
||||||
|
function.add(countLocal);
|
||||||
|
|
||||||
|
var sourceArray = new WasmCast(new WasmGetLocal(sourceLocal), arrayStruct.getNonNullReference());
|
||||||
|
var sourceArrayData = new WasmStructGet(arrayStruct, sourceArray, ARRAY_DATA_FIELD_OFFSET);
|
||||||
|
var targetArray = new WasmCast(new WasmGetLocal(targetLocal), arrayStruct.getNonNullReference());
|
||||||
|
var targetArrayData = new WasmStructGet(arrayStruct, targetArray, ARRAY_DATA_FIELD_OFFSET);
|
||||||
|
|
||||||
|
function.getBody().add(new WasmArrayCopy(
|
||||||
|
arrayDataType, targetArrayData, new WasmGetLocal(sourceIndexLocal),
|
||||||
|
arrayDataType, sourceArrayData, new WasmGetLocal(targetIndexLocal),
|
||||||
|
new WasmGetLocal(countLocal)));
|
||||||
|
return function;
|
||||||
|
}
|
||||||
|
|
||||||
private WasmFunctionType getArrayGetType() {
|
private WasmFunctionType getArrayGetType() {
|
||||||
if (arrayGetType == null) {
|
if (arrayGetType == null) {
|
||||||
arrayGetType = functionTypes.of(standardClasses.objectClass().getType(),
|
arrayGetType = functionTypes.of(standardClasses.objectClass().getType(),
|
||||||
|
@ -830,6 +886,14 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
return arrayLengthType;
|
return arrayLengthType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private WasmFunctionType getArrayCopyType() {
|
||||||
|
if (arrayCopyType == null) {
|
||||||
|
arrayCopyType = functionTypes.of(null, standardClasses.objectClass().getType(), WasmType.INT32,
|
||||||
|
standardClasses.objectClass().getType(), WasmType.INT32, WasmType.INT32);
|
||||||
|
}
|
||||||
|
return arrayCopyType;
|
||||||
|
}
|
||||||
|
|
||||||
private void fillVirtualTableEntry(List<WasmExpression> target, WasmGlobal global,
|
private void fillVirtualTableEntry(List<WasmExpression> target, WasmGlobal global,
|
||||||
WasmStructure structure, WasmGCVirtualTable virtualTable, WasmGCVirtualTableEntry entry) {
|
WasmStructure structure, WasmGCVirtualTable virtualTable, WasmGCVirtualTableEntry entry) {
|
||||||
var implementor = virtualTable.implementor(entry);
|
var implementor = virtualTable.implementor(entry);
|
||||||
|
@ -966,6 +1030,12 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
fields.add(new WasmField(arrayGetType.getReference().asStorage(),
|
fields.add(new WasmField(arrayGetType.getReference().asStorage(),
|
||||||
names.structureField("@arrayGet")));
|
names.structureField("@arrayGet")));
|
||||||
}
|
}
|
||||||
|
if (metadataRequirements.hasArrayCopy()) {
|
||||||
|
arrayCopyOffset = fields.size();
|
||||||
|
var arrayCopyType = getArrayCopyType();
|
||||||
|
fields.add(new WasmField(arrayCopyType.getReference().asStorage(),
|
||||||
|
names.structureField("@arrayCopy")));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
arrayVirtualTableStruct.setSupertype(standardClasses.objectClass().getVirtualTableStructure());
|
arrayVirtualTableStruct.setSupertype(standardClasses.objectClass().getVirtualTableStructure());
|
||||||
module.types.add(arrayVirtualTableStruct);
|
module.types.add(arrayVirtualTableStruct);
|
||||||
|
@ -986,6 +1056,12 @@ public class WasmGCClassGenerator implements WasmGCClassInfoProvider, WasmGCInit
|
||||||
return arrayGetOffset;
|
return arrayGetOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getArrayCopyOffset() {
|
||||||
|
initStructures();
|
||||||
|
return arrayCopyOffset;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getEnumConstantsFunctionOffset() {
|
public int getEnumConstantsFunctionOffset() {
|
||||||
return enumConstantsFunctionOffset;
|
return enumConstantsFunctionOffset;
|
||||||
|
|
|
@ -65,6 +65,8 @@ public interface WasmGCClassInfoProvider {
|
||||||
|
|
||||||
int getArrayLengthOffset();
|
int getArrayLengthOffset();
|
||||||
|
|
||||||
|
int getArrayCopyOffset();
|
||||||
|
|
||||||
int getEnumConstantsFunctionOffset();
|
int getEnumConstantsFunctionOffset();
|
||||||
|
|
||||||
int getCloneOffset();
|
int getCloneOffset();
|
||||||
|
|
|
@ -19,6 +19,7 @@ import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Queue;
|
||||||
import org.teavm.backend.wasm.WasmFunctionTypes;
|
import org.teavm.backend.wasm.WasmFunctionTypes;
|
||||||
import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider;
|
import org.teavm.backend.wasm.generate.gc.WasmGCNameProvider;
|
||||||
import org.teavm.backend.wasm.model.WasmFunction;
|
import org.teavm.backend.wasm.model.WasmFunction;
|
||||||
|
@ -51,19 +52,22 @@ public class WasmGCSupertypeFunctionGenerator implements WasmGCSupertypeFunction
|
||||||
private TagRegistry tagRegistry;
|
private TagRegistry tagRegistry;
|
||||||
private WasmFunctionTypes functionTypes;
|
private WasmFunctionTypes functionTypes;
|
||||||
private WasmFunctionType functionType;
|
private WasmFunctionType functionType;
|
||||||
|
private Queue<Runnable> queue;
|
||||||
|
|
||||||
WasmGCSupertypeFunctionGenerator(
|
WasmGCSupertypeFunctionGenerator(
|
||||||
WasmModule module,
|
WasmModule module,
|
||||||
WasmGCClassGenerator classGenerator,
|
WasmGCClassGenerator classGenerator,
|
||||||
WasmGCNameProvider nameProvider,
|
WasmGCNameProvider nameProvider,
|
||||||
TagRegistry tagRegistry,
|
TagRegistry tagRegistry,
|
||||||
WasmFunctionTypes functionTypes
|
WasmFunctionTypes functionTypes,
|
||||||
|
Queue<Runnable> queue
|
||||||
) {
|
) {
|
||||||
this.module = module;
|
this.module = module;
|
||||||
this.classGenerator = classGenerator;
|
this.classGenerator = classGenerator;
|
||||||
this.nameProvider = nameProvider;
|
this.nameProvider = nameProvider;
|
||||||
this.tagRegistry = tagRegistry;
|
this.tagRegistry = tagRegistry;
|
||||||
this.functionTypes = functionTypes;
|
this.functionTypes = functionTypes;
|
||||||
|
this.queue = queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -83,6 +87,7 @@ public class WasmGCSupertypeFunctionGenerator implements WasmGCSupertypeFunction
|
||||||
function.add(subtypeVar);
|
function.add(subtypeVar);
|
||||||
module.functions.add(function);
|
module.functions.add(function);
|
||||||
|
|
||||||
|
queue.add(() -> {
|
||||||
if (type instanceof ValueType.Object) {
|
if (type instanceof ValueType.Object) {
|
||||||
var className = ((ValueType.Object) type).getClassName();
|
var className = ((ValueType.Object) type).getClassName();
|
||||||
generateIsClass(subtypeVar, className, function);
|
generateIsClass(subtypeVar, className, function);
|
||||||
|
@ -94,6 +99,7 @@ public class WasmGCSupertypeFunctionGenerator implements WasmGCSupertypeFunction
|
||||||
var condition = new WasmReferencesEqual(new WasmGetLocal(subtypeVar), new WasmGetGlobal(expected));
|
var condition = new WasmReferencesEqual(new WasmGetLocal(subtypeVar), new WasmGetGlobal(expected));
|
||||||
function.getBody().add(condition);
|
function.getBody().add(condition);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return function;
|
return function;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ import org.teavm.backend.wasm.model.WasmFunctionType;
|
||||||
import org.teavm.backend.wasm.model.WasmLocal;
|
import org.teavm.backend.wasm.model.WasmLocal;
|
||||||
import org.teavm.backend.wasm.model.WasmModule;
|
import org.teavm.backend.wasm.model.WasmModule;
|
||||||
import org.teavm.backend.wasm.model.WasmStructure;
|
import org.teavm.backend.wasm.model.WasmStructure;
|
||||||
|
import org.teavm.backend.wasm.model.WasmTag;
|
||||||
import org.teavm.backend.wasm.model.WasmType;
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmArrayGet;
|
import org.teavm.backend.wasm.model.expression.WasmArrayGet;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmArrayLength;
|
import org.teavm.backend.wasm.model.expression.WasmArrayLength;
|
||||||
|
@ -822,5 +823,10 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
|
||||||
public WasmGCStringProvider strings() {
|
public WasmGCStringProvider strings() {
|
||||||
return context.strings();
|
return context.strings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WasmTag exceptionTag() {
|
||||||
|
return context.getExceptionTag();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,20 +19,47 @@ import org.teavm.ast.InvocationExpr;
|
||||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
|
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
|
||||||
import org.teavm.backend.wasm.model.WasmArray;
|
import org.teavm.backend.wasm.model.WasmArray;
|
||||||
import org.teavm.backend.wasm.model.WasmFunction;
|
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.WasmStructure;
|
import org.teavm.backend.wasm.model.WasmStructure;
|
||||||
import org.teavm.backend.wasm.model.WasmType;
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmArrayCopy;
|
import org.teavm.backend.wasm.model.expression.WasmArrayCopy;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmArrayLength;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmBlock;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmBranch;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmCall;
|
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmCallReference;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmCast;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmGetLocal;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmIntBinaryOperation;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmIntType;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmReturn;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmStructGet;
|
import org.teavm.backend.wasm.model.expression.WasmStructGet;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmThrow;
|
||||||
|
import org.teavm.backend.wasm.runtime.gc.WasmGCSupport;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
|
|
||||||
public class SystemArrayCopyIntrinsic implements WasmGCIntrinsic {
|
public class SystemArrayCopyIntrinsic implements WasmGCIntrinsic {
|
||||||
private WasmFunction defaultFunction;
|
private WasmFunction defaultFunction;
|
||||||
|
private WasmFunction argsCheckFunction;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) {
|
public WasmExpression apply(InvocationExpr invocation, WasmGCIntrinsicContext context) {
|
||||||
|
switch (invocation.getMethod().getName()) {
|
||||||
|
case "arraycopy":
|
||||||
|
return generateArrayCopy(invocation, context);
|
||||||
|
case "doArrayCopy":
|
||||||
|
return generateDoArrayCopy(invocation, context);
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private WasmExpression generateArrayCopy(InvocationExpr invocation, WasmGCIntrinsicContext context) {
|
||||||
var result = tryGenerateSpecialCase(invocation, context);
|
var result = tryGenerateSpecialCase(invocation, context);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
tryGenerateSpecialCase(invocation, context);
|
tryGenerateSpecialCase(invocation, context);
|
||||||
|
@ -46,6 +73,32 @@ public class SystemArrayCopyIntrinsic implements WasmGCIntrinsic {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private WasmExpression generateDoArrayCopy(InvocationExpr invocation, WasmGCIntrinsicContext context) {
|
||||||
|
var objStruct = context.classInfoProvider().getClassInfo(Object.class.getName()).getStructure();
|
||||||
|
var arrayClsStruct = context.classInfoProvider().getArrayVirtualTableStructure();
|
||||||
|
var block = new WasmBlock(false);
|
||||||
|
|
||||||
|
var source = context.exprCache().create(context.generate(invocation.getArguments().get(0)),
|
||||||
|
objStruct.getReference(), invocation.getLocation(), block.getBody());
|
||||||
|
WasmExpression sourceCls = new WasmStructGet(objStruct, source.expr(),
|
||||||
|
WasmGCClassInfoProvider.CLASS_FIELD_OFFSET);
|
||||||
|
sourceCls = new WasmCast(sourceCls, arrayClsStruct.getNonNullReference());
|
||||||
|
var copyFunction = new WasmStructGet(arrayClsStruct, sourceCls,
|
||||||
|
context.classInfoProvider().getArrayCopyOffset());
|
||||||
|
var functionTypeRef = (WasmType.CompositeReference) arrayClsStruct.getFields().get(
|
||||||
|
context.classInfoProvider().getArrayCopyOffset()).getUnpackedType();
|
||||||
|
var functionType = (WasmFunctionType) functionTypeRef.composite;
|
||||||
|
var call = new WasmCallReference(copyFunction, functionType);
|
||||||
|
call.getArguments().add(source.expr());
|
||||||
|
call.getArguments().add(context.generate(invocation.getArguments().get(1)));
|
||||||
|
call.getArguments().add(context.generate(invocation.getArguments().get(2)));
|
||||||
|
call.getArguments().add(context.generate(invocation.getArguments().get(3)));
|
||||||
|
call.getArguments().add(context.generate(invocation.getArguments().get(4)));
|
||||||
|
block.getBody().add(call);
|
||||||
|
source.release();
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
private WasmExpression tryGenerateSpecialCase(InvocationExpr invocation, WasmGCIntrinsicContext context) {
|
private WasmExpression tryGenerateSpecialCase(InvocationExpr invocation, WasmGCIntrinsicContext context) {
|
||||||
var sourceArray = invocation.getArguments().get(0);
|
var sourceArray = invocation.getArguments().get(0);
|
||||||
var targetArray = invocation.getArguments().get(2);
|
var targetArray = invocation.getArguments().get(2);
|
||||||
|
@ -69,35 +122,120 @@ public class SystemArrayCopyIntrinsic implements WasmGCIntrinsic {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var block = new WasmBlock(false);
|
||||||
|
|
||||||
var wasmTargetArrayType = (WasmType.CompositeReference) context.typeMapper().mapType(
|
var wasmTargetArrayType = (WasmType.CompositeReference) context.typeMapper().mapType(
|
||||||
ValueType.arrayOf(targetItemType));
|
ValueType.arrayOf(targetItemType));
|
||||||
var wasmTargetArrayStruct = (WasmStructure) wasmTargetArrayType.composite;
|
var wasmTargetArrayStruct = (WasmStructure) wasmTargetArrayType.composite;
|
||||||
var wasmTargetArrayWrapper = context.generate(invocation.getArguments().get(2));
|
var wasmTargetArrayWrapper = context.generate(invocation.getArguments().get(2));
|
||||||
var wasmTargetArray = new WasmStructGet(wasmTargetArrayStruct, wasmTargetArrayWrapper,
|
var wasmTargetArrayTypeRef = (WasmType.CompositeReference) wasmTargetArrayStruct.getFields()
|
||||||
WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET);
|
.get(WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET).getUnpackedType();
|
||||||
var wasmTargetIndex = context.generate(invocation.getArguments().get(3));
|
var wasmTargetArray = context.exprCache().create(new WasmStructGet(wasmTargetArrayStruct,
|
||||||
|
wasmTargetArrayWrapper, WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET),
|
||||||
|
wasmTargetArrayTypeRef, null, block.getBody());
|
||||||
|
var wasmTargetIndex = context.exprCache().create(context.generate(invocation.getArguments().get(3)),
|
||||||
|
WasmType.INT32, null, block.getBody());
|
||||||
var wasmSourceArrayType = (WasmType.CompositeReference) context.typeMapper().mapType(
|
var wasmSourceArrayType = (WasmType.CompositeReference) context.typeMapper().mapType(
|
||||||
ValueType.arrayOf(sourceItemType));
|
ValueType.arrayOf(sourceItemType));
|
||||||
var wasmSourceArrayStruct = (WasmStructure) wasmSourceArrayType.composite;
|
var wasmSourceArrayStruct = (WasmStructure) wasmSourceArrayType.composite;
|
||||||
var wasmSourceArrayWrapper = context.generate(invocation.getArguments().get(0));
|
var wasmSourceArrayWrapper = context.generate(invocation.getArguments().get(0));
|
||||||
var wasmSourceArray = new WasmStructGet(wasmSourceArrayStruct, wasmSourceArrayWrapper,
|
|
||||||
WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET);
|
|
||||||
var wasmSourceIndex = context.generate(invocation.getArguments().get(1));
|
|
||||||
var wasmSize = context.generate(invocation.getArguments().get(4));
|
|
||||||
|
|
||||||
var wasmTargetArrayTypeRef = (WasmType.CompositeReference) wasmTargetArrayStruct.getFields()
|
|
||||||
.get(WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET).getUnpackedType();
|
|
||||||
var wasmSourceArrayTypeRef = (WasmType.CompositeReference) wasmSourceArrayStruct.getFields()
|
var wasmSourceArrayTypeRef = (WasmType.CompositeReference) wasmSourceArrayStruct.getFields()
|
||||||
.get(WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET).getUnpackedType();
|
.get(WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET).getUnpackedType();
|
||||||
|
var wasmSourceArray = context.exprCache().create(new WasmStructGet(wasmSourceArrayStruct,
|
||||||
|
wasmSourceArrayWrapper, WasmGCClassInfoProvider.ARRAY_DATA_FIELD_OFFSET),
|
||||||
|
wasmSourceArrayTypeRef, null, block.getBody());
|
||||||
|
var wasmSourceIndex = context.exprCache().create(context.generate(invocation.getArguments().get(1)),
|
||||||
|
WasmType.INT32, null, block.getBody());
|
||||||
|
var wasmSize = context.exprCache().create(context.generate(invocation.getArguments().get(4)),
|
||||||
|
WasmType.INT32, null, block.getBody());
|
||||||
|
|
||||||
return new WasmArrayCopy((WasmArray) wasmTargetArrayTypeRef.composite, wasmTargetArray, wasmTargetIndex,
|
|
||||||
(WasmArray) wasmSourceArrayTypeRef.composite, wasmSourceArray, wasmSourceIndex, wasmSize);
|
block.getBody().add(new WasmCall(
|
||||||
|
getArgsCheckFunction(context),
|
||||||
|
wasmTargetArray.expr(), wasmTargetIndex.expr(),
|
||||||
|
wasmSourceArray.expr(), wasmSourceIndex.expr(),
|
||||||
|
wasmSize.expr()
|
||||||
|
));
|
||||||
|
|
||||||
|
block.getBody().add(new WasmArrayCopy(
|
||||||
|
(WasmArray) wasmTargetArrayTypeRef.composite, wasmTargetArray.expr(), wasmTargetIndex.expr(),
|
||||||
|
(WasmArray) wasmSourceArrayTypeRef.composite, wasmSourceArray.expr(), wasmSourceIndex.expr(),
|
||||||
|
wasmSize.expr()
|
||||||
|
));
|
||||||
|
wasmTargetArray.release();
|
||||||
|
wasmTargetIndex.release();
|
||||||
|
wasmSourceArray.release();
|
||||||
|
wasmSourceIndex.release();
|
||||||
|
wasmSize.release();
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
private WasmFunction getArgsCheckFunction(WasmGCIntrinsicContext context) {
|
||||||
|
if (argsCheckFunction == null) {
|
||||||
|
argsCheckFunction = createArgsCheckFunction(context);
|
||||||
|
}
|
||||||
|
return argsCheckFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
private WasmFunction createArgsCheckFunction(WasmGCIntrinsicContext context) {
|
||||||
|
var function = new WasmFunction(context.functionTypes().of(null,
|
||||||
|
WasmType.Reference.ARRAY, WasmType.INT32, WasmType.Reference.ARRAY,
|
||||||
|
WasmType.INT32, WasmType.INT32));
|
||||||
|
function.setName(context.names().topLevel("teavm@checkArrayCopy"));
|
||||||
|
context.module().functions.add(function);
|
||||||
|
|
||||||
|
var targetArrayLocal = new WasmLocal(WasmType.Reference.ARRAY, "targetArray");
|
||||||
|
var targetArrayIndexLocal = new WasmLocal(WasmType.INT32, "targetIndex");
|
||||||
|
var sourceArrayLocal = new WasmLocal(WasmType.Reference.ARRAY, "sourceArray");
|
||||||
|
var sourceArrayIndexLocal = new WasmLocal(WasmType.INT32, "sourceIndex");
|
||||||
|
var countLocal = new WasmLocal(WasmType.INT32, "count");
|
||||||
|
function.add(targetArrayLocal);
|
||||||
|
function.add(targetArrayIndexLocal);
|
||||||
|
function.add(sourceArrayLocal);
|
||||||
|
function.add(sourceArrayIndexLocal);
|
||||||
|
function.add(countLocal);
|
||||||
|
|
||||||
|
var block = new WasmBlock(false);
|
||||||
|
var targetIndexLessThanZero = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.LT_SIGNED,
|
||||||
|
new WasmGetLocal(targetArrayIndexLocal), new WasmInt32Constant(0));
|
||||||
|
block.getBody().add(new WasmBranch(targetIndexLessThanZero, block));
|
||||||
|
var sourceIndexLessThanZero = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.LT_SIGNED,
|
||||||
|
new WasmGetLocal(sourceArrayIndexLocal), new WasmInt32Constant(0));
|
||||||
|
block.getBody().add(new WasmBranch(sourceIndexLessThanZero, block));
|
||||||
|
var countPositive = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.LT_SIGNED,
|
||||||
|
new WasmGetLocal(countLocal), new WasmInt32Constant(0));
|
||||||
|
block.getBody().add(new WasmBranch(countPositive, block));
|
||||||
|
|
||||||
|
var targetSize = new WasmArrayLength(new WasmGetLocal(targetArrayLocal));
|
||||||
|
var targetIndexLimit = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SUB,
|
||||||
|
targetSize, new WasmGetLocal(countLocal));
|
||||||
|
var targetIndexGreaterThanSize = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.GT_SIGNED,
|
||||||
|
new WasmGetLocal(targetArrayIndexLocal), targetIndexLimit);
|
||||||
|
block.getBody().add(new WasmBranch(targetIndexGreaterThanSize, block));
|
||||||
|
|
||||||
|
var sourceSize = new WasmArrayLength(new WasmGetLocal(sourceArrayLocal));
|
||||||
|
var sourceIndexLimit = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SUB,
|
||||||
|
sourceSize, new WasmGetLocal(countLocal));
|
||||||
|
var sourceIndexGreaterThanSize = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.GT_SIGNED,
|
||||||
|
new WasmGetLocal(sourceArrayIndexLocal), sourceIndexLimit);
|
||||||
|
block.getBody().add(new WasmBranch(sourceIndexGreaterThanSize, block));
|
||||||
|
|
||||||
|
block.getBody().add(new WasmReturn());
|
||||||
|
|
||||||
|
function.getBody().add(block);
|
||||||
|
|
||||||
|
var aioobeFunction = context.functions().forStaticMethod(new MethodReference(WasmGCSupport.class, "aiiobe",
|
||||||
|
ArrayIndexOutOfBoundsException.class));
|
||||||
|
var throwExpr = new WasmThrow(context.exceptionTag());
|
||||||
|
throwExpr.getArguments().add(new WasmCall(aioobeFunction));
|
||||||
|
function.getBody().add(throwExpr);
|
||||||
|
return function;
|
||||||
}
|
}
|
||||||
|
|
||||||
private WasmFunction getDefaultFunction(WasmGCIntrinsicContext manager) {
|
private WasmFunction getDefaultFunction(WasmGCIntrinsicContext manager) {
|
||||||
if (defaultFunction == null) {
|
if (defaultFunction == null) {
|
||||||
defaultFunction = manager.functions().forStaticMethod(new MethodReference(System.class,
|
defaultFunction = manager.functions().forStaticMethod(new MethodReference(System.class,
|
||||||
"arraycopy", Object.class, int.class, Object.class, int.class, int.class, void.class));
|
"arrayCopyImpl", Object.class, int.class, Object.class, int.class, int.class, void.class));
|
||||||
}
|
}
|
||||||
return defaultFunction;
|
return defaultFunction;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
|
||||||
import org.teavm.backend.wasm.generate.gc.classes.WasmGCTypeMapper;
|
import org.teavm.backend.wasm.generate.gc.classes.WasmGCTypeMapper;
|
||||||
import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringProvider;
|
import org.teavm.backend.wasm.generate.gc.strings.WasmGCStringProvider;
|
||||||
import org.teavm.backend.wasm.model.WasmModule;
|
import org.teavm.backend.wasm.model.WasmModule;
|
||||||
|
import org.teavm.backend.wasm.model.WasmTag;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
import org.teavm.model.ClassHierarchy;
|
import org.teavm.model.ClassHierarchy;
|
||||||
|
|
||||||
|
@ -55,4 +56,6 @@ public interface WasmGCIntrinsicContext {
|
||||||
WasmGCStringProvider strings();
|
WasmGCStringProvider strings();
|
||||||
|
|
||||||
ClassLoader classLoader();
|
ClassLoader classLoader();
|
||||||
|
|
||||||
|
WasmTag exceptionTag();
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,8 +108,11 @@ public class WasmGCIntrinsics implements WasmGCIntrinsicProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillSystem() {
|
private void fillSystem() {
|
||||||
|
var arrayCopyIntrinsic = new SystemArrayCopyIntrinsic();
|
||||||
add(new MethodReference(System.class, "arraycopy", Object.class, int.class, Object.class,
|
add(new MethodReference(System.class, "arraycopy", Object.class, int.class, Object.class,
|
||||||
int.class, int.class, void.class), new SystemArrayCopyIntrinsic());
|
int.class, int.class, void.class), arrayCopyIntrinsic);
|
||||||
|
add(new MethodReference(System.class, "doArrayCopy", Object.class, int.class, Object.class,
|
||||||
|
int.class, int.class, void.class), arrayCopyIntrinsic);
|
||||||
add(new MethodReference(System.class, "currentTimeMillis", long.class), new SystemIntrinsic());
|
add(new MethodReference(System.class, "currentTimeMillis", long.class), new SystemIntrinsic());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ public class WasmStructSet extends WasmExpression {
|
||||||
private WasmExpression value;
|
private WasmExpression value;
|
||||||
|
|
||||||
public WasmStructSet(WasmStructure type, WasmExpression instance, int fieldIndex, WasmExpression value) {
|
public WasmStructSet(WasmStructure type, WasmExpression instance, int fieldIndex, WasmExpression value) {
|
||||||
|
checkFieldIndex(fieldIndex);
|
||||||
this.type = Objects.requireNonNull(type);
|
this.type = Objects.requireNonNull(type);
|
||||||
this.instance = Objects.requireNonNull(instance);
|
this.instance = Objects.requireNonNull(instance);
|
||||||
this.fieldIndex = fieldIndex;
|
this.fieldIndex = fieldIndex;
|
||||||
|
@ -52,6 +53,7 @@ public class WasmStructSet extends WasmExpression {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFieldIndex(int fieldIndex) {
|
public void setFieldIndex(int fieldIndex) {
|
||||||
|
checkFieldIndex(fieldIndex);
|
||||||
this.fieldIndex = fieldIndex;
|
this.fieldIndex = fieldIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,4 +69,11 @@ public class WasmStructSet extends WasmExpression {
|
||||||
public void acceptVisitor(WasmExpressionVisitor visitor) {
|
public void acceptVisitor(WasmExpressionVisitor visitor) {
|
||||||
visitor.visit(this);
|
visitor.visit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void checkFieldIndex(int fieldIndex) {
|
||||||
|
if (fieldIndex < 0) {
|
||||||
|
throw new IllegalArgumentException("Field index must be >= 0");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,11 +83,15 @@ public class BaseClassesTransformation implements ClassHolderTransformer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (cls.getName().equals("java.lang.System")) {
|
} else if (cls.getName().equals("java.lang.System")) {
|
||||||
|
Program arrayCopyProgram = null;
|
||||||
|
MethodDescriptor arrayCopyDescriptor = null;
|
||||||
for (var method : cls.getMethods()) {
|
for (var method : cls.getMethods()) {
|
||||||
switch (method.getName()) {
|
switch (method.getName()) {
|
||||||
case "arraycopy":
|
case "arraycopy":
|
||||||
|
arrayCopyProgram = method.getProgram();
|
||||||
method.setProgram(null);
|
method.setProgram(null);
|
||||||
method.getModifiers().add(ElementModifier.NATIVE);
|
method.getModifiers().add(ElementModifier.NATIVE);
|
||||||
|
arrayCopyDescriptor = method.getDescriptor();
|
||||||
break;
|
break;
|
||||||
case "currentTimeMillis": {
|
case "currentTimeMillis": {
|
||||||
var annotation = new AnnotationHolder(Import.class.getName());
|
var annotation = new AnnotationHolder(Import.class.getName());
|
||||||
|
@ -97,6 +101,13 @@ public class BaseClassesTransformation implements ClassHolderTransformer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (arrayCopyProgram != null) {
|
||||||
|
var arrayCopyImpl = new MethodHolder(new MethodDescriptor("arrayCopyImpl",
|
||||||
|
arrayCopyDescriptor.getSignature()));
|
||||||
|
arrayCopyImpl.setProgram(arrayCopyProgram);
|
||||||
|
arrayCopyImpl.getModifiers().add(ElementModifier.STATIC);
|
||||||
|
cls.addMethod(arrayCopyImpl);
|
||||||
|
}
|
||||||
} else if (cls.getName().equals("java.lang.ref.WeakReference")) {
|
} else if (cls.getName().equals("java.lang.ref.WeakReference")) {
|
||||||
var constructor = cls.getMethod(new MethodDescriptor("<init>", Object.class, ReferenceQueue.class,
|
var constructor = cls.getMethod(new MethodDescriptor("<init>", Object.class, ReferenceQueue.class,
|
||||||
void.class));
|
void.class));
|
||||||
|
|
|
@ -42,10 +42,13 @@ public class ClassMetadataRequirements {
|
||||||
"get", Object.class, int.class, Object.class);
|
"get", Object.class, int.class, Object.class);
|
||||||
private static final MethodReference ARRAY_LENGTH = new MethodReference(Array.class,
|
private static final MethodReference ARRAY_LENGTH = new MethodReference(Array.class,
|
||||||
"getLength", Object.class, int.class);
|
"getLength", Object.class, int.class);
|
||||||
|
private static final MethodReference ARRAY_COPY = new MethodReference(System.class,
|
||||||
|
"arraycopy", Object.class, int.class, Object.class, int.class, int.class, void.class);
|
||||||
private static final ClassInfo EMPTY_INFO = new ClassInfo();
|
private static final ClassInfo EMPTY_INFO = new ClassInfo();
|
||||||
private Map<ValueType, ClassInfo> requirements = new HashMap<>();
|
private Map<ValueType, ClassInfo> requirements = new HashMap<>();
|
||||||
private boolean hasArrayGet;
|
private boolean hasArrayGet;
|
||||||
private boolean hasArrayLength;
|
private boolean hasArrayLength;
|
||||||
|
private boolean hasArrayCopy;
|
||||||
private boolean hasEnumConstants;
|
private boolean hasEnumConstants;
|
||||||
private boolean hasSuperclass;
|
private boolean hasSuperclass;
|
||||||
private boolean hasIsAssignable;
|
private boolean hasIsAssignable;
|
||||||
|
@ -137,6 +140,15 @@ public class ClassMetadataRequirements {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var arrayCopy = dependencyInfo.getMethod(ARRAY_COPY);
|
||||||
|
if (arrayCopy != null) {
|
||||||
|
hasArrayCopy = arrayCopy.isUsed();
|
||||||
|
var classNames = arrayCopy.getVariable(1).getTypes();
|
||||||
|
for (var className : classNames) {
|
||||||
|
requirements.computeIfAbsent(decodeType(className), k -> new ClassInfo()).arrayCopy = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var clone = dependencyInfo.getMethod(new MethodReference(Object.class, "cloneObject", Object.class));
|
var clone = dependencyInfo.getMethod(new MethodReference(Object.class, "cloneObject", Object.class));
|
||||||
if (clone != null) {
|
if (clone != null) {
|
||||||
var classNames = clone.getVariable(0).getTypes();
|
var classNames = clone.getVariable(0).getTypes();
|
||||||
|
@ -182,6 +194,10 @@ public class ClassMetadataRequirements {
|
||||||
return hasArrayLength;
|
return hasArrayLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasArrayCopy() {
|
||||||
|
return hasArrayCopy;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasEnumConstants() {
|
public boolean hasEnumConstants() {
|
||||||
return hasEnumConstants;
|
return hasEnumConstants;
|
||||||
}
|
}
|
||||||
|
@ -240,6 +256,7 @@ public class ClassMetadataRequirements {
|
||||||
boolean newArray;
|
boolean newArray;
|
||||||
boolean arrayLength;
|
boolean arrayLength;
|
||||||
boolean arrayGet;
|
boolean arrayGet;
|
||||||
|
boolean arrayCopy;
|
||||||
boolean cloneMethod;
|
boolean cloneMethod;
|
||||||
boolean enumConstants;
|
boolean enumConstants;
|
||||||
|
|
||||||
|
@ -283,6 +300,11 @@ public class ClassMetadataRequirements {
|
||||||
return arrayLength;
|
return arrayLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean arrayCopy() {
|
||||||
|
return arrayCopy;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean arrayGet() {
|
public boolean arrayGet() {
|
||||||
return arrayGet;
|
return arrayGet;
|
||||||
|
@ -318,6 +340,8 @@ public class ClassMetadataRequirements {
|
||||||
|
|
||||||
boolean arrayGet();
|
boolean arrayGet();
|
||||||
|
|
||||||
|
boolean arrayCopy();
|
||||||
|
|
||||||
boolean cloneMethod();
|
boolean cloneMethod();
|
||||||
|
|
||||||
boolean enumConstants();
|
boolean enumConstants();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user