This commit is contained in:
Alexey Andreev 2016-09-01 00:23:13 +03:00
parent 1ae683ead3
commit bb4040af23
8 changed files with 118 additions and 70 deletions

View File

@ -15,8 +15,11 @@
*/
package org.teavm.classlib.java.lang;
import org.teavm.interop.Address;
import org.teavm.interop.Async;
import org.teavm.interop.DelegateTo;
import org.teavm.interop.Rename;
import org.teavm.interop.Structure;
import org.teavm.interop.Superclass;
import org.teavm.interop.Sync;
import org.teavm.jso.browser.TimerHandler;
@ -25,6 +28,11 @@ import org.teavm.platform.PlatformObject;
import org.teavm.platform.PlatformQueue;
import org.teavm.platform.PlatformRunnable;
import org.teavm.platform.async.AsyncCallback;
import org.teavm.runtime.Allocator;
import org.teavm.runtime.RuntimeArray;
import org.teavm.runtime.RuntimeClass;
import org.teavm.runtime.RuntimeJavaObject;
import org.teavm.runtime.RuntimeObject;
/**
*
@ -191,6 +199,7 @@ public class TObject {
return getClass().getName() + "@" + TInteger.toHexString(identity());
}
@DelegateTo("identityLowLevel")
int identity() {
PlatformObject platformThis = Platform.getPlatformObject(this);
if (platformThis.getId() == 0) {
@ -199,7 +208,24 @@ public class TObject {
return Platform.getPlatformObject(this).getId();
}
@SuppressWarnings("unused")
private static int identityLowLevel(RuntimeJavaObject object) {
if ((object.classReference & RuntimeObject.MONITOR_EXISTS) != 0) {
object = (RuntimeJavaObject) object.monitor;
}
int result = object.monitor.toAddress().toInt();
if (result == 0) {
result = RuntimeJavaObject.nextId++;
if (result == 0) {
result = RuntimeJavaObject.nextId++;
}
object.monitor = Address.fromInt(result).toStructure();
}
return result;
}
@Override
@DelegateTo("cloneLowLevel")
protected Object clone() throws TCloneNotSupportedException {
if (!(this instanceof TCloneable) && Platform.getPlatformObject(this)
.getPlatformClass().getMetadata().getArrayItem() == null) {
@ -210,6 +236,28 @@ public class TObject {
return result;
}
@SuppressWarnings("unused")
private static RuntimeJavaObject cloneLowLevel(RuntimeJavaObject self) {
RuntimeClass cls = RuntimeClass.getClass(self);
int skip = Structure.sizeOf(RuntimeJavaObject.class);
int size;
RuntimeJavaObject copy;
if (cls.itemType == null) {
copy = Allocator.allocate(cls).toStructure();
size = cls.size;
} else {
RuntimeArray array = (RuntimeArray) self;
copy = Allocator.allocateArray(cls, array.size).toStructure();
int itemSize = (cls.itemType.flags & RuntimeClass.PRIMITIVE) == 0 ? 4 : cls.itemType.size;
Address headerSize = Address.align(Address.fromInt(Structure.sizeOf(RuntimeArray.class)), itemSize);
size = itemSize * array.size + headerSize.toInt();
}
if (size > skip) {
Allocator.moveMemoryBlock(self.toAddress().add(skip), copy.toAddress().add(skip), size - skip);
}
return copy;
}
@Sync
@Rename("notify")
public final void notify0() {

View File

@ -33,6 +33,7 @@ public final class Example {
testHashCode();
testArrayList();
testArrayCopy();
testArrayIsObject();
}
private static void testFibonacci() {
@ -121,6 +122,15 @@ public final class Example {
println(sb.toString());
}
private static void testArrayIsObject() {
byte[] array = new byte[] { 1, 2, 3 };
byte[] copy = array.clone();
println("array.hashCode() = " + array.hashCode());
println("copy.hashCode() = " + copy.hashCode());
println("array.equals(array) = " + array.equals(array));
println("array.equals(copy) = " + array.equals(copy));
}
private static Base instance(int index) {
switch (index) {
case 0:

View File

@ -31,6 +31,7 @@ import org.teavm.backend.wasm.generate.WasmClassGenerator;
import org.teavm.backend.wasm.generate.WasmDependencyListener;
import org.teavm.backend.wasm.generate.WasmGenerationContext;
import org.teavm.backend.wasm.generate.WasmGenerator;
import org.teavm.backend.wasm.generate.WasmGeneratorUtil;
import org.teavm.backend.wasm.generate.WasmMangling;
import org.teavm.backend.wasm.generate.WasmStringPool;
import org.teavm.backend.wasm.intrinsics.AddressIntrinsic;
@ -43,13 +44,16 @@ import org.teavm.backend.wasm.intrinsics.PlatformObjectIntrinsic;
import org.teavm.backend.wasm.intrinsics.StructureIntrinsic;
import org.teavm.backend.wasm.intrinsics.WasmRuntimeIntrinsic;
import org.teavm.backend.wasm.model.WasmFunction;
import org.teavm.backend.wasm.model.WasmLocal;
import org.teavm.backend.wasm.model.WasmMemorySegment;
import org.teavm.backend.wasm.model.WasmModule;
import org.teavm.backend.wasm.model.WasmType;
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.WasmDrop;
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.WasmInt32Subtype;
import org.teavm.backend.wasm.model.expression.WasmIntBinary;
@ -59,7 +63,6 @@ import org.teavm.backend.wasm.model.expression.WasmLoadInt32;
import org.teavm.backend.wasm.model.expression.WasmReturn;
import org.teavm.backend.wasm.model.expression.WasmStoreInt32;
import org.teavm.backend.wasm.patches.ClassPatch;
import org.teavm.backend.wasm.patches.ObjectPatch;
import org.teavm.backend.wasm.render.WasmCRenderer;
import org.teavm.dependency.ClassDependency;
import org.teavm.dependency.DependencyChecker;
@ -124,7 +127,6 @@ public class WasmTarget implements TeaVMTarget {
@Override
public List<ClassHolderTransformer> getTransformers() {
List<ClassHolderTransformer> transformers = new ArrayList<>();
transformers.add(new ObjectPatch());
transformers.add(new ClassPatch());
transformers.add(new WasmDependencyListener());
return transformers;
@ -257,7 +259,11 @@ public class WasmTarget implements TeaVMTarget {
if (implementor.getProgram() == null || implementor.getProgram().basicBlockCount() == 0) {
continue;
}
module.add(generator.generate(method.getReference(), implementor));
if (method == implementor) {
module.add(generator.generate(method.getReference(), implementor));
} else {
module.add(generateStub(method, implementor));
}
if (controller.wasCancelled()) {
return;
}
@ -328,6 +334,33 @@ public class WasmTarget implements TeaVMTarget {
}
}
private WasmFunction generateStub(MethodHolder method, MethodHolder implementor) {
WasmFunction function = new WasmFunction(WasmMangling.mangleMethod(method.getReference()));
if (!method.hasModifier(ElementModifier.STATIC)) {
function.getParameters().add(WasmType.INT32);
}
ValueType[] parameterTypes = method.getParameterTypes();
for (ValueType parameterType : parameterTypes) {
function.getParameters().add(WasmGeneratorUtil.mapType(parameterType));
}
WasmCall call = new WasmCall(WasmMangling.mangleMethod(implementor.getReference()));
for (WasmType param : function.getParameters()) {
WasmLocal local = new WasmLocal(param);
function.add(local);
call.getArguments().add(new WasmGetLocal(local));
}
function.setResult(WasmGeneratorUtil.mapType(method.getResultType()));
if (method.getResultType() == ValueType.VOID) {
function.getBody().add(new WasmDrop(call));
} else {
function.getBody().add(new WasmReturn(call));
}
return function;
}
private void renderClinit(ListableClassReaderSource classes, WasmClassGenerator classGenerator,
WasmModule module) {
for (String className : classes.getClassNames()) {

View File

@ -123,11 +123,20 @@ public class WasmClassGenerator {
addClass(itemType);
ClassBinaryData itemBinaryData = binaryDataMap.get(itemType);
VirtualTable vtable = vtableProvider.lookup("java.lang.Object");
int vtableSize = vtable != null ? vtable.getEntries().size() : 0;
DataType arrayType = new DataArray(DataPrimitives.INT, vtableSize);
DataValue wrapper = new DataStructure((byte) 0, classStructure, arrayType).createValue();
if (vtableSize > 0) {
fillVirtualTable(vtable, wrapper.getValue(1));
}
binaryData.size = 4;
binaryData.data = classStructure.createValue();
binaryData.data = wrapper.getValue(0);
binaryData.data.setInt(1, 4);
binaryData.data.setAddress(5, itemBinaryData.start);
binaryData.start = binaryWriter.append(binaryData.data);
binaryData.start = binaryWriter.append(vtableSize > 0 ? wrapper : binaryData.data);
itemBinaryData.data.setAddress(6, binaryData.start);
}
@ -161,10 +170,15 @@ public class WasmClassGenerator {
int tag = ranges.stream().mapToInt(range -> range.lower).min().orElse(0);
header.setInt(3, tag);
header.setInt(4, RuntimeClass.computeCanary(binaryData.size, tag));
if (vtable == null) {
return header;
if (vtable != null) {
fillVirtualTable(vtable, array);
}
return vtable != null ? wrapper : header;
}
private void fillVirtualTable(VirtualTable vtable, DataValue array) {
int index = 0;
for (VirtualTableEntry vtableEntry : vtable.getEntries().values()) {
int methodIndex;
@ -180,8 +194,6 @@ public class WasmClassGenerator {
array.setInt(index++, methodIndex);
}
return wrapper;
}
public int getClassPointer(ValueType type) {

View File

@ -37,7 +37,6 @@ public class ClassPatch implements ClassHolderTransformer {
if (!cls.getName().equals("java.lang.Class")) {
return;
}
for (MethodHolder method : cls.getMethods()) {
patchProgram(method.getProgram());
}

View File

@ -1,59 +0,0 @@
/*
* Copyright 2016 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.patches;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.interop.Address;
import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderTransformer;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodHolder;
import org.teavm.model.Program;
import org.teavm.model.util.ProgramUtils;
import org.teavm.runtime.RuntimeJavaObject;
import org.teavm.runtime.RuntimeObject;
public class ObjectPatch implements ClassHolderTransformer {
@Override
public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) {
if (!cls.getName().equals("java.lang.Object")) {
return;
}
MethodHolder method = cls.getMethod(new MethodDescriptor("identity", int.class));
Program patchedProgram = ProgramUtils.copy(innerSource.get(ObjectPatch.class.getName())
.getMethod(new MethodDescriptor("patchedIdentity", int.class)).getProgram());
method.setProgram(patchedProgram);
}
@SuppressWarnings("unused")
private int patchedIdentity() {
RuntimeJavaObject object = Address.ofObject(this).toStructure();
if ((object.classReference & RuntimeObject.MONITOR_EXISTS) != 0) {
object = (RuntimeJavaObject) object.monitor;
}
int result = object.monitor.toAddress().toInt();
if (result == 0) {
result = RuntimeJavaObject.nextId++;
if (result == 0) {
result = RuntimeJavaObject.nextId++;
}
object.monitor = Address.fromInt(result).toStructure();
}
return result;
}
}

View File

@ -121,7 +121,7 @@ public class WasmCRenderer {
indent();
for (int i = 0; i < module.getFunctionTable().size() - 1; ++i) {
WasmFunction function = module.getFunctionTable().get(i);
line(function.getName() + ",");
line((function != null ? function.getName() : "unknown") + ",");
}
line(module.getFunctionTable().get(module.getFunctionTable().size() - 1).getName());
outdent();

View File

@ -643,6 +643,11 @@ class DependencyGraphBuilder {
arrayNode.addConsumer(receiverNode::propagate);
arrayNode.getArrayItem().connect(receiverNode.getArrayItem());
}
MethodDependency cloneDep = dependencyChecker.linkMethod(
new MethodReference(Object.class, "clone", Object.class),
new CallLocation(caller.getMethod(), currentLocation));
arrayNode.connect(cloneDep.getVariable(0));
cloneDep.use();
}
@Override