From 44277db2ded3833d5275be7773a2a819afa69052 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 6 Mar 2012 13:03:42 -0700 Subject: [PATCH 1/9] fix handling of exceptions thrown from interpreter during method invocation Since we use Thread::code to store a reference to either the method to be invoked or the current bytecode being executed depending on the context, we must be careful to switch it back to the bytecode of the exception handler if an exception is thrown while invoking a method (e.g. an UnsatisfiedLinkError). --- src/interpret.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/interpret.cpp b/src/interpret.cpp index 6e04cd4942..6f3c853ec6 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -758,6 +758,8 @@ interpret3(Thread* t, const int base) object& exception = t->exception; uintptr_t* stack = t->stack; + code = methodCode(t, frameMethod(t, frame)); + if (UNLIKELY(exception)) { goto throw_; } From e8e3c9066feca6e50d28870292522435d5869c99 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 6 Mar 2012 13:07:59 -0700 Subject: [PATCH 2/9] implement sun.misc.Unsafe raw memory access methods The primitive get/put methods are implemented as intrinsics by the compiler for performance. --- src/builtin.cpp | 174 +++++++++++++++++++++++++++++++++++ src/classpath-openjdk.cpp | 109 ---------------------- src/compile.cpp | 186 ++++++++++++++++++++++++++++++++------ 3 files changed, 332 insertions(+), 137 deletions(-) diff --git a/src/builtin.cpp b/src/builtin.cpp index eed2508564..f7f2c12d29 100644 --- a/src/builtin.cpp +++ b/src/builtin.cpp @@ -327,3 +327,177 @@ Avian_avian_Singleton_getLong (t, reinterpret_cast(arguments[0]), arguments[1]), 8); return v; } + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_allocateMemory +(Thread* t, object, uintptr_t* arguments) +{ + void* p = malloc(arguments[1]); + if (p) { + return reinterpret_cast(p); + } else { + throwNew(t, Machine::OutOfMemoryErrorType); + } +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_freeMemory +(Thread*, object, uintptr_t* arguments) +{ + void* p = reinterpret_cast(arguments[1]); + if (p) { + free(p); + } +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_setMemory +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + int64_t count; memcpy(&count, arguments + 3, 8); + int8_t v = arguments[5]; + + memset(reinterpret_cast(p), v, count); +} + +// NB: The following primitive get/put methods are only used by the +// interpreter. The JIT/AOT compiler implements them as intrinsics, +// so these versions will be ignored. + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putByte__JB +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + int8_t v = arguments[3]; + + *reinterpret_cast(p) = v; +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putShort__JS +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + int16_t v = arguments[3]; + + *reinterpret_cast(p) = v; +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putChar__JC +(Thread* t, object method, uintptr_t* arguments) +{ + Avian_sun_misc_Unsafe_putShort__JS(t, method, arguments); +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putInt__JI +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + int32_t v = arguments[3]; + + *reinterpret_cast(p) = v; +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putFloat__JF +(Thread* t, object method, uintptr_t* arguments) +{ + Avian_sun_misc_Unsafe_putInt__JI(t, method, arguments); +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putLong__JJ +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + int64_t v; memcpy(&v, arguments + 3, 8); + + *reinterpret_cast(p) = v; +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putDouble__JD +(Thread* t, object method, uintptr_t* arguments) +{ + Avian_sun_misc_Unsafe_putLong__JJ(t, method, arguments); +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_putAddress__JJ +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + int64_t v; memcpy(&v, arguments + 3, 8); + + *reinterpret_cast(p) = v; +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getByte__J +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + + return *reinterpret_cast(p); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getShort__J +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + + return *reinterpret_cast(p); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getChar__J +(Thread* t, object method, uintptr_t* arguments) +{ + return Avian_sun_misc_Unsafe_getShort__J(t, method, arguments); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getInt__J +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + + return *reinterpret_cast(p); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getFloat__J +(Thread* t, object method, uintptr_t* arguments) +{ + return Avian_sun_misc_Unsafe_getInt__J(t, method, arguments); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getLong__J +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + + return *reinterpret_cast(p); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getDouble__J +(Thread* t, object method, uintptr_t* arguments) +{ + return Avian_sun_misc_Unsafe_getLong__J(t, method, arguments); +} + +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getAddress__J +(Thread*, object, uintptr_t* arguments) +{ + int64_t p; memcpy(&p, arguments + 1, 8); + + return *reinterpret_cast(p); +} diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index c2b8471dde..977d466c6d 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -2615,115 +2615,6 @@ Avian_sun_misc_Unsafe_compareAndSwapLong #endif } -extern "C" JNIEXPORT int64_t JNICALL -Avian_sun_misc_Unsafe_allocateMemory -(Thread* t, object, uintptr_t* arguments) -{ - void* p = malloc(arguments[1]); - if (p) { - return reinterpret_cast(p); - } else { - throwNew(t, Machine::OutOfMemoryErrorType); - } -} - -extern "C" JNIEXPORT void JNICALL -Avian_sun_misc_Unsafe_freeMemory -(Thread*, object, uintptr_t* arguments) -{ - void* p = reinterpret_cast(arguments[1]); - if (p) { - free(p); - } -} - -extern "C" JNIEXPORT void JNICALL -Avian_sun_misc_Unsafe_setMemory -(Thread*, object, uintptr_t* arguments) -{ - int64_t p; memcpy(&p, arguments + 1, 8); - int64_t count; memcpy(&count, arguments + 3, 8); - int8_t v = arguments[5]; - - memset(reinterpret_cast(p), v, count); -} - -extern "C" JNIEXPORT void JNICALL -Avian_sun_misc_Unsafe_putByte__JB -(Thread*, object, uintptr_t* arguments) -{ - int64_t p; memcpy(&p, arguments + 1, 8); - int8_t v = arguments[3]; - - *reinterpret_cast(p) = v; -} - -extern "C" JNIEXPORT void JNICALL -Avian_sun_misc_Unsafe_putShort__JS -(Thread*, object, uintptr_t* arguments) -{ - int64_t p; memcpy(&p, arguments + 1, 8); - int16_t v = arguments[3]; - - *reinterpret_cast(p) = v; -} - -extern "C" JNIEXPORT void JNICALL -Avian_sun_misc_Unsafe_putLong__JJ -(Thread*, object, uintptr_t* arguments) -{ - int64_t p; memcpy(&p, arguments + 1, 8); - int64_t v; memcpy(&v, arguments + 3, 8); - - *reinterpret_cast(p) = v; -} - -extern "C" JNIEXPORT void JNICALL -Avian_sun_misc_Unsafe_putInt__JI -(Thread*, object, uintptr_t* arguments) -{ - int64_t p; memcpy(&p, arguments + 1, 8); - int32_t v = arguments[3]; - - *reinterpret_cast(p) = v; -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_sun_misc_Unsafe_getByte__J -(Thread*, object, uintptr_t* arguments) -{ - int64_t p; memcpy(&p, arguments + 1, 8); - - return *reinterpret_cast(p); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_sun_misc_Unsafe_getInt__J -(Thread*, object, uintptr_t* arguments) -{ - int64_t p; memcpy(&p, arguments + 1, 8); - - return *reinterpret_cast(p); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_sun_misc_Unsafe_getLong__J -(Thread*, object, uintptr_t* arguments) -{ - int64_t p; memcpy(&p, arguments + 1, 8); - - return *reinterpret_cast(p); -} - -extern "C" JNIEXPORT int64_t JNICALL -Avian_sun_misc_Unsafe_getFloat__J -(Thread*, object, uintptr_t* arguments) -{ - int64_t p; memcpy(&p, arguments + 1, 8); - - return *reinterpret_cast(p); -} - extern "C" JNIEXPORT int64_t JNICALL Avian_sun_misc_Unsafe_pageSize (Thread*, object, uintptr_t*) diff --git a/src/compile.cpp b/src/compile.cpp index 214cc7ba2c..4963212feb 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -3809,6 +3809,13 @@ floatBranch(MyThread* t, Frame* frame, object code, unsigned& ip, return true; } +Compiler::Operand* +popLongAddress(Frame* frame) +{ + return TargetBytesPerWord == 8 ? frame->popLong() : frame->c->load + (8, 8, frame->popLong(), TargetBytesPerWord); +} + bool intrinsic(MyThread* t, Frame* frame, object target) { @@ -3837,6 +3844,127 @@ intrinsic(MyThread* t, Frame* frame, object target) return true; } } + } else if (UNLIKELY(MATCH(className, "sun/misc/Unsafe"))) { + Compiler* c = frame->c; + if (MATCH(methodName(t, target), "getByte") + and MATCH(methodSpec(t, target), "(J)B")) + { + Compiler::Operand* address = popLongAddress(frame); + frame->popObject(); + frame->pushInt + (c->load + (1, 1, c->memory(address, Compiler::IntegerType, 0, 0, 1), + TargetBytesPerWord)); + return true; + } else if (MATCH(methodName(t, target), "putByte") + and MATCH(methodSpec(t, target), "(JB)V")) + { + Compiler::Operand* value = frame->popInt(); + Compiler::Operand* address = popLongAddress(frame); + frame->popObject(); + c->store + (TargetBytesPerWord, value, 1, c->memory + (address, Compiler::IntegerType, 0, 0, 1)); + return true; + } else if ((MATCH(methodName(t, target), "getShort") + and MATCH(methodSpec(t, target), "(J)S")) + or (MATCH(methodName(t, target), "getChar") + and MATCH(methodSpec(t, target), "(J)C"))) + { + Compiler::Operand* address = popLongAddress(frame); + frame->popObject(); + frame->pushInt + (c->load + (2, 2, c->memory(address, Compiler::IntegerType, 0, 0, 1), + TargetBytesPerWord)); + return true; + } else if ((MATCH(methodName(t, target), "putShort") + and MATCH(methodSpec(t, target), "(JS)V")) + or (MATCH(methodName(t, target), "putChar") + and MATCH(methodSpec(t, target), "(JC)V"))) + { + Compiler::Operand* value = frame->popInt(); + Compiler::Operand* address = popLongAddress(frame); + frame->popObject(); + c->store + (TargetBytesPerWord, value, 2, c->memory + (address, Compiler::IntegerType, 0, 0, 1)); + return true; + } else if ((MATCH(methodName(t, target), "getInt") + and MATCH(methodSpec(t, target), "(J)I")) + or (MATCH(methodName(t, target), "getFloat") + and MATCH(methodSpec(t, target), "(J)F"))) + { + Compiler::Operand* address = popLongAddress(frame); + frame->popObject(); + frame->pushInt + (c->load + (4, 4, c->memory + (address, MATCH(methodName(t, target), "getInt") + ? Compiler::IntegerType : Compiler::FloatType, 0, 0, 1), + TargetBytesPerWord)); + return true; + } else if ((MATCH(methodName(t, target), "putInt") + and MATCH(methodSpec(t, target), "(JI)V")) + or (MATCH(methodName(t, target), "putFloat") + and MATCH(methodSpec(t, target), "(JF)V"))) + { + Compiler::Operand* value = frame->popInt(); + Compiler::Operand* address = popLongAddress(frame); + frame->popObject(); + c->store + (TargetBytesPerWord, value, 4, c->memory + (address, MATCH(methodName(t, target), "putInt") + ? Compiler::IntegerType : Compiler::FloatType, 0, 0, 1)); + return true; + } else if ((MATCH(methodName(t, target), "getLong") + and MATCH(methodSpec(t, target), "(J)J")) + or (MATCH(methodName(t, target), "getDouble") + and MATCH(methodSpec(t, target), "(J)D"))) + { + Compiler::Operand* address = popLongAddress(frame); + frame->popObject(); + frame->pushLong + (c->load + (8, 8, c->memory + (address, MATCH(methodName(t, target), "getLong") + ? Compiler::IntegerType : Compiler::FloatType, 0, 0, 1), + 8)); + return true; + } else if ((MATCH(methodName(t, target), "putLong") + and MATCH(methodSpec(t, target), "(JJ)V")) + or (MATCH(methodName(t, target), "putDouble") + and MATCH(methodSpec(t, target), "(JD)V"))) + { + Compiler::Operand* value = frame->popLong(); + Compiler::Operand* address = popLongAddress(frame); + frame->popObject(); + c->store + (8, value, 8, c->memory + (address, MATCH(methodName(t, target), "putLong") + ? Compiler::IntegerType : Compiler::FloatType, 0, 0, 1)); + return true; + } else if (MATCH(methodName(t, target), "getAddress") + and MATCH(methodSpec(t, target), "(J)J")) + { + Compiler::Operand* address = popLongAddress(frame); + frame->popObject(); + frame->pushLong + (c->load + (TargetBytesPerWord, TargetBytesPerWord, + c->memory(address, Compiler::AddressType, 0, 0, 1), 8)); + return true; + } else if (MATCH(methodName(t, target), "putAddress") + and MATCH(methodSpec(t, target), "(JJ)V")) + { + Compiler::Operand* value = frame->popLong(); + Compiler::Operand* address = popLongAddress(frame); + frame->popObject(); + c->store + (8, value, TargetBytesPerWord, c->memory + (address, Compiler::AddressType, 0, 0, 1)); + return true; + } } return false; } @@ -5022,43 +5150,45 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, if (LIKELY(target)) { assert(t, (methodFlags(t, target) & ACC_STATIC) == 0); + + if (not intrinsic(t, frame, target)) { + bool tailCall = isTailCall(t, code, ip, context->method, target); - bool tailCall = isTailCall(t, code, ip, context->method, target); + if (LIKELY(methodVirtual(t, target))) { + unsigned parameterFootprint = methodParameterFootprint(t, target); - if (LIKELY(methodVirtual(t, target))) { - unsigned parameterFootprint = methodParameterFootprint(t, target); + unsigned offset = TargetClassVtable + + (methodOffset(t, target) * TargetBytesPerWord); - unsigned offset = TargetClassVtable - + (methodOffset(t, target) * TargetBytesPerWord); + Compiler::Operand* instance = c->peek(1, parameterFootprint - 1); - Compiler::Operand* instance = c->peek(1, parameterFootprint - 1); + unsigned rSize = resultSize(t, methodReturnCode(t, target)); - unsigned rSize = resultSize(t, methodReturnCode(t, target)); + Compiler::Operand* result = c->stackCall + (c->memory + (c->and_ + (TargetBytesPerWord, c->constant + (TargetPointerMask, Compiler::IntegerType), + c->memory(instance, Compiler::ObjectType, 0, 0, 1)), + Compiler::ObjectType, offset, 0, 1), + tailCall ? Compiler::TailJump : 0, + frame->trace(0, 0), + rSize, + operandTypeForFieldCode(t, methodReturnCode(t, target)), + parameterFootprint); - Compiler::Operand* result = c->stackCall - (c->memory - (c->and_ - (TargetBytesPerWord, c->constant - (TargetPointerMask, Compiler::IntegerType), - c->memory(instance, Compiler::ObjectType, 0, 0, 1)), - Compiler::ObjectType, offset, 0, 1), - tailCall ? Compiler::TailJump : 0, - frame->trace(0, 0), - rSize, - operandTypeForFieldCode(t, methodReturnCode(t, target)), - parameterFootprint); + frame->pop(parameterFootprint); - frame->pop(parameterFootprint); + if (rSize) { + pushReturnValue(t, frame, methodReturnCode(t, target), result); + } + } else { + // OpenJDK generates invokevirtual calls to private methods + // (e.g. readObject and writeObject for serialization), so + // we must handle such cases here. - if (rSize) { - pushReturnValue(t, frame, methodReturnCode(t, target), result); + compileDirectInvoke(t, frame, target, tailCall); } - } else { - // OpenJDK generates invokevirtual calls to private methods - // (e.g. readObject and writeObject for serialization), so - // we must handle such cases here. - - compileDirectInvoke(t, frame, target, tailCall); } } else { PROTECT(t, reference); From 443097f3bce1002049424915be9374d0f94e7920 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Wed, 7 Mar 2012 08:55:01 -0700 Subject: [PATCH 3/9] add support for Xcode 4.3 --- makefile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/makefile b/makefile index 08287d14f9..9408df6d9c 100755 --- a/makefile +++ b/makefile @@ -214,6 +214,9 @@ openjdk-extra-cflags = -fvisibility=hidden bootimage-cflags = -DTARGET_BYTES_PER_WORD=$(pointer-size) +developer-dir := $(shell if test -d /Developer; then echo /Developer; \ + else echo /Applications/Xcode.app/Contents/Developer; fi) + ifeq ($(build-arch),powerpc) ifneq ($(arch),$(build-arch)) bootimage-cflags += -DTARGET_OPPOSITE_ENDIAN @@ -254,7 +257,7 @@ ifeq ($(arch),arm) ifneq ($(arch),$(build-arch)) ifeq ($(platform),darwin) - ios-bin = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin + ios-bin = $(developer-dir)/Platforms/iPhoneOS.platform/Developer/usr/bin cxx = $(ios-bin)/g++ cc = $(ios-bin)/gcc ar = $(ios-bin)/ar @@ -322,7 +325,7 @@ ifeq ($(platform),darwin) converter-cflags += -DOPPOSITE_ENDIAN endif flags = -arch armv7 -isysroot \ - /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/ + $(developer-dir)/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/ openjdk-extra-cflags += $(flags) cflags += $(flags) asmflags += $(flags) From 6c9a1e1643638de61da539aa77ed851c47b447c6 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 20 Feb 2012 17:23:18 -0700 Subject: [PATCH 4/9] add "throws IOException" to java.io.File.createTempFile --- classpath/java/io/File.java | 9 +++++++-- test/Files.java | 6 ++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/classpath/java/io/File.java b/classpath/java/io/File.java index bfae0da9b6..a77502c041 100644 --- a/classpath/java/io/File.java +++ b/classpath/java/io/File.java @@ -35,11 +35,16 @@ public class File implements Serializable { this(parent.getPath() + FileSeparator + child); } - public static File createTempFile(String prefix, String suffix) { + public static File createTempFile(String prefix, String suffix) + throws IOException + { return createTempFile(prefix, suffix, null); } - public static File createTempFile(String prefix, String suffix, File directory) { + public static File createTempFile(String prefix, String suffix, + File directory) + throws IOException + { if(directory == null) { directory = new File(System.getProperty("java.io.tmpdir")); } diff --git a/test/Files.java b/test/Files.java index 7661e79018..f3d1988f31 100644 --- a/test/Files.java +++ b/test/Files.java @@ -21,7 +21,9 @@ public class Files { } - private static void setExecutableTestWithPermissions(boolean executable) { + private static void setExecutableTestWithPermissions(boolean executable) + throws Exception + { File file = File.createTempFile("avian.", null); file.setExecutable(executable); if (executable) { @@ -33,7 +35,7 @@ public class Files { } } - public static void main(String[] args) { + public static void main(String[] args) throws Exception { isAbsoluteTest(true); isAbsoluteTest(false); setExecutableTestWithPermissions(true); From 71295e54c71feb28736aaa27e454171f95b3eec1 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 11 Mar 2012 04:58:15 -0600 Subject: [PATCH 5/9] handle constants larger than 8 bits in subtractBorrowCR --- src/x86.cpp | 3 ++- test/Longs.java | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/x86.cpp b/src/x86.cpp index 28c6dc2bc7..42f6ccf8de 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -1478,7 +1478,8 @@ subtractBorrowCR(Context* c, unsigned size UNUSED, Assembler::Constant* a, opcode(c, 0x83, 0xd8 + regCode(b)); c->code.append(v); } else { - abort(c); + opcode(c, 0x81, 0xd8 + regCode(b)); + c->code.append4(v); } } diff --git a/test/Longs.java b/test/Longs.java index 434ee908c9..0472536f60 100644 --- a/test/Longs.java +++ b/test/Longs.java @@ -234,6 +234,54 @@ public class Longs { expect((a ^ 25214903884L) == (2L ^ 25214903884L)); } + { long b = 2; + expect((-281474976710656L) >> b == -281474976710656L >> 2); + expect((-281474976710656L) >>> b == -281474976710656L >>> 2); + expect((-281474976710656L) << b == -281474976710656L << 2); + expect((-281474976710656L) + b == -281474976710656L + 2L); + expect((-281474976710656L) - b == -281474976710656L - 2L); + expect((-281474976710656L) * b == -281474976710656L * 2L); + expect((-281474976710656L) / b == -281474976710656L / 2L); + expect((-281474976710656L) % b == -281474976710656L % 2L); + expect(((-281474976710656L) & b) == (-281474976710656L & 2L)); + expect(((-281474976710656L) | b) == (-281474976710656L | 2L)); + expect(((-281474976710656L) ^ b) == (-281474976710656L ^ 2L)); + + b = 2; + expect(281474976710656L >> b == 281474976710656L >> 2); + expect(281474976710656L >>> b == 281474976710656L >>> 2); + expect(281474976710656L << b == 281474976710656L << 2); + expect(281474976710656L + b == 281474976710656L + 2L); + expect(281474976710656L - b == 281474976710656L - 2L); + expect(281474976710656L * b == 281474976710656L * 2L); + expect(281474976710656L / b == 281474976710656L / 2L); + expect(281474976710656L % b == 281474976710656L % 2L); + expect((281474976710656L & b) == (281474976710656L & 2L)); + expect((281474976710656L | b) == (281474976710656L | 2L)); + expect((281474976710656L ^ b) == (281474976710656L ^ 2L)); + } + + { long a = 2L; + expect(a + (-281474976710656L) == 2L + (-281474976710656L)); + expect(a - (-281474976710656L) == 2L - (-281474976710656L)); + expect(a * (-281474976710656L) == 2L * (-281474976710656L)); + expect(a / (-281474976710656L) == 2L / (-281474976710656L)); + expect(a % (-281474976710656L) == 2L % (-281474976710656L)); + expect((a & (-281474976710656L)) == (2L & (-281474976710656L))); + expect((a | (-281474976710656L)) == (2L | (-281474976710656L))); + expect((a ^ (-281474976710656L)) == (2L ^ (-281474976710656L))); + + a = 2L; + expect(a + 281474976710656L == 2L + 281474976710656L); + expect(a - 281474976710656L == 2L - 281474976710656L); + expect(a * 281474976710656L == 2L * 281474976710656L); + expect(a / 281474976710656L == 2L / 281474976710656L); + expect(a % 281474976710656L == 2L % 281474976710656L); + expect((a & 281474976710656L) == (2L & 281474976710656L)); + expect((a | 281474976710656L) == (2L | 281474976710656L)); + expect((a ^ 281474976710656L) == (2L ^ 281474976710656L)); + } + { long x = 231; expect((x >> 32) == 0); expect((x >>> 32) == 0); From 8590695f2d30e2ff1ccfca4decf48d17dc88f397 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 11 Mar 2012 05:00:08 -0600 Subject: [PATCH 6/9] constrain exception handler bounds to bytecode length Scala occasionally generates exception handler tables with interval bounds which fall outside the range of valid bytecode indexes, so we must clamp them or risk out-of-bounds array accesses. --- src/compile.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/compile.cpp b/src/compile.cpp index 4963212feb..2b415588db 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -6172,6 +6172,10 @@ logCompile(MyThread* t, const void* code, unsigned size, const char* class_, int resolveIpForwards(Context* context, int start, int end) { + if (start < 0) { + start = 0; + } + while (start < end and context->visitTable[start] == 0) { ++ start; } @@ -6186,6 +6190,13 @@ resolveIpForwards(Context* context, int start, int end) int resolveIpBackwards(Context* context, int start, int end) { + Thread* t = context->thread; + if (start >= static_cast + (codeLength(t, methodCode(t, context->method)))) + { + start = codeLength(t, methodCode(t, context->method)) - 1; + } + while (start >= end and context->visitTable[start] == 0) { -- start; } @@ -6269,11 +6280,16 @@ translateExceptionHandlerTable(MyThread* t, Context* context, intptr_t start) exceptionHandlerEnd(oldHandler)); if (LIKELY(handlerStart >= 0)) { + assert(t, handlerStart < static_cast + (codeLength(t, methodCode(t, context->method)))); + int handlerEnd = resolveIpBackwards (context, exceptionHandlerEnd(oldHandler), exceptionHandlerStart(oldHandler)); assert(t, handlerEnd >= 0); + assert(t, handlerEnd < static_cast + (codeLength(t, methodCode(t, context->method)))); intArrayBody(t, newIndex, ni * 3) = c->machineIp(handlerStart)->value() - start; From 3e38628ad6e40b726d3264e6a9ccd2afcb31edf4 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 11 Mar 2012 05:04:12 -0600 Subject: [PATCH 7/9] check superclasses in fieldForOffset, not just immediate class --- src/classpath-openjdk.cpp | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 977d466c6d..bf6d16b5c0 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -2207,19 +2207,40 @@ pipeAvailable(int fd, int* available) } object -fieldForOffset(Thread* t, object o, unsigned offset) +fieldForOffsetInClass(Thread* t, object c, unsigned offset) { - object table = classFieldTable(t, objectClass(t, o)); - for (unsigned i = 0; i < objectArrayLength(t, table); ++i) { - object field = objectArrayBody(t, table, i); - if ((fieldFlags(t, field) & ACC_STATIC) == 0 - and fieldOffset(t, field) == offset) - { + object super = classSuper(t, c); + if (super) { + object field = fieldForOffsetInClass(t, super, offset); + if (field) { return field; } } - - abort(t); + + object table = classFieldTable(t, c); + if (table) { + for (unsigned i = 0; i < objectArrayLength(t, table); ++i) { + object field = objectArrayBody(t, table, i); + if ((fieldFlags(t, field) & ACC_STATIC) == 0 + and fieldOffset(t, field) == offset) + { + return field; + } + } + } + + return 0; +} + +object +fieldForOffset(Thread* t, object o, unsigned offset) +{ + object field = fieldForOffsetInClass(t, objectClass(t, o), offset); + if (field) { + return field; + } else { + abort(t); + } } } // namespace local From 04a34a75ed04cd8d947d57919622913d45d0d681 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 11 Mar 2012 05:05:14 -0600 Subject: [PATCH 8/9] implement sun.misc.Unsafe.monitorEnter and monitorExit --- src/classpath-openjdk.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index bf6d16b5c0..5ff044d49f 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -2694,6 +2694,20 @@ Avian_sun_misc_Unsafe_park monitorRelease(t, local::interruptLock(t, t->javaThread)); } +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_monitorEnter +(Thread* t, object, uintptr_t* arguments) +{ + acquire(t, reinterpret_cast(arguments[1])); +} + +extern "C" JNIEXPORT void JNICALL +Avian_sun_misc_Unsafe_monitorExit +(Thread* t, object, uintptr_t* arguments) +{ + release(t, reinterpret_cast(arguments[1])); +} + namespace { namespace local { From 6cc0ddda7c59e9c1f283bd9f20115268eeb81726 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 11 Mar 2012 05:06:08 -0600 Subject: [PATCH 9/9] implement JVM_HoldsLock --- src/classpath-openjdk.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 5ff044d49f..2866b6072b 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -3289,8 +3289,21 @@ EXPORT(JVM_IsInterrupted)(Thread* t, jobject thread, jboolean clear) return run(t, jvmIsInterrupted, arguments); } +uint64_t +jvmHoldsLock(Thread* t, uintptr_t* arguments) +{ + object m = objectMonitor(t, *reinterpret_cast(arguments[0]), false); + + return m and monitorOwner(t, m) == t; +} + extern "C" JNIEXPORT jboolean JNICALL -EXPORT(JVM_HoldsLock)(Thread*, jclass, jobject) { abort(); } +EXPORT(JVM_HoldsLock)(Thread* t, jclass, jobject o) +{ + uintptr_t arguments[] = { reinterpret_cast(o) }; + + return run(t, jvmHoldsLock, arguments); +} extern "C" JNIEXPORT void JNICALL EXPORT(JVM_DumpAllStacks)(Thread*, jclass) { abort(); }