Add support of Object.hashCode

This commit is contained in:
Alexey Andreev 2016-08-19 12:36:09 +03:00
parent 8c6cf1840b
commit 35b59ed916
13 changed files with 146 additions and 10 deletions

View File

@ -49,6 +49,7 @@ import org.teavm.javascript.spi.Injector;
import org.teavm.model.BasicBlock;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderTransformer;
import org.teavm.model.ElementModifier;
import org.teavm.model.InstructionLocation;
import org.teavm.model.ListableClassHolderSource;
@ -82,6 +83,11 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
private final Set<MethodReference> asyncMethods = new HashSet<>();
private final Set<MethodReference> asyncFamilyMethods = new HashSet<>();
@Override
public List<ClassHolderTransformer> getTransformers() {
return Collections.emptyList();
}
@Override
public void setController(TeaVMTargetController controller) {
this.controller = controller;

View File

@ -15,7 +15,6 @@
*/
package org.teavm.runtime;
public class RuntimeArray extends RuntimeObject {
RuntimeObject monitor;
public class RuntimeArray extends RuntimeJavaObject {
int size;
}

View File

@ -0,0 +1,21 @@
/*
* 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.runtime;
public class RuntimeJavaObject extends RuntimeObject {
public static int nextId = 1;
public RuntimeObject monitor;
}

View File

@ -18,5 +18,8 @@ package org.teavm.runtime;
import org.teavm.interop.Structure;
public class RuntimeObject extends Structure {
public static final int GC_MARKED = 0x80000000;
public static final int MONITOR_EXISTS = 0x20000000;
public int classReference;
}

View File

@ -134,6 +134,10 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
}
};
for (ClassHolderTransformer transformer : target.getTransformers()) {
dependencyChecker.addClassTransformer(transformer);
}
for (TeaVMHostExtension extension : target.getHostExtensions()) {
for (Class<?> extensionType : getExtensionTypes(extension)) {
extensions.put(extensionType, extension);

View File

@ -18,10 +18,13 @@ package org.teavm.vm;
import java.io.OutputStream;
import java.util.List;
import org.teavm.dependency.DependencyChecker;
import org.teavm.model.ClassHolderTransformer;
import org.teavm.model.ListableClassHolderSource;
import org.teavm.vm.spi.TeaVMHostExtension;
public interface TeaVMTarget {
List<ClassHolderTransformer> getTransformers();
void setController(TeaVMTargetController controller);
List<TeaVMHostExtension> getHostExtensions();

View File

@ -60,6 +60,12 @@ public final class Example {
Initialized.foo();
Initialized.foo();
Initialized.foo();
Object o = new Object();
WasmRuntime.print(o.hashCode());
WasmRuntime.print(o.hashCode());
WasmRuntime.print(new Object().hashCode());
WasmRuntime.print(new Object().hashCode());
}
private static Base instance(int index) {

View File

@ -20,6 +20,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
@ -33,6 +34,7 @@ import org.teavm.interop.StaticInit;
import org.teavm.model.BasicBlock;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassHolder;
import org.teavm.model.ClassHolderTransformer;
import org.teavm.model.ClassReader;
import org.teavm.model.ElementModifier;
import org.teavm.model.FieldReference;
@ -84,6 +86,7 @@ import org.teavm.wasm.model.expression.WasmIntType;
import org.teavm.wasm.model.expression.WasmLoadInt32;
import org.teavm.wasm.model.expression.WasmReturn;
import org.teavm.wasm.model.expression.WasmStoreInt32;
import org.teavm.wasm.patches.ObjectPatch;
import org.teavm.wasm.render.WasmRenderer;
public class WasmTarget implements TeaVMTarget {
@ -104,6 +107,13 @@ public class WasmTarget implements TeaVMTarget {
return true;
}
@Override
public List<ClassHolderTransformer> getTransformers() {
List<ClassHolderTransformer> transformers = new ArrayList<>();
transformers.add(new ObjectPatch());
return transformers;
}
@Override
public void contributeDependencies(DependencyChecker dependencyChecker) {
for (Class type : Arrays.asList(int.class, long.class, float.class, double.class)) {

View File

@ -62,9 +62,7 @@ import org.teavm.ast.UnwrapArrayExpr;
import org.teavm.ast.VariableExpr;
import org.teavm.ast.WhileStatement;
import org.teavm.interop.Address;
import org.teavm.model.ClassReader;
import org.teavm.model.FieldReference;
import org.teavm.model.MethodDescriptor;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
import org.teavm.model.classes.TagRegistry;
@ -111,6 +109,7 @@ import org.teavm.wasm.model.expression.WasmStoreFloat64;
import org.teavm.wasm.model.expression.WasmStoreInt32;
import org.teavm.wasm.model.expression.WasmStoreInt64;
import org.teavm.wasm.model.expression.WasmSwitch;
import org.teavm.wasm.model.expression.WasmUnreachable;
class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
private WasmGenerationContext context;
@ -735,6 +734,23 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
call.getArguments().add(result);
}
result = call;
} else if (expr.getType() == InvocationType.CONSTRUCTOR) {
WasmBlock block = new WasmBlock(false);
WasmLocal tmp = function.getLocalVariables().get(getTemporaryInt32());
block.getBody().add(new WasmSetLocal(tmp, allocateObject(expr.getMethod().getClassName())));
String methodName = WasmMangling.mangleMethod(expr.getMethod());
WasmCall call = new WasmCall(methodName);
call.getArguments().add(new WasmGetLocal(tmp));
for (Expr argument : expr.getArguments()) {
argument.acceptVisitor(this);
call.getArguments().add(result);
}
block.getBody().add(call);
block.getBody().add(new WasmGetLocal(tmp));
result = block;
} else {
expr.getArguments().get(0).acceptVisitor(this);
WasmExpression instance = result;
@ -860,12 +876,16 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
@Override
public void visit(NewExpr expr) {
int tag = classGenerator.getClassPointer(ValueType.object(expr.getConstructedClass()));
result = allocateObject(expr.getConstructedClass());
}
private WasmExpression allocateObject(String className) {
int tag = classGenerator.getClassPointer(ValueType.object(className));
String allocName = WasmMangling.mangleMethod(new MethodReference(Allocator.class, "allocate",
RuntimeClass.class, Address.class));
WasmCall call = new WasmCall(allocName);
call.getArguments().add(new WasmInt32Constant(tag));
result = call;
return call;
}
@Override
@ -952,7 +972,13 @@ class WasmGenerationVisitor implements StatementVisitor, ExprVisitor {
@Override
public void visit(ThrowStatement statement) {
WasmBlock block = new WasmBlock(false);
statement.getException().acceptVisitor(this);
block.getBody().add(result);
block.getBody().add(new WasmUnreachable());
result = block;
}
@Override

View File

@ -53,6 +53,7 @@ public class WasmAddressIntrinsic implements WasmIntrinsic {
return new WasmConversion(WasmType.INT32, WasmType.INT64, false, value);
}
case "fromInt":
case "ofObject":
return manager.generate(invocation.getArguments().get(0));
case "fromLong": {
WasmExpression value = manager.generate(invocation.getArguments().get(0));

View File

@ -0,0 +1,59 @@
/*
* 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.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

@ -57,4 +57,6 @@ public final class Address {
public static native Address fromInt(int value);
public static native Address fromLong(long value);
public static native Address ofObject(Object obj);
}

View File

@ -17,10 +17,6 @@ package org.teavm.interop;
import java.lang.annotation.*;
/**
*
* @author Alexey Andreev
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.CONSTRUCTOR })
public @interface Rename {