C backend: make compiled binary independent of load location

This commit is contained in:
Alexey Andreev 2018-05-13 23:27:27 +03:00
parent 8cf69db8bb
commit 76ca3f06cf
7 changed files with 130 additions and 9 deletions

View File

@ -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<Generator> generators = new ArrayList<>();
generators.add(new ArrayGenerator());

View File

@ -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;
}
}
}

View File

@ -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();

View File

@ -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();
}
}
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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);
}