From 76ca3f06cf305a81f3fb6d0e9eacf19fa5f77a49 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sun, 13 May 2018 23:27:27 +0300 Subject: [PATCH] C backend: make compiled binary independent of load location --- .../java/org/teavm/backend/c/CTarget.java | 2 + .../c/intrinsic/RuntimeClassIntrinsic.java | 53 ++++++++++++++++++ .../org/teavm/backend/wasm/WasmTarget.java | 2 + .../intrinsics/RuntimeClassIntrinsic.java | 56 +++++++++++++++++++ .../java/org/teavm/runtime/Allocator.java | 4 +- .../java/org/teavm/runtime/RuntimeClass.java | 8 ++- .../resources/org/teavm/backend/c/runtime.c | 14 +++-- 7 files changed, 130 insertions(+), 9 deletions(-) create mode 100644 core/src/main/java/org/teavm/backend/c/intrinsic/RuntimeClassIntrinsic.java create mode 100644 core/src/main/java/org/teavm/backend/wasm/intrinsics/RuntimeClassIntrinsic.java diff --git a/core/src/main/java/org/teavm/backend/c/CTarget.java b/core/src/main/java/org/teavm/backend/c/CTarget.java index 648f06743..d5793dafe 100644 --- a/core/src/main/java/org/teavm/backend/c/CTarget.java +++ b/core/src/main/java/org/teavm/backend/c/CTarget.java @@ -53,6 +53,7 @@ import org.teavm.backend.c.intrinsic.PlatformClassIntrinsic; import org.teavm.backend.c.intrinsic.PlatformClassMetadataIntrinsic; import org.teavm.backend.c.intrinsic.PlatformIntrinsic; import org.teavm.backend.c.intrinsic.PlatformObjectIntrinsic; +import org.teavm.backend.c.intrinsic.RuntimeClassIntrinsic; import org.teavm.backend.c.intrinsic.ShadowStackIntrinsic; import org.teavm.backend.c.intrinsic.StructureIntrinsic; import org.teavm.dependency.ClassDependency; @@ -231,6 +232,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost { intrinsics.add(new MutatorIntrinsic()); intrinsics.add(new ExceptionHandlingIntrinsic()); intrinsics.add(new FunctionIntrinsic(characteristics, exportDependencyListener.getResolvedMethods())); + intrinsics.add(new RuntimeClassIntrinsic()); List generators = new ArrayList<>(); generators.add(new ArrayGenerator()); diff --git a/core/src/main/java/org/teavm/backend/c/intrinsic/RuntimeClassIntrinsic.java b/core/src/main/java/org/teavm/backend/c/intrinsic/RuntimeClassIntrinsic.java new file mode 100644 index 000000000..2c8211521 --- /dev/null +++ b/core/src/main/java/org/teavm/backend/c/intrinsic/RuntimeClassIntrinsic.java @@ -0,0 +1,53 @@ +/* + * Copyright 2018 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.c.intrinsic; + +import org.teavm.ast.InvocationExpr; +import org.teavm.model.MethodReference; +import org.teavm.runtime.RuntimeClass; + +public class RuntimeClassIntrinsic implements Intrinsic { + @Override + public boolean canHandle(MethodReference method) { + if (!method.getClassName().equals(RuntimeClass.class.getName())) { + return false; + } + + switch (method.getName()) { + case "pack": + case "unpack": + return true; + default: + return false; + } + } + + @Override + public void apply(IntrinsicContext context, InvocationExpr invocation) { + switch (invocation.getMethod().getName()) { + case "pack": + context.writer().print("PACK_CLASS("); + context.emit(invocation.getArguments().get(0)); + context.writer().print(")"); + break; + case "unpack": + context.writer().print("UNPACK_CLASS("); + context.emit(invocation.getArguments().get(0)); + context.writer().print(")"); + break; + } + } +} diff --git a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java index ce728edeb..93230f438 100644 --- a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java +++ b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java @@ -52,6 +52,7 @@ 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.RuntimeClassIntrinsic; import org.teavm.backend.wasm.intrinsics.ShadowStackIntrinsic; import org.teavm.backend.wasm.intrinsics.StructureIntrinsic; import org.teavm.backend.wasm.intrinsics.WasmIntrinsicFactory; @@ -332,6 +333,7 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost { context.addIntrinsic(new PlatformObjectIntrinsic(classGenerator)); context.addIntrinsic(new PlatformClassMetadataIntrinsic()); context.addIntrinsic(new ClassIntrinsic()); + context.addIntrinsic(new RuntimeClassIntrinsic()); context.addGenerator(new ArrayGenerator()); IntrinsicFactoryContext intrinsicFactoryContext = new IntrinsicFactoryContext(); diff --git a/core/src/main/java/org/teavm/backend/wasm/intrinsics/RuntimeClassIntrinsic.java b/core/src/main/java/org/teavm/backend/wasm/intrinsics/RuntimeClassIntrinsic.java new file mode 100644 index 000000000..345b950ab --- /dev/null +++ b/core/src/main/java/org/teavm/backend/wasm/intrinsics/RuntimeClassIntrinsic.java @@ -0,0 +1,56 @@ +/* + * Copyright 2018 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.intrinsics; + +import org.teavm.ast.InvocationExpr; +import org.teavm.backend.wasm.model.expression.WasmExpression; +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.model.MethodReference; +import org.teavm.runtime.RuntimeClass; + +public class RuntimeClassIntrinsic implements WasmIntrinsic { + @Override + public boolean isApplicable(MethodReference methodReference) { + if (!methodReference.getClassName().equals(RuntimeClass.class.getName())) { + return false; + } + + switch (methodReference.getName()) { + case "pack": + case "unpack": + return true; + default: + return false; + } + } + + @Override + public WasmExpression apply(InvocationExpr invocation, WasmIntrinsicManager manager) { + switch (invocation.getMethod().getName()) { + case "pack": + return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHR_UNSIGNED, + manager.generate(invocation.getArguments().get(0)), new WasmInt32Constant(3)); + case "unpack": + return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.SHL, + manager.generate(invocation.getArguments().get(0)), new WasmInt32Constant(3)); + default: + throw new AssertionError(); + } + } +} diff --git a/core/src/main/java/org/teavm/runtime/Allocator.java b/core/src/main/java/org/teavm/runtime/Allocator.java index af7c9314b..5e49084fe 100644 --- a/core/src/main/java/org/teavm/runtime/Allocator.java +++ b/core/src/main/java/org/teavm/runtime/Allocator.java @@ -28,7 +28,7 @@ public final class Allocator { public static Address allocate(RuntimeClass tag) { RuntimeObject object = GC.alloc(tag.size); fillZero(object.toAddress(), tag.size); - object.classReference = tag.toAddress().toInt() >> 3; + object.classReference = tag.pack(); return object.toAddress(); } @@ -41,7 +41,7 @@ public final class Allocator { fillZero(result, sizeInBytes); RuntimeArray array = result.toStructure(); - array.classReference = tag.toAddress().toInt() >> 3; + array.classReference = tag.pack(); array.size = size; return result; diff --git a/core/src/main/java/org/teavm/runtime/RuntimeClass.java b/core/src/main/java/org/teavm/runtime/RuntimeClass.java index 2cdf30ecb..76304b91f 100644 --- a/core/src/main/java/org/teavm/runtime/RuntimeClass.java +++ b/core/src/main/java/org/teavm/runtime/RuntimeClass.java @@ -61,6 +61,12 @@ public class RuntimeClass extends RuntimeObject { @Unmanaged public static RuntimeClass getClass(RuntimeObject object) { - return Address.fromInt(object.classReference << 3).toStructure(); + return unpack(object.classReference); } + + @Unmanaged + public static native RuntimeClass unpack(int n); + + @Unmanaged + public final native int pack(); } diff --git a/core/src/main/resources/org/teavm/backend/c/runtime.c b/core/src/main/resources/org/teavm/backend/c/runtime.c index a093e27f1..d024a30f5 100644 --- a/core/src/main/resources/org/teavm/backend/c/runtime.c +++ b/core/src/main/resources/org/teavm/backend/c/runtime.c @@ -29,8 +29,8 @@ typedef struct JavaArray JavaArray; typedef struct JavaClass JavaClass; typedef struct JavaString JavaString; -#define PACK_CLASS(cls) ((int32_t) (((uintptr_t) (cls)) >> 3)) -#define UNPACK_CLASS(cls) ((JavaClass *) (uintptr_t) (uint32_t) (uintptr_t) (((int64_t*) NULL) + cls)) +#define PACK_CLASS(cls) ((int32_t) ((uintptr_t) ((char*) (cls) - (char*) &TeaVM_beforeClasses) >> 3)) +#define UNPACK_CLASS(cls) ((JavaClass*) ((char*) &TeaVM_beforeClasses + ((cls) << 3))) #define CLASS_OF(obj) (UNPACK_CLASS(((JavaObject*) (obj))->header)) #define AS(ptr, type) ((type*) (ptr)) @@ -65,10 +65,10 @@ static inline int32_t instanceof(void*, int32_t (*)(JavaClass*)); static inline void* checkcast(void*, int32_t (*)(JavaClass*)); #define ALLOC_STACK(size) \ - void* __shadowStack__[(size) + 3]; \ - __shadowStack__[0] = stackTop; \ - __shadowStack__[2] = (void*) size; \ - stackTop = __shadowStack__ + void* __shadowStack__[(size) + 3]; \ + __shadowStack__[0] = stackTop; \ + __shadowStack__[2] = (void*) size; \ + stackTop = __shadowStack__ #define RELEASE_STACK stackTop = __shadowStack__[0] #define GC_ROOT(index, ptr) __shadowStack__[3 + (index)] = ptr @@ -106,6 +106,8 @@ static int32_t gc_regionSize = INT32_C(32768); static int32_t gc_regionMaxCount = INT32_C(0); static int64_t gc_availableBytes = INT64_C(0); +static char TeaVM_beforeClasses[128] = "TEAVM"; + static double TeaVM_rand() { return rand() / ((double) RAND_MAX + 1); }