mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Implementing System.arraycopy
This commit is contained in:
parent
cc9af93021
commit
ca3258417b
|
@ -21,11 +21,13 @@ import org.teavm.classlib.java.io.TPrintStream;
|
|||
import org.teavm.classlib.java.lang.reflect.TArray;
|
||||
import org.teavm.dependency.PluggableDependency;
|
||||
import org.teavm.backend.javascript.spi.GeneratedBy;
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.DelegateTo;
|
||||
import org.teavm.interop.Structure;
|
||||
import org.teavm.runtime.Allocator;
|
||||
import org.teavm.runtime.RuntimeArray;
|
||||
import org.teavm.runtime.RuntimeClass;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public final class TSystem extends TObject {
|
||||
public static final TPrintStream out = new TPrintStream(new TConsoleOutputStreamStdout(), false);
|
||||
public static final TPrintStream err = new TPrintStream(new TConsoleOutputStreamStderr(), false);
|
||||
|
@ -74,8 +76,25 @@ public final class TSystem extends TObject {
|
|||
}
|
||||
|
||||
@GeneratedBy(SystemNativeGenerator.class)
|
||||
@DelegateTo("doArrayCopyLowLevel")
|
||||
private static native void doArrayCopy(Object src, int srcPos, Object dest, int destPos, int length);
|
||||
|
||||
static void doArrayCopyLowLevel(RuntimeArray src, int srcPos, RuntimeArray dest, int destPos, int length) {
|
||||
RuntimeClass type = Address.fromInt(src.classReference << 3).toStructure();
|
||||
int itemSize = type.itemType.size;
|
||||
if ((type.itemType.flags & RuntimeClass.PRIMITIVE) == 0) {
|
||||
itemSize = Address.sizeOf();
|
||||
}
|
||||
|
||||
Address srcAddress = Address.align(src.toAddress().add(RuntimeArray.class, 1), itemSize);
|
||||
srcAddress = srcAddress.add(itemSize * srcPos);
|
||||
|
||||
Address destAddress = Address.align(dest.toAddress().add(RuntimeArray.class, 1), itemSize);
|
||||
destAddress = destAddress.add(itemSize * destPos);
|
||||
|
||||
Allocator.moveMemoryBlock(srcAddress, destAddress, length * itemSize);
|
||||
}
|
||||
|
||||
@GeneratedBy(SystemNativeGenerator.class)
|
||||
public static native long currentTimeMillis();
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ public final class Example {
|
|||
testLazyInitialization();
|
||||
testHashCode();
|
||||
testArrayList();
|
||||
//testArrayCopy();
|
||||
}
|
||||
|
||||
private static void testFibonacci() {
|
||||
|
@ -101,6 +102,25 @@ public final class Example {
|
|||
}
|
||||
}
|
||||
|
||||
private static void testArrayCopy() {
|
||||
byte[] array = new byte[100];
|
||||
byte[] negatives = new byte[100];
|
||||
for (int i = 0; i < array.length; ++i) {
|
||||
array[i] = (byte) i;
|
||||
negatives[i] = (byte) -i;
|
||||
}
|
||||
System.arraycopy(negatives, 4, array, 0, 12);
|
||||
System.arraycopy(negatives, 1, array, 21, 12);
|
||||
System.arraycopy(negatives, 2, array, 35, 12);
|
||||
System.arraycopy(negatives, 1, array, 8, 3);
|
||||
System.arraycopy(array, 50, array, 54, 12);
|
||||
StringBuilder sb = new StringBuilder("arrayCopy result:");
|
||||
for (int i = 0; i < array.length; ++i) {
|
||||
sb.append(" ").append(array[i]);
|
||||
}
|
||||
println(sb.toString());
|
||||
}
|
||||
|
||||
private static Base instance(int index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
|
|
|
@ -166,7 +166,7 @@ public final class WasmRuntime {
|
|||
return (a << 56) | (b << 48) | (c << 40) | (d << 32) | (e << 24) | (f << 16) | (g << 8) | h;
|
||||
}
|
||||
|
||||
private static Address align(Address address, int alignment) {
|
||||
public static Address align(Address address, int alignment) {
|
||||
int value = address.toInt();
|
||||
if (value == 0) {
|
||||
return address;
|
||||
|
@ -232,8 +232,125 @@ public final class WasmRuntime {
|
|||
break;
|
||||
}
|
||||
|
||||
for (address = Address.fromInt(alignedStart + 1); address.toInt() < alignedEnd; address = address.add(4)) {
|
||||
for (address = Address.fromInt(alignedStart + 4); address.toInt() < alignedEnd; address = address.add(4)) {
|
||||
address.putInt(0);
|
||||
}
|
||||
}
|
||||
|
||||
public static void moveMemoryBlock(Address source, Address target, int count) {
|
||||
if (count < 8) {
|
||||
slowMemoryMove(source, target, count);
|
||||
}
|
||||
int diff = source.toInt() - target.toInt();
|
||||
if (diff == 0) {
|
||||
return;
|
||||
}
|
||||
if ((diff & 3) != 0) {
|
||||
slowMemoryMove(source, target, count);
|
||||
return;
|
||||
}
|
||||
|
||||
Address alignedSourceStart = Address.fromInt(source.toInt() >>> 2 << 2);
|
||||
Address alignedTargetStart = Address.fromInt(target.toInt() >>> 2 << 2);
|
||||
|
||||
Address alignedSourceEnd = Address.fromInt((source.toInt() + count) >>> 2 << 2);
|
||||
Address alignedTargetEnd = Address.fromInt((target.toInt() + count) >>> 2 << 2);
|
||||
|
||||
if (source.toInt() > target.toInt()) {
|
||||
switch (source.toInt() - alignedSourceStart.toInt()) {
|
||||
case 0:
|
||||
alignedTargetStart.putInt(alignedSourceStart.getInt());
|
||||
break;
|
||||
case 1:
|
||||
alignedTargetStart.add(3).putByte(alignedSourceStart.add(3).getByte());
|
||||
break;
|
||||
case 2:
|
||||
alignedTargetStart.add(2).putShort(alignedSourceStart.add(2).getShort());
|
||||
break;
|
||||
case 3:
|
||||
alignedTargetStart.add(1).putByte(alignedSourceStart.add(1).getByte());
|
||||
alignedTargetStart.add(2).putShort(alignedSourceStart.add(2).getShort());
|
||||
break;
|
||||
}
|
||||
|
||||
alignedSourceStart = alignedSourceStart.add(4);
|
||||
alignedTargetStart = alignedTargetStart.add(4);
|
||||
|
||||
while (alignedSourceStart.toInt() < alignedSourceEnd.toInt()) {
|
||||
alignedTargetStart.putInt(alignedSourceStart.getInt());
|
||||
alignedSourceStart = alignedSourceStart.add(4);
|
||||
alignedTargetStart = alignedTargetStart.add(4);
|
||||
}
|
||||
|
||||
switch (source.getInt() + count - alignedSourceEnd.getInt()) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
alignedTargetEnd.putByte(alignedSourceEnd.getByte());
|
||||
break;
|
||||
case 2:
|
||||
alignedTargetEnd.putShort(alignedSourceEnd.getShort());
|
||||
break;
|
||||
case 3:
|
||||
alignedTargetEnd.putShort(alignedSourceEnd.getShort());
|
||||
alignedTargetEnd.add(2).putByte(alignedSourceEnd.add(2).getByte());
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (source.getInt() + count - alignedSourceEnd.getInt()) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
alignedTargetEnd.putByte(alignedSourceEnd.getByte());
|
||||
break;
|
||||
case 2:
|
||||
alignedTargetEnd.putShort(alignedSourceEnd.getShort());
|
||||
break;
|
||||
case 3:
|
||||
alignedTargetEnd.add(2).putByte(alignedSourceEnd.add(2).getByte());
|
||||
alignedTargetEnd.putShort(alignedSourceEnd.getShort());
|
||||
break;
|
||||
}
|
||||
|
||||
while (alignedSourceEnd.toInt() > alignedTargetEnd.toInt()) {
|
||||
alignedTargetEnd.putInt(alignedSourceEnd.getInt());
|
||||
alignedSourceEnd = alignedSourceEnd.add(-4);
|
||||
alignedTargetEnd = alignedTargetEnd.add(-4);
|
||||
}
|
||||
|
||||
switch (source.toInt() - alignedSourceStart.toInt()) {
|
||||
case 0:
|
||||
alignedTargetStart.putInt(alignedSourceStart.getInt());
|
||||
break;
|
||||
case 1:
|
||||
alignedTargetStart.add(3).putByte(alignedSourceStart.add(3).getByte());
|
||||
break;
|
||||
case 2:
|
||||
alignedTargetStart.add(2).putShort(alignedSourceStart.add(2).getShort());
|
||||
break;
|
||||
case 3:
|
||||
alignedTargetStart.add(2).putShort(alignedSourceStart.add(2).getShort());
|
||||
alignedTargetStart.add(1).putByte(alignedSourceStart.add(1).getByte());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void slowMemoryMove(Address source, Address target, int count) {
|
||||
if (source.toInt() > target.toInt()) {
|
||||
while (count-- > 0) {
|
||||
target.putByte(source.getByte());
|
||||
target = target.add(1);
|
||||
source = source.add(1);
|
||||
}
|
||||
} else {
|
||||
source.add(count);
|
||||
target.add(count);
|
||||
while (count-- > 0) {
|
||||
target = target.add(-1);
|
||||
source = source.add(-1);
|
||||
target.putByte(source.getByte());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,13 +33,13 @@ import org.teavm.backend.wasm.generate.WasmGenerationContext;
|
|||
import org.teavm.backend.wasm.generate.WasmGenerator;
|
||||
import org.teavm.backend.wasm.generate.WasmMangling;
|
||||
import org.teavm.backend.wasm.generate.WasmStringPool;
|
||||
import org.teavm.backend.wasm.intrinsics.AddressIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.AllocatorIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.ClassIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.PlatformClassIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.PlatformClassMetadataIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.PlatformIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.PlatformObjectIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.WasmAddressIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.WasmRuntimeIntrinsic;
|
||||
import org.teavm.backend.wasm.intrinsics.WasmStructureIntrinsic;
|
||||
import org.teavm.backend.wasm.model.WasmFunction;
|
||||
|
@ -196,7 +196,7 @@ public class WasmTarget implements TeaVMTarget {
|
|||
WasmGenerationContext context = new WasmGenerationContext(classes, controller.getDiagnostics(),
|
||||
vtableProvider, tagRegistry, stringPool);
|
||||
|
||||
context.addIntrinsic(new WasmAddressIntrinsic());
|
||||
context.addIntrinsic(new AddressIntrinsic(classGenerator));
|
||||
context.addIntrinsic(new WasmStructureIntrinsic(classGenerator));
|
||||
context.addIntrinsic(new WasmRuntimeIntrinsic());
|
||||
context.addIntrinsic(new AllocatorIntrinsic());
|
||||
|
@ -293,7 +293,7 @@ public class WasmTarget implements TeaVMTarget {
|
|||
if (clinit == null) {
|
||||
continue;
|
||||
}
|
||||
initFunction.getBody().add(new WasmCall(WasmMangling.mangleMethod(clinit.getReference())));
|
||||
initFunction.getBody().add(new WasmCall(WasmMangling.mangleInitializer(className)));
|
||||
}
|
||||
module.add(initFunction);
|
||||
module.setStartFunction(initFunction);
|
||||
|
|
|
@ -202,6 +202,13 @@ public class WasmClassGenerator {
|
|||
return data.size;
|
||||
}
|
||||
|
||||
public int getClassAlignment(String className) {
|
||||
ValueType type = ValueType.object(className);
|
||||
addClass(type);
|
||||
ClassBinaryData data = binaryDataMap.get(type);
|
||||
return data.alignment;
|
||||
}
|
||||
|
||||
public boolean isStructure(String className) {
|
||||
ValueType type = ValueType.object(className);
|
||||
addClass(type);
|
||||
|
@ -217,11 +224,13 @@ public class WasmClassGenerator {
|
|||
addClass(ValueType.object(cls.getParent()));
|
||||
ClassBinaryData parentData = binaryDataMap.get(ValueType.object(cls.getParent()));
|
||||
data.size = parentData.size;
|
||||
data.alignment = parentData.alignment;
|
||||
if (parentData.start == -1) {
|
||||
data.start = -1;
|
||||
}
|
||||
} else {
|
||||
data.size = 4;
|
||||
data.alignment = 4;
|
||||
}
|
||||
|
||||
for (FieldReader field : cls.getFields()) {
|
||||
|
@ -234,6 +243,9 @@ public class WasmClassGenerator {
|
|||
data.fieldLayout.put(field.getName(), offset);
|
||||
data.size = offset + desiredAlignment;
|
||||
}
|
||||
if (data.alignment == 0) {
|
||||
data.alignment = desiredAlignment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -259,7 +271,7 @@ public class WasmClassGenerator {
|
|||
return DataPrimitives.ADDRESS;
|
||||
}
|
||||
|
||||
private static int align(int base, int alignment) {
|
||||
public static int align(int base, int alignment) {
|
||||
if (base == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -312,6 +324,7 @@ public class WasmClassGenerator {
|
|||
private class ClassBinaryData {
|
||||
ValueType type;
|
||||
int size;
|
||||
int alignment;
|
||||
int start;
|
||||
ObjectIntMap<String> fieldLayout = new ObjectIntOpenHashMap<>();
|
||||
DataValue data;
|
||||
|
|
|
@ -83,9 +83,8 @@ public class WasmGenerator {
|
|||
new WasmInt32Constant(RuntimeClass.INITIALIZED));
|
||||
|
||||
WasmConditional conditional = new WasmConditional(initFlag);
|
||||
MethodReference clinit = new MethodReference(method.getOwnerName(),
|
||||
"<clinit>", ValueType.VOID);
|
||||
conditional.getThenBlock().getBody().add(new WasmCall(WasmMangling.mangleMethod(clinit)));
|
||||
conditional.getThenBlock().getBody().add(new WasmCall(
|
||||
WasmMangling.mangleInitializer(method.getOwnerName())));
|
||||
function.getBody().add(conditional);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,10 +15,17 @@
|
|||
*/
|
||||
package org.teavm.backend.wasm.intrinsics;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
import org.teavm.ast.ConstantExpr;
|
||||
import org.teavm.ast.InvocationExpr;
|
||||
import org.teavm.backend.wasm.WasmRuntime;
|
||||
import org.teavm.backend.wasm.generate.WasmClassGenerator;
|
||||
import org.teavm.backend.wasm.generate.WasmMangling;
|
||||
import org.teavm.backend.wasm.model.WasmType;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||
import org.teavm.backend.wasm.model.expression.WasmConversion;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
|
||||
import org.teavm.backend.wasm.model.expression.WasmInt32Subtype;
|
||||
import org.teavm.backend.wasm.model.expression.WasmInt64Subtype;
|
||||
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
|
||||
|
@ -36,7 +43,13 @@ import org.teavm.interop.Address;
|
|||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
public class WasmAddressIntrinsic implements WasmIntrinsic {
|
||||
public class AddressIntrinsic implements WasmIntrinsic {
|
||||
private WasmClassGenerator classGenerator;
|
||||
|
||||
public AddressIntrinsic(WasmClassGenerator classGenerator) {
|
||||
this.classGenerator = classGenerator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(MethodReference methodReference) {
|
||||
return methodReference.getClassName().equals(Address.class.getName());
|
||||
|
@ -61,11 +74,24 @@ public class WasmAddressIntrinsic implements WasmIntrinsic {
|
|||
}
|
||||
case "add": {
|
||||
WasmExpression base = manager.generate(invocation.getArguments().get(0));
|
||||
WasmExpression offset = manager.generate(invocation.getArguments().get(1));
|
||||
if (invocation.getMethod().parameterType(0) == ValueType.LONG) {
|
||||
offset = new WasmConversion(WasmType.INT64, WasmType.INT32, false, offset);
|
||||
if (invocation.getMethod().parameterCount() == 1) {
|
||||
WasmExpression offset = manager.generate(invocation.getArguments().get(1));
|
||||
if (invocation.getMethod().parameterType(0) == ValueType.LONG) {
|
||||
offset = new WasmConversion(WasmType.INT64, WasmType.INT32, false, offset);
|
||||
}
|
||||
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, base, offset);
|
||||
} else {
|
||||
WasmExpression offset = manager.generate(invocation.getArguments().get(2));
|
||||
Object type = ((ConstantExpr) invocation.getArguments().get(1)).getValue();
|
||||
String className = ((ValueType.Object) type).getClassName();
|
||||
int size = classGenerator.getClassSize(className);
|
||||
int alignment = classGenerator.getClassAlignment(className);
|
||||
size = WasmClassGenerator.align(size, alignment);
|
||||
|
||||
offset = new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.MUL, offset,
|
||||
new WasmInt32Constant(size));
|
||||
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, base, offset);
|
||||
}
|
||||
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD, base, offset);
|
||||
}
|
||||
case "getByte":
|
||||
return new WasmLoadInt32(1, manager.generate(invocation.getArguments().get(0)),
|
||||
|
@ -121,6 +147,17 @@ public class WasmAddressIntrinsic implements WasmIntrinsic {
|
|||
WasmExpression value = manager.generate(invocation.getArguments().get(1));
|
||||
return new WasmStoreFloat64(8, address, value);
|
||||
}
|
||||
case "sizeOf":
|
||||
return new WasmInt32Constant(4);
|
||||
case "align": {
|
||||
MethodReference delegate = new MethodReference(WasmRuntime.class.getName(),
|
||||
invocation.getMethod().getDescriptor());
|
||||
WasmCall call = new WasmCall(WasmMangling.mangleMethod(delegate));
|
||||
call.getArguments().addAll(invocation.getArguments().stream()
|
||||
.map(arg -> manager.generate(arg))
|
||||
.collect(Collectors.toSet()));
|
||||
return call;
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException(invocation.getMethod().toString());
|
||||
}
|
|
@ -21,7 +21,6 @@ import org.teavm.backend.wasm.WasmRuntime;
|
|||
import org.teavm.backend.wasm.generate.WasmMangling;
|
||||
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.runtime.Allocator;
|
||||
|
||||
|
@ -35,9 +34,11 @@ public class AllocatorIntrinsic implements WasmIntrinsic {
|
|||
@Override
|
||||
public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) {
|
||||
switch (invocation.getMethod().getName()) {
|
||||
case "fillZero": {
|
||||
WasmCall call = new WasmCall(WasmMangling.mangleMethod(new MethodReference(WasmRuntime.class,
|
||||
"fillZero", Address.class, int.class, void.class)));
|
||||
case "fillZero":
|
||||
case "moveMemoryBlock": {
|
||||
MethodReference delegateMetod = new MethodReference(WasmRuntime.class.getName(),
|
||||
invocation.getMethod().getDescriptor());
|
||||
WasmCall call = new WasmCall(WasmMangling.mangleMethod(delegateMetod));
|
||||
call.getArguments().addAll(invocation.getArguments().stream().map(manager::generate)
|
||||
.collect(Collectors.toList()));
|
||||
return call;
|
||||
|
|
|
@ -51,4 +51,6 @@ public final class Allocator {
|
|||
}
|
||||
|
||||
public static native void fillZero(Address address, int count);
|
||||
|
||||
public static native void moveMemoryBlock(Address source, Address target, int count);
|
||||
}
|
||||
|
|
|
@ -59,4 +59,10 @@ public final class Address {
|
|||
public static native Address fromLong(long value);
|
||||
|
||||
public static native Address ofObject(Object obj);
|
||||
|
||||
public static native Address align(Address address, int alignment);
|
||||
|
||||
public static native int sizeOf();
|
||||
|
||||
public native Address add(Class<? extends Structure> type, int offset);
|
||||
}
|
||||
|
|
|
@ -21,6 +21,4 @@ public class Structure {
|
|||
public final native Address toAddress();
|
||||
|
||||
public static native int sizeOf(Class<? extends Structure> type);
|
||||
|
||||
public static native <T extends Structure> T add(T base, int offset);
|
||||
}
|
||||
|
|
|
@ -26,10 +26,6 @@ import org.teavm.platform.metadata.ClassResource;
|
|||
import org.teavm.platform.metadata.StaticFieldResource;
|
||||
import org.teavm.platform.plugin.PlatformGenerator;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public final class Platform {
|
||||
private Platform() {
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user