From b2268143f5354f72fcfe778110cd7eb44584c739 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 20 Feb 2011 02:48:56 +0000 Subject: [PATCH 01/32] preserve statck alignment in arm.S's vmRun --- src/arm.S | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/arm.S b/src/arm.S index 458ece75cb..ece98ea386 100644 --- a/src/arm.S +++ b/src/arm.S @@ -66,6 +66,8 @@ vmRun: // r1: arguments // r2: checkpoint stmfd sp!, {r4-r11, lr} + // align stack + sub sp, sp, #12 str sp, [r2, #CHECKPOINT_STACK] @@ -76,5 +78,6 @@ vmRun: .globl vmRun_returnAddress vmRun_returnAddress: + add sp, sp, #12 ldmfd sp!, {r4-r11, lr} bx lr From 8a88c6ee3c63a6728a59b979a13d5d70736a23c6 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 19 Feb 2011 20:33:26 -0700 Subject: [PATCH 02/32] fix ARM stack unwinding We can't rely on the C++ compiler to save the return address in a known location on entry to each function we might call from Java (although GCC 4.5 seems to do so consistently, which is why I hadn't realized the unwinding code was relying on that assumption), so we must store it explicitly in MyThread::ip in each thunk. For PowerPC and x86, we continue saving it on the stack as always, since the calling convention guarantees its location relative to the stack pointer. --- src/arm.cpp | 6 +++++- src/assembler.h | 2 +- src/compile.cpp | 30 +++++++++++++++++++++--------- src/powerpc.cpp | 2 +- src/x86.cpp | 2 +- 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/arm.cpp b/src/arm.cpp index d0bb5f02c7..2275737e8d 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -2126,7 +2126,11 @@ class MyAssembler: public Assembler { &handlerConstant); } - virtual void saveFrame(unsigned stackOffset) { + virtual void saveFrame(unsigned stackOffset, unsigned ipOffset) { + Register link(LinkRegister); + Memory linkDst(ThreadRegister, ipOffset); + moveRM(&c, BytesPerWord, &link, BytesPerWord, &linkDst); + Register stack(StackRegister); Memory stackDst(ThreadRegister, stackOffset); moveRM(&c, BytesPerWord, &stack, BytesPerWord, &stackDst); diff --git a/src/assembler.h b/src/assembler.h index d122a53207..d86a893760 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -397,7 +397,7 @@ class Assembler { virtual void checkStackOverflow(uintptr_t handler, unsigned stackLimitOffsetFromThread) = 0; - virtual void saveFrame(unsigned stackOffset) = 0; + virtual void saveFrame(unsigned stackOffset, unsigned ipOffset) = 0; virtual void pushFrame(unsigned argumentCount, ...) = 0; virtual void allocateFrame(unsigned footprint) = 0; virtual void adjustFrame(unsigned difference) = 0; diff --git a/src/compile.cpp b/src/compile.cpp index 37374f03c0..77603fcaa2 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -435,6 +435,18 @@ nextFrame(MyThread* t, void** ip, void** sp, object method, object target) // fprintf(stderr, "next frame ip %p sp %p\n", *ip, *sp); } +void* +getIp(MyThread* t) +{ + // Here we use the convention that, if the return address is neither + // pushed on to the stack automatically as part of the call nor + // stored in the caller's frame, it will be saved in MyThread::ip + // instead of on the stack. See the various implementations of + // Assembler::saveFrame for details on how this is done. + return t->arch->returnAddressOffset() < 0 + ? t->ip : t->arch->frameIp(t->stack); +} + class MyStackWalker: public Processor::StackWalker { public: enum State { @@ -475,7 +487,7 @@ class MyStackWalker: public Processor::StackWalker { trace = t->traceContext->trace; continuation = t->traceContext->continuation; } else { - ip_ = 0; + ip_ = getIp(t); stack = t->stack; trace = t->trace; continuation = t->continuation; @@ -1981,7 +1993,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetFrame, stack = t->traceContext->stack; continuation = t->traceContext->continuation; } else { - ip = 0; + ip = getIp(t); stack = t->stack; continuation = t->continuation; } @@ -6669,7 +6681,7 @@ visitArguments(MyThread* t, Heap::Visitor* v, void* stack, object method) void visitStack(MyThread* t, Heap::Visitor* v) { - void* ip = t->arch->frameIp(t->stack); + void* ip = getIp(t); void* stack = t->stack; MyThread::CallTrace* trace = t->trace; @@ -8398,7 +8410,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) { Assembler* a = defaultContext.context.assembler; - a->saveFrame(difference(&(t->stack), t)); + a->saveFrame(difference(&(t->stack), t), difference(&(t->ip), t)); p->thunks.default_.frameSavedOffset = a->length(); @@ -8442,7 +8454,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) a->apply(Move, BytesPerWord, RegisterOperand, &index, BytesPerWord, MemoryOperand, &virtualCallIndex); - a->saveFrame(difference(&(t->stack), t)); + a->saveFrame(difference(&(t->stack), t), difference(&(t->ip), t)); p->thunks.defaultVirtual.frameSavedOffset = a->length(); @@ -8464,7 +8476,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) { Assembler* a = nativeContext.context.assembler; - a->saveFrame(difference(&(t->stack), t)); + a->saveFrame(difference(&(t->stack), t), difference(&(t->ip), t)); p->thunks.native.frameSavedOffset = a->length(); @@ -8484,7 +8496,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) { Assembler* a = aioobContext.context.assembler; - a->saveFrame(difference(&(t->stack), t)); + a->saveFrame(difference(&(t->stack), t), difference(&(t->ip), t)); p->thunks.aioob.frameSavedOffset = a->length(); @@ -8501,7 +8513,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) { Assembler* a = stackOverflowContext.context.assembler; - a->saveFrame(difference(&(t->stack), t)); + a->saveFrame(difference(&(t->stack), t), difference(&(t->ip), t)); p->thunks.stackOverflow.frameSavedOffset = a->length(); @@ -8518,7 +8530,7 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) { Assembler* a = tableContext.context.assembler; - a->saveFrame(difference(&(t->stack), t)); + a->saveFrame(difference(&(t->stack), t), difference(&(t->ip), t)); p->thunks.table.frameSavedOffset = a->length(); diff --git a/src/powerpc.cpp b/src/powerpc.cpp index edcd587132..184f7ab124 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -2253,7 +2253,7 @@ class MyAssembler: public Assembler { &handlerConstant); } - virtual void saveFrame(unsigned stackOffset) { + virtual void saveFrame(unsigned stackOffset, unsigned) { Register returnAddress(0); emit(&c, mflr(returnAddress.low)); diff --git a/src/x86.cpp b/src/x86.cpp index 97ef3c2bb3..0f2964e6c7 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -3382,7 +3382,7 @@ class MyAssembler: public Assembler { &handlerConstant); } - virtual void saveFrame(unsigned stackOffset) { + virtual void saveFrame(unsigned stackOffset, unsigned) { Register stack(rsp); Memory stackDst(rbx, stackOffset); apply(Move, BytesPerWord, RegisterOperand, &stack, From 45a246967246d44a8951cc43891399c26791eb2c Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 20 Feb 2011 05:59:13 +0000 Subject: [PATCH 03/32] abort if allocation fails in heap.cpp's allocate --- src/heap.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/heap.cpp b/src/heap.cpp index 02e0e99a19..c2474cf653 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -1746,7 +1746,10 @@ tryAllocate(Context* c, unsigned size) void* allocate(Context* c, unsigned size) { - return allocate(c, size, false); + void* p = allocate(c, size, false); + expect(c->system, p); + + return p; } void From ab3929d411673116570e9108b7304a55a890ccc1 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 20 Feb 2011 05:59:36 +0000 Subject: [PATCH 04/32] fix PowerPC and ARM bootimage builds This requires reducing HeapCapacity and CodeCapacity back to 128MB and 30MB respectively. I had set them to larger values to test non-ProGuard'ed OpenJDK bootimage builds, which naturally needed a lot more space. However, such builds aren't really useful in the real world, and the compiler currently can't handle jumps or calls spanning more than the maximum size of an immediate branch offset on ARM or PowerPC, so I'm lowering them back down to more realistic values. --- src/bootimage.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/bootimage.cpp b/src/bootimage.cpp index 13a278ea8b..e7f0d9510c 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -23,7 +23,7 @@ using namespace vm; namespace { -const unsigned HeapCapacity = 768 * 1024 * 1024; +const unsigned HeapCapacity = 128 * 1024 * 1024; // Notes on immutable references in the heap image: // @@ -560,9 +560,15 @@ main(int ac, const char** av) Finder* f = makeFinder(s, h, av[1], 0); Processor* p = makeProcessor(s, h, false); - BootImage image; - const unsigned CodeCapacity = 128 * 1024 * 1024; + // todo: currently, the compiler cannot compile code with jumps or + // calls spanning more than the maximum size of an immediate value + // in a branch instruction for the target architecture (~32MB on + // PowerPC and ARM). When that limitation is removed, we'll be able + // to specify a capacity as large as we like here: + const unsigned CodeCapacity = 30 * 1024 * 1024; + uint8_t* code = static_cast(h->allocate(CodeCapacity)); + BootImage image; p->initialize(&image, code, CodeCapacity); Machine* m = new (h->allocate(sizeof(Machine))) Machine From 98e74f66e9829fef4b1807aabdc685aa1dc4f55a Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 20 Feb 2011 20:30:56 +0000 Subject: [PATCH 05/32] fix compile-arm.S's vmJumpAndInvoke --- src/compile-arm.S | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/compile-arm.S b/src/compile-arm.S index 8af887fdbb..8c062c1c12 100644 --- a/src/compile-arm.S +++ b/src/compile-arm.S @@ -197,9 +197,12 @@ GLOBAL(vmJumpAndInvoke): ldr r5,[sp,#0] ldr r6,[sp,#4] - // allocate new frame, adding room for callee-saved registers + // allocate new frame, adding room for callee-saved registers, plus + // 4 bytes of padding since the calculation of frameSize assumes 4 + // bytes have already been allocated to save the return address, + // which is not true in this case sub r2,r2,r6 - sub r2,r2,#80 + sub r2,r2,#84 mov r8,r0 @@ -213,7 +216,7 @@ LOCAL(vmJumpAndInvoke_argumentLoop): add r6,r6,#4 LOCAL(vmJumpAndInvoke_argumentTest): - cmp r6,r4 + cmp r6,r3 ble LOCAL(vmJumpAndInvoke_argumentLoop) // the arguments have been copied, so we can set the real stack From 20f451012208d317b4803f0bd1d428413cfa8043 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 20 Feb 2011 13:31:29 -0700 Subject: [PATCH 06/32] fix ARM stack unwinding (part 2) My previous attempt at this was incomplete; it did not address Java->native->Java->native call sequences, nor did it address continuations. This commit takes care of both. --- src/compile.cpp | 42 +++++++++++++++++++++++------------------- test/Initializers.java | 24 ++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 19 deletions(-) create mode 100644 test/Initializers.java diff --git a/src/compile.cpp b/src/compile.cpp index 77603fcaa2..f942a0b7ed 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -81,12 +81,18 @@ isVmInvokeUnsafeStack(void* ip) < reinterpret_cast (voidPointer(vmInvoke_safeStack)); } +class MyThread; + +void* +getIp(MyThread*); + class MyThread: public Thread { public: class CallTrace { public: CallTrace(MyThread* t, object method): t(t), + ip(getIp(t)), stack(t->stack), scratch(t->scratch), continuation(t->continuation), @@ -107,6 +113,7 @@ class MyThread: public Thread { } MyThread* t; + void* ip; void* stack; void* scratch; object continuation; @@ -436,15 +443,20 @@ nextFrame(MyThread* t, void** ip, void** sp, object method, object target) } void* -getIp(MyThread* t) +getIp(MyThread* t, void* ip, void* stack) { // Here we use the convention that, if the return address is neither // pushed on to the stack automatically as part of the call nor // stored in the caller's frame, it will be saved in MyThread::ip // instead of on the stack. See the various implementations of // Assembler::saveFrame for details on how this is done. - return t->arch->returnAddressOffset() < 0 - ? t->ip : t->arch->frameIp(t->stack); + return t->arch->returnAddressOffset() < 0 ? ip : t->arch->frameIp(stack); +} + +void* +getIp(MyThread* t) +{ + return getIp(t, t->ip, t->stack); } class MyStackWalker: public Processor::StackWalker { @@ -521,10 +533,6 @@ class MyStackWalker: public Processor::StackWalker { // fprintf(stderr, "state: %d\n", state); switch (state) { case Start: - if (ip_ == 0) { - ip_ = t->arch->frameIp(stack); - } - if (trace and trace->nativeMethod) { method_ = trace->nativeMethod; state = NativeMethod; @@ -554,7 +562,7 @@ class MyStackWalker: public Processor::StackWalker { if (trace) { continuation = trace->continuation; stack = trace->stack; - ip_ = t->arch->frameIp(stack); + ip_ = trace->ip; trace = trace->next; state = Start; @@ -1998,10 +2006,6 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetFrame, continuation = t->continuation; } - if (ip == 0) { - ip = t->arch->frameIp(stack); - } - object target = t->trace->targetMethod; *targetIp = 0; @@ -2080,7 +2084,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetFrame, object makeCurrentContinuation(MyThread* t, void** targetIp, void** targetStack) { - void* ip = t->arch->frameIp(t->stack); + void* ip = getIp(t); void* stack = t->stack; object context = t->continuation @@ -6219,7 +6223,7 @@ compileMethod(MyThread* t) ip = t->tailAddress; t->tailAddress = 0; } else { - ip = t->arch->frameIp(t->stack); + ip = getIp(t); } return reinterpret_cast(compileMethod2(t, ip)); @@ -6470,7 +6474,7 @@ invokeNative(MyThread* t) ip = t->tailAddress; t->tailAddress = 0; } else { - ip = t->arch->frameIp(t->stack); + ip = getIp(t); } object node = findCallNode(t, ip); @@ -6511,7 +6515,7 @@ invokeNative(MyThread* t) stack += t->arch->frameReturnAddressSize(); - transition(t, t->arch->frameIp(t->stack), stack, t->continuation, t->trace); + transition(t, getIp(t), stack, t->continuation, t->trace); return result; } @@ -6708,7 +6712,7 @@ visitStack(MyThread* t, Heap::Visitor* v) target = method; } else if (trace) { stack = trace->stack; - ip = t->arch->frameIp(stack); + ip = trace->ip; trace = trace->next; if (trace) { @@ -7697,12 +7701,12 @@ class MyProcessor: public Processor { // we caught the thread in a thunk or native code, and the // saved stack pointer indicates the most recent Java frame // on the stack - c.ip = t->arch->frameIp(target->stack); + c.ip = getIp(target); c.stack = target->stack; } else if (isThunk(t, ip) or isVirtualThunk(t, ip)) { // we caught the thread in a thunk where the stack register // indicates the most recent Java frame on the stack - c.ip = t->arch->frameIp(stack); + c.ip = getIp(t, link, stack); c.stack = stack; } else { // we caught the thread in native code, and the most recent diff --git a/test/Initializers.java b/test/Initializers.java new file mode 100644 index 0000000000..5b6fe2c2cb --- /dev/null +++ b/test/Initializers.java @@ -0,0 +1,24 @@ +public class Initializers { + private static class Static2 { + public static String foo = "Static2.foo"; + + static { + System.gc(); + new Exception().printStackTrace(); + } + } + + private static class Static1 { + public static String foo = "Static1.foo"; + + static { + System.out.println(Static2.foo); + } + } + + public static void main(String[] args) { + Object x = new Object(); + System.out.println(Static1.foo); + x.toString(); + } +} From e20daca297687e1ac2586813a1f6e14eb7bd3106 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 21 Feb 2011 15:25:52 -0700 Subject: [PATCH 07/32] use link register to determine return address when appropriate in getStackTrace On PowerPC and ARM, we can't rely on the return address having already been saved on the stack on entry to a thunk, so we must look for it in the link register instead. --- src/arm.cpp | 6 +++++- src/assembler.h | 2 ++ src/compile.cpp | 10 +++++++++- src/powerpc.cpp | 4 ++++ src/x86.cpp | 4 ++++ 5 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/arm.cpp b/src/arm.cpp index 2275737e8d..c026635ed4 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -1838,7 +1838,11 @@ class MyArchitecture: public Assembler::Architecture { return index; } - + + virtual bool hasLinkRegister() { + return true; + } + virtual unsigned stackAlignmentInWords() { return StackAlignmentInWords; } diff --git a/src/assembler.h b/src/assembler.h index d86a893760..15d08c130a 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -333,6 +333,8 @@ class Assembler { virtual unsigned argumentRegisterCount() = 0; virtual int argumentRegister(unsigned index) = 0; + virtual bool hasLinkRegister() = 0; + virtual unsigned stackAlignmentInWords() = 0; virtual bool matchCall(void* returnAddress, void* target) = 0; diff --git a/src/compile.cpp b/src/compile.cpp index f942a0b7ed..72490c8490 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -7706,7 +7706,15 @@ class MyProcessor: public Processor { } else if (isThunk(t, ip) or isVirtualThunk(t, ip)) { // we caught the thread in a thunk where the stack register // indicates the most recent Java frame on the stack - c.ip = getIp(t, link, stack); + + // On e.g. x86, the return address will have already been + // pushed onto the stack, in which case we use getIp to + // retrieve it. On e.g. PowerPC and ARM, it will be in the + // link register. Note that we can't just check if the link + // argument is null here, since we use ecx/rcx as a + // pseudo-link register on x86 for the purpose of tail + // calls. + c.ip = t->arch->hasLinkRegister() ? link : getIp(t, link, stack); c.stack = stack; } else { // we caught the thread in native code, and the most recent diff --git a/src/powerpc.cpp b/src/powerpc.cpp index 184f7ab124..6c721651ba 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -1952,6 +1952,10 @@ class MyArchitecture: public Assembler::Architecture { return index + 3; } + + virtual bool hasLinkRegister() { + return true; + } virtual unsigned stackAlignmentInWords() { return StackAlignmentInWords; diff --git a/src/x86.cpp b/src/x86.cpp index 0f2964e6c7..956d99b1c9 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -2846,6 +2846,10 @@ class MyArchitecture: public Assembler::Architecture { } } + virtual bool hasLinkRegister() { + return false; + } + virtual unsigned stackAlignmentInWords() { return StackAlignmentInWords; } From addaf09aa39182582ddb7340b3b071d01d59be92 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 21 Feb 2011 16:00:20 -0700 Subject: [PATCH 08/32] use run function to call boot in JNI_CreateJavaVM boot may throw an exception, which we can't allow to propagate beyond the JNI_CreateJavaVM call. --- src/jnienv.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/jnienv.cpp b/src/jnienv.cpp index eebbf2ad6d..3fb07db9ad 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -2287,11 +2287,9 @@ append(char** p, const char* value, unsigned length, char tail) } } -void -boot(Thread* t) +uint64_t +boot(Thread* t, uintptr_t*) { - enter(t, Thread::ActiveState); - t->javaThread = t->m->classpath->makeThread(t, 0); setRoot(t, Machine::NullPointerException, makeThrowable @@ -2313,6 +2311,8 @@ boot(Thread* t) t->m->classpath->boot(t); enter(t, Thread::IdleState); + + return 1; } } // namespace local @@ -2628,7 +2628,8 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args) *t = p->makeThread(*m, 0, 0); - local::boot(*t); + enter(*t, Thread::ActiveState); + enter(*t, Thread::IdleState); - return 0; + return run(*t, local::boot, 0) ? 0 : -1; } From d520514a8762e69d4d89183989dd9370e14cd49f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 21 Feb 2011 16:05:28 -0700 Subject: [PATCH 09/32] add support for Class-Path manifest attribute This attribute, found in some JAR manifests, indicates additional JARs and/or directories to append to the classpath. Tomcat in particular uses it. --- src/finder.cpp | 170 +++++++++++++++++++++++++++++++++++------------- src/finder.h | 16 +++++ src/main.cpp | 16 ----- src/tokenizer.h | 15 +++-- 4 files changed, 152 insertions(+), 65 deletions(-) diff --git a/src/finder.cpp b/src/finder.cpp index b0e25ef82a..2199dd5207 100644 --- a/src/finder.cpp +++ b/src/finder.cpp @@ -632,59 +632,139 @@ class BuiltinElement: public JarElement { const char* libraryName; }; +void +add(Element** first, Element** last, Element* e) +{ + if (*last) { + (*last)->next = e; + } else { + *first = e; + } + *last = e; +} + +unsigned +baseName(const char* name, char fileSeparator) +{ + const char* p = name; + const char* last = 0; + while (*p) { + if (*p == fileSeparator) { + last = p; + } + ++p; + } + + return last ? (last + 1) - name : 0; +} + +void +add(System* s, Element** first, Element** last, Allocator* allocator, + const char* name, unsigned nameLength, const char* bootLibrary); + +void +addJar(System* s, Element** first, Element** last, Allocator* allocator, + const char* name, const char* bootLibrary) +{ + if (DebugFind) { + fprintf(stderr, "add jar %s\n", name); + } + + JarElement* e = new (allocator->allocate(sizeof(JarElement))) + JarElement(s, allocator, name); + + add(first, last, e); + + System::Region* region = e->find("META-INF/MANIFEST.MF"); + if (region) { + unsigned start = 0; + unsigned length; + while (readLine(region->start(), region->length(), &start, &length)) { + const unsigned PrefixLength = 12; + if (strncmp("Class-Path: ", reinterpret_cast + (region->start() + start), PrefixLength) == 0) + { + for (Tokenizer t(reinterpret_cast + (region->start() + start + PrefixLength), + length - PrefixLength, ' '); + t.hasMore();) + { + Tokenizer::Token token(t.next()); + + unsigned base = baseName(name, s->fileSeparator()); + + RUNTIME_ARRAY(char, n, base + token.length + 1); + memcpy(RUNTIME_ARRAY_BODY(n), name, base); + memcpy(RUNTIME_ARRAY_BODY(n) + base, token.s, token.length); + RUNTIME_ARRAY_BODY(n)[base + token.length] = 0; + + add(s, first, last, allocator, RUNTIME_ARRAY_BODY(n), + base + token.length, bootLibrary); + } + } + start += length; + } + + region->dispose(); + } +} + +void +add(System* s, Element** first, Element** last, Allocator* allocator, + const char* token, unsigned tokenLength, const char* bootLibrary) +{ + if (*token == '[' and token[tokenLength - 1] == ']') { + char* name = static_cast(allocator->allocate(tokenLength - 1)); + memcpy(name, token + 1, tokenLength - 1); + name[tokenLength - 2] = 0; + + if (DebugFind) { + fprintf(stderr, "add builtin %s\n", name); + } + + add(first, last, new (allocator->allocate(sizeof(BuiltinElement))) + BuiltinElement(s, allocator, name, bootLibrary)); + } else { + char* name = static_cast(allocator->allocate(tokenLength + 1)); + memcpy(name, token, tokenLength); + name[tokenLength] = 0; + + unsigned length; + switch (s->stat(name, &length)) { + case System::TypeFile: { + addJar(s, first, last, allocator, name, bootLibrary); + } break; + + case System::TypeDirectory: { + if (DebugFind) { + fprintf(stderr, "add directory %s\n", name); + } + + add(first, last, new (allocator->allocate(sizeof(DirectoryElement))) + DirectoryElement(s, allocator, name)); + } break; + + default: { + if (DebugFind) { + fprintf(stderr, "ignore nonexistent %s\n", name); + } + + allocator->free(name, strlen(name) + 1); + } break; + } + } +} + Element* parsePath(System* s, Allocator* allocator, const char* path, const char* bootLibrary) { Element* first = 0; - Element* prev = 0; + Element* last = 0; for (Tokenizer t(path, s->pathSeparator()); t.hasMore();) { Tokenizer::Token token(t.next()); - Element* e; - if (*token.s == '[' and token.s[token.length - 1] == ']') { - char* name = static_cast(allocator->allocate(token.length - 1)); - memcpy(name, token.s + 1, token.length - 1); - name[token.length - 2] = 0; - - e = new (allocator->allocate(sizeof(BuiltinElement))) - BuiltinElement(s, allocator, name, bootLibrary); - } else { - char* name = static_cast(allocator->allocate(token.length + 1)); - memcpy(name, token.s, token.length); - name[token.length] = 0; - - unsigned length; - switch (s->stat(name, &length)) { - case System::TypeFile: { - e = new (allocator->allocate(sizeof(JarElement))) - JarElement(s, allocator, name); - } break; - - case System::TypeDirectory: { - e = new (allocator->allocate(sizeof(DirectoryElement))) - DirectoryElement(s, allocator, name); - } break; - - default: { - allocator->free(name, strlen(name) + 1); - e = 0; - } break; - } - } - - if (DebugFind) { - fprintf(stderr, "add element %.*s %p\n", token.length, token.s, e); - } - - if (e) { - if (prev) { - prev->next = e; - } else { - first = e; - } - prev = e; - } + add(s, &first, &last, allocator, token.s, token.length, bootLibrary); } return first; diff --git a/src/finder.h b/src/finder.h index 203abb49e3..7546fb8b9c 100644 --- a/src/finder.h +++ b/src/finder.h @@ -17,6 +17,22 @@ namespace vm { +inline bool +readLine(const uint8_t* base, unsigned total, unsigned* start, + unsigned* length) +{ + const uint8_t* p = base + *start; + const uint8_t* end = base + total; + while (p != end and (*p == '\n' or *p == '\r')) ++ p; + + *start = p - base; + while (p != end and not (*p == '\n' or *p == '\r')) ++ p; + + *length = (p - base) - *start; + + return *length != 0; +} + class Finder { public: class IteratorImp { diff --git a/src/main.cpp b/src/main.cpp index 9996e6078d..d04fbe3f34 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -74,22 +74,6 @@ vmNativeCall(void*, void*, unsigned, unsigned) namespace { -bool -readLine(const uint8_t* base, unsigned total, unsigned* start, - unsigned* length) -{ - const uint8_t* p = base + *start; - const uint8_t* end = base + total; - while (p != end and (*p == '\n' or *p == '\r')) ++ p; - - *start = p - base; - while (p != end and not (*p == '\n' or *p == '\r')) ++ p; - - *length = (p - base) - *start; - - return *length != 0; -} - const char* mainClass(const char* jar) { diff --git a/src/tokenizer.h b/src/tokenizer.h index 4036e7d197..ac008055ff 100644 --- a/src/tokenizer.h +++ b/src/tokenizer.h @@ -23,20 +23,27 @@ class Tokenizer { unsigned length; }; - Tokenizer(const char* s, char delimiter): s(s), delimiter(delimiter) { } + Tokenizer(const char* s, char delimiter): + s(s), limit(0), delimiter(delimiter) + { } + + Tokenizer(const char* s, unsigned length, char delimiter): + s(s), limit(s + length), delimiter(delimiter) + { } bool hasMore() { - while (*s == delimiter) ++s; - return *s != 0; + while (*s == delimiter and s != limit) ++s; + return *s != 0 and s != limit; } Token next() { const char* p = s; - while (*s and *s != delimiter) ++s; + while (*s and *s != delimiter and s != limit) ++s; return Token(p, s - p); } const char* s; + const char* limit; char delimiter; }; From 6014cb93b15db3c16db9266788edfaccb043c9f1 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 22 Feb 2011 15:45:46 -0700 Subject: [PATCH 10/32] fix Mac OS PowerPC cross build While we can use Linux's jni.h to cross compile the i386 Mac OS build, that doesn't work for the PowerPC one. Now we use the proper /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Headers/jni.h from the sysroot instead. --- makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/makefile b/makefile index 811a14ceb4..ccd6c8ada9 100644 --- a/makefile +++ b/makefile @@ -219,13 +219,14 @@ ifeq ($(platform),darwin) ar = i686-apple-darwin8-ar ranlib = i686-apple-darwin8-ranlib strip = i686-apple-darwin8-strip - extra-cflags = -I$(JAVA_HOME)/include/linux + sysroot = /opt/mac/SDKs/MacOSX10.4u.sdk + cflags = -I$(sysroot)/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Headers/ \ + $(common-cflags) -fPIC -fvisibility=hidden -I$(src) else + build-cflags = $(common-cflags) -fPIC -fvisibility=hidden -I$(src) build-lflags += -framework CoreFoundation endif - build-cflags = $(common-cflags) $(extra-cflags) -fPIC -fvisibility=hidden \ - -I$(src) version-script-flag = lflags = $(common-lflags) -ldl -framework CoreFoundation \ -framework CoreServices From bead78d982fc231e0edfbb52315c6750963da3bd Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 22 Feb 2011 17:54:56 -0700 Subject: [PATCH 11/32] wrap primitive return values using correct types in Method.invoke The VM uses Integer and Long instances internally to wrap the results of dynamic method invocations, but Method.invoke should use the correct, specific type for the primitive (e.g. Character for char). --- src/classpath-avian.cpp | 5 +++- src/classpath-common.h | 34 +++++++++++++++++++++++ src/classpath-openjdk.cpp | 5 +++- test/Reflection.java | 58 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+), 2 deletions(-) diff --git a/src/classpath-avian.cpp b/src/classpath-avian.cpp index 95b2a32703..9efba455e4 100644 --- a/src/classpath-avian.cpp +++ b/src/classpath-avian.cpp @@ -312,8 +312,11 @@ Avian_java_lang_reflect_Method_invoke } }); + unsigned returnCode = methodReturnCode(t, method); + return reinterpret_cast - (t->m->processor->invokeArray(t, method, instance, args)); + (translateInvokeResult + (t, returnCode, t->m->processor->invokeArray(t, method, instance, args))); } extern "C" JNIEXPORT int64_t JNICALL diff --git a/src/classpath-common.h b/src/classpath-common.h index 6efc0a1424..8c89f94cf6 100644 --- a/src/classpath-common.h +++ b/src/classpath-common.h @@ -286,6 +286,40 @@ makeStackTraceElement(Thread* t, object e) return makeStackTraceElement(t, class_, method, file, line); } +object +translateInvokeResult(Thread* t, unsigned returnCode, object o) +{ + switch (returnCode) { + case ByteField: + return makeByte(t, intValue(t, o)); + + case BooleanField: + return makeBoolean(t, intValue(t, o) != 0); + + case CharField: + return makeChar(t, intValue(t, o)); + + case ShortField: + return makeShort(t, intValue(t, o)); + + case FloatField: + return makeFloat(t, intValue(t, o)); + + case IntField: + case LongField: + case ObjectField: + case VoidField: + return o; + + case DoubleField: + return makeDouble(t, longValue(t, o)); + break; + + default: + abort(t); + } +} + } // namespace vm #endif//CLASSPATH_COMMON_H diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index ab7ba61179..6e432d54d2 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -3162,6 +3162,8 @@ jvmInvokeMethod(Thread* t, uintptr_t* arguments) instance = 0; } + unsigned returnCode = methodReturnCode(t, vmMethod); + object result; if (args) { result = t->m->processor->invokeArray @@ -3170,7 +3172,8 @@ jvmInvokeMethod(Thread* t, uintptr_t* arguments) result = t->m->processor->invoke(t, vmMethod, instance ? *instance : 0); } - return reinterpret_cast(makeLocalReference(t, result)); + return reinterpret_cast + (makeLocalReference(t, translateInvokeResult(t, returnCode, result))); } extern "C" JNIEXPORT jobject JNICALL diff --git a/test/Reflection.java b/test/Reflection.java index 71a70db815..f71b39e81b 100644 --- a/test/Reflection.java +++ b/test/Reflection.java @@ -2,6 +2,42 @@ import java.lang.reflect.Method; import java.lang.reflect.Field; public class Reflection { + public static boolean booleanMethod() { + return true; + } + + public static byte byteMethod() { + return 1; + } + + public static char charMethod() { + return '2'; + } + + public static short shortMethod() { + return 3; + } + + public static int intMethod() { + return 4; + } + + public static float floatMethod() { + return 5.0f; + } + + public static long longMethod() { + return 6; + } + + public static double doubleMethod() { + return 7.0; + } + + public static void expect(boolean v) { + if (! v) throw new RuntimeException(); + } + public static void main(String[] args) throws Exception { Class system = Class.forName("java.lang.System"); Field out = system.getDeclaredField("out"); @@ -9,5 +45,27 @@ public class Reflection { Method println = output.getDeclaredMethod("println", String.class); println.invoke(out.get(null), "Hello, World!"); + + expect((Boolean) Reflection.class.getMethod("booleanMethod").invoke(null)); + + expect(1 == (Byte) Reflection.class.getMethod("byteMethod").invoke(null)); + + expect('2' == (Character) Reflection.class.getMethod + ("charMethod").invoke(null)); + + expect(3 == (Short) Reflection.class.getMethod + ("shortMethod").invoke(null)); + + expect(4 == (Integer) Reflection.class.getMethod + ("intMethod").invoke(null)); + + expect(5.0 == (Float) Reflection.class.getMethod + ("floatMethod").invoke(null)); + + expect(6 == (Long) Reflection.class.getMethod + ("longMethod").invoke(null)); + + expect(7.0 == (Double) Reflection.class.getMethod + ("doubleMethod").invoke(null)); } } From 45674efcea0e33413d6a4f9ea52e9f85dffaf3cd Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 22 Feb 2011 18:37:42 -0700 Subject: [PATCH 12/32] implement JVM_SetSockOpt and Unsafe.getLongVolatile --- src/classpath-openjdk.cpp | 48 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 6e432d54d2..4e10e073fd 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -1395,6 +1395,22 @@ pipeAvailable(int fd, int* available) #endif } +object +fieldForOffset(Thread* t, object o, 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) + { + return field; + } + } + + abort(t); +} + } // namespace local } // namespace @@ -1569,6 +1585,32 @@ Avian_sun_misc_Unsafe_getIntVolatile return result; } +extern "C" JNIEXPORT int64_t JNICALL +Avian_sun_misc_Unsafe_getLongVolatile +(Thread* t, object, uintptr_t* arguments) +{ + object o = reinterpret_cast(arguments[1]); + int64_t offset; memcpy(&offset, arguments + 2, 8); + + object field; + if (BytesPerWord < 8) { + field = local::fieldForOffset(t, o, offset); + + PROTECT(t, field); + acquire(t, field); + } + + int64_t result = cast(o, offset); + + if (BytesPerWord < 8) { + release(t, field); + } else { + loadMemoryBarrier(); + } + + return result; +} + extern "C" JNIEXPORT void JNICALL Avian_sun_misc_Unsafe_putInt__Ljava_lang_Object_2JI (Thread*, object, uintptr_t* arguments) @@ -3730,7 +3772,11 @@ extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_GetSockOpt)(jint, int, int, char*, int*) { abort(); } extern "C" JNIEXPORT jint JNICALL -EXPORT(JVM_SetSockOpt)(jint, int, int, const char*, int) { abort(); } +EXPORT(JVM_SetSockOpt)(jint socket, int level, int optionName, + const char* optionValue, int optionLength) +{ + return setsockopt(socket, level, optionName, optionValue, optionLength); +} extern "C" JNIEXPORT struct protoent* JNICALL EXPORT(JVM_GetProtoByName)(char*) { abort(); } From 783c6092af859bab63a2bbd987bdba52e27ed47b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 22 Feb 2011 19:12:41 -0700 Subject: [PATCH 13/32] remove dead break statement from translateInvokeResult --- src/classpath-common.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/classpath-common.h b/src/classpath-common.h index 8c89f94cf6..6fdcdf3742 100644 --- a/src/classpath-common.h +++ b/src/classpath-common.h @@ -313,7 +313,6 @@ translateInvokeResult(Thread* t, unsigned returnCode, object o) case DoubleField: return makeDouble(t, longValue(t, o)); - break; default: abort(t); From 8b9cdc13ba60e376e8ea722794804953ffa82d3d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 22 Feb 2011 19:13:38 -0700 Subject: [PATCH 14/32] fix return of double values from Java to native code on x86_32 --- src/compile-x86.S | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/compile-x86.S b/src/compile-x86.S index 3f839ce3c5..77d681298d 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -385,21 +385,7 @@ GLOBAL(vmInvoke_safeStack): // handle return value based on expected type movl 28(%esp),%ecx - -LOCAL(vmInvoke_void): - cmpl $VOID_TYPE,%ecx - jne LOCAL(vmInvoke_int64) - jmp LOCAL(vmInvoke_return) -LOCAL(vmInvoke_int64): - cmpl $INT64_TYPE,%ecx - jne LOCAL(vmInvoke_int32) - jmp LOCAL(vmInvoke_return) - -LOCAL(vmInvoke_int32): - movl $0,%edx - -LOCAL(vmInvoke_return): popl %ebp ret From 6025ba736e6934a78c3fbad947fe062a4cb3dad8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 22 Feb 2011 19:16:54 -0700 Subject: [PATCH 15/32] fix return of double values from Java to native code on PowerPC --- src/compile-powerpc.S | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/compile-powerpc.S b/src/compile-powerpc.S index 7e40816105..68e4d8acd2 100644 --- a/src/compile-powerpc.S +++ b/src/compile-powerpc.S @@ -215,19 +215,6 @@ LOCAL(vmInvoke_exit): // handle return value based on expected type lwz r8,44(r1) -LOCAL(vmInvoke_void): - cmplwi r8,VOID_TYPE - bne LOCAL(vmInvoke_int64) - b LOCAL(vmInvoke_return) - -LOCAL(vmInvoke_int64): - cmplwi r8,INT64_TYPE - bne LOCAL(vmInvoke_int32) - b LOCAL(vmInvoke_return) - -LOCAL(vmInvoke_int32): - li r3,0 - LOCAL(vmInvoke_return): // load return address lwz r0,8(r1) From cd3d1800c45e503390395824270a704ef0b9fa46 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 22 Feb 2011 19:46:15 -0700 Subject: [PATCH 16/32] fix return of double values from Java to native code on ARM --- src/compile-arm.S | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/compile-arm.S b/src/compile-arm.S index 8c062c1c12..c96ef2bc29 100644 --- a/src/compile-arm.S +++ b/src/compile-arm.S @@ -170,17 +170,6 @@ LOCAL(vmInvoke_exit): // restore callee-saved registers ldmfd sp!, {r4-r11, lr} -LOCAL(vmInvoke_void): - cmp ip, #VOID_TYPE - beq LOCAL(vmInvoke_return) - -LOCAL(vmInvoke_int64): - cmp ip, #INT64_TYPE - beq LOCAL(vmInvoke_return) - -LOCAL(vmInvoke_int32): - mov r1, #0 - LOCAL(vmInvoke_return): bx lr From f1255c8fd8cb5f2b812d66c6d101ea551015ab6b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 25 Feb 2011 08:13:25 -0700 Subject: [PATCH 17/32] use pthread_sigmask instead of sigprocmask to unblock signals Apparently, the behavior of the latter is undefined in multithreaded processes. --- src/posix.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/posix.cpp b/src/posix.cpp index b885e422fc..3fcbb218de 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -924,10 +924,9 @@ handleSignal(int signal, siginfo_t* info, void* context) // supposed to work. sigset_t set; - sigemptyset(&set); sigaddset(&set, signal); - sigprocmask(SIG_UNBLOCK, &set, 0); + pthread_sigmask(SIG_UNBLOCK, &set, 0); vmJump(ip, frame, stack, thread, 0, 0); } From 42fd021acf89c8f1b3133e476b4fd721ac36a7c8 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 25 Feb 2011 08:17:15 -0700 Subject: [PATCH 18/32] various fixes for running Tomcat on the OpenJDK build --- src/classpath-openjdk.cpp | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/classpath-openjdk.cpp b/src/classpath-openjdk.cpp index 4e10e073fd..61bbc06dbf 100644 --- a/src/classpath-openjdk.cpp +++ b/src/classpath-openjdk.cpp @@ -1845,7 +1845,7 @@ EXPORT(JVM_IHashCode)(Thread* t, jobject o) { ENTER(t, Thread::ActiveState); - return objectHash(t, *o); + return o ? objectHash(t, *o) : 0; } uint64_t @@ -2913,10 +2913,18 @@ extern "C" JNIEXPORT jobjectArray JNICALL EXPORT(JVM_GetDeclaredClasses)(Thread*, jclass) { abort(); } extern "C" JNIEXPORT jclass JNICALL -EXPORT(JVM_GetDeclaringClass)(Thread*, jclass) { abort(); } +EXPORT(JVM_GetDeclaringClass)(Thread*, jclass) +{ + // todo: implement properly + return 0; +} extern "C" JNIEXPORT jstring JNICALL -EXPORT(JVM_GetClassSignature)(Thread*, jclass) { abort(); } +EXPORT(JVM_GetClassSignature)(Thread*, jclass) +{ + // todo: implement properly + return 0; +} extern "C" JNIEXPORT jbyteArray JNICALL EXPORT(JVM_GetClassAnnotations)(Thread* t, jclass c) @@ -3769,7 +3777,14 @@ EXPORT(JVM_GetSockName)(jint socket, struct sockaddr* address, } extern "C" JNIEXPORT jint JNICALL -EXPORT(JVM_GetSockOpt)(jint, int, int, char*, int*) { abort(); } +EXPORT(JVM_GetSockOpt)(jint socket, int level, int optionName, + char* optionValue, int* optionLength) +{ + socklen_t length; + int rv = getsockopt(socket, level, optionName, optionValue, &length); + *optionLength = length; + return rv; +} extern "C" JNIEXPORT jint JNICALL EXPORT(JVM_SetSockOpt)(jint socket, int level, int optionName, @@ -3836,7 +3851,11 @@ extern "C" JNIEXPORT jobject JNICALL EXPORT(JVM_InitAgentProperties)(Thread*, jobject) { abort(); } extern "C" JNIEXPORT jobjectArray JNICALL -EXPORT(JVM_GetEnclosingMethodInfo)(JNIEnv*, jclass) { abort(); } +EXPORT(JVM_GetEnclosingMethodInfo)(JNIEnv*, jclass) +{ + // todo: implement properly + return 0; +} extern "C" JNIEXPORT jintArray JNICALL EXPORT(JVM_GetThreadStateValues)(JNIEnv*, jint) { abort(); } From a4c4d54cdd889b0c5dd6dd88ea2ceab2974d1b45 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Fri, 25 Feb 2011 11:04:23 -0700 Subject: [PATCH 19/32] restore MyThread::ip in MyThread::CallTrace destructor This is necessary to ensure we can unwind the stack properly on ARM after returning from a recursive invocation of vmInvoke. --- src/compile.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compile.cpp b/src/compile.cpp index 72490c8490..e1728451eb 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -109,7 +109,7 @@ class MyThread: public Thread { t->scratch = scratch; - doTransition(t, 0, stack, continuation, next); + doTransition(t, ip, stack, continuation, next); } MyThread* t; @@ -2040,6 +2040,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetFrame, target = method; } } else { + expect(t, ip); *targetIp = ip; *targetFrame = 0; *targetStack = static_cast(stack) From 944e2233358cd2ffaf8224efee438e059ed60c18 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 26 Feb 2011 12:40:54 -0700 Subject: [PATCH 20/32] use wait/notifyAll too avoid starvation in Trace test Thread.yield is not enough to ensure that the tracing thread does not starve the test thread on some QEMU VMs, so we use wait/notifyAll to make sure both threads have opportunities to run and the test actually finishes. --- test/Trace.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/Trace.java b/test/Trace.java index 79aa3b421d..e07976888b 100644 --- a/test/Trace.java +++ b/test/Trace.java @@ -67,10 +67,16 @@ public class Trace implements Runnable { if (i % 100 == 0) { System.out.print("r"); System.out.flush(); + synchronized (this) { + notifyAll(); + } } } } finally { - alive = false; + synchronized (this) { + alive = false; + notifyAll(); + } } } @@ -88,7 +94,7 @@ public class Trace implements Runnable { ++ count; if (count % 100 == 0) { - Thread.yield(); + trace.wait(); System.out.print("t"); System.out.flush(); } From 9e1ee7e97452536179aaf907408e997130ebc7e2 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 26 Feb 2011 12:45:22 -0700 Subject: [PATCH 21/32] enable Linux PowerPC build --- makefile | 6 ++- src/binaryToObject/elf.cpp | 16 ++++++-- src/binaryToObject/main.cpp | 6 ++- src/common.h | 2 +- src/compile-powerpc.S | 32 ++++++++------- src/compiler.cpp | 7 ++-- src/powerpc-regs.S | 64 ++++++++++++++++++++++++++++++ src/powerpc.S | 78 +++++++++++++++++++++++-------------- src/powerpc.cpp | 28 ++++++++----- src/powerpc.h | 45 ++++++++++++++------- 10 files changed, 206 insertions(+), 78 deletions(-) create mode 100644 src/powerpc-regs.S diff --git a/makefile b/makefile index ccd6c8ada9..50f813d75b 100644 --- a/makefile +++ b/makefile @@ -3,7 +3,11 @@ MAKEFLAGS = -s name = avian version = 0.4 -build-arch := $(shell uname -m | sed 's/^i.86$$/i386/' | sed 's/^arm.*$$/arm/') +build-arch := $(shell uname -m \ + | sed 's/^i.86$$/i386/' \ + | sed 's/^arm.*$$/arm/' \ + | sed 's/ppc/powerpc/') + ifeq (Power,$(filter Power,$(build-arch))) build-arch = powerpc endif diff --git a/src/binaryToObject/elf.cpp b/src/binaryToObject/elf.cpp index 8af5c0cd58..44915282bb 100644 --- a/src/binaryToObject/elf.cpp +++ b/src/binaryToObject/elf.cpp @@ -35,6 +35,7 @@ #define EV_CURRENT 1 #define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 #define ELFOSABI_SYSV 0 @@ -43,6 +44,7 @@ #define EM_386 3 #define EM_X86_64 62 #define EM_ARM 40 +#define EM_PPC 20 #define SHT_PROGBITS 1 #define SHT_SYMTAB 2 @@ -77,7 +79,6 @@ # error #endif -#define Data ELFDATA2LSB #define OSABI ELFOSABI_SYSV namespace { @@ -178,7 +179,7 @@ void writeObject(const uint8_t* data, unsigned size, FILE* out, const char* startName, const char* endName, const char* sectionName, unsigned sectionFlags, - unsigned alignment, int machine) + unsigned alignment, int machine, int encoding) { const unsigned sectionCount = 5; const unsigned symbolCount = 2; @@ -222,7 +223,7 @@ writeObject(const uint8_t* data, unsigned size, FILE* out, fileHeader.e_ident[EI_MAG2] = ELFMAG2; fileHeader.e_ident[EI_MAG3] = ELFMAG3; fileHeader.e_ident[EI_CLASS] = Class; - fileHeader.e_ident[EI_DATA] = Data; + fileHeader.e_ident[EI_DATA] = encoding; fileHeader.e_ident[EI_VERSION] = EV_CURRENT; fileHeader.e_ident[EI_OSABI] = OSABI; fileHeader.e_ident[EI_ABIVERSION] = 0; @@ -349,12 +350,19 @@ MAKE_NAME(writeElf, BITS_PER_WORD, Object) bool writable, bool executable) { int machine; + int encoding; if (strcmp(architecture, "x86_64") == 0) { machine = EM_X86_64; + encoding = ELFDATA2LSB; } else if (strcmp(architecture, "i386") == 0) { machine = EM_386; + encoding = ELFDATA2LSB; } else if (strcmp(architecture, "arm") == 0) { machine = EM_ARM; + encoding = ELFDATA2LSB; + } else if (strcmp(architecture, "powerpc") == 0) { + machine = EM_PPC; + encoding = ELFDATA2MSB; } else { fprintf(stderr, "unsupported architecture: %s\n", architecture); return false; @@ -376,7 +384,7 @@ MAKE_NAME(writeElf, BITS_PER_WORD, Object) } writeObject(data, size, out, startName, endName, sectionName, sectionFlags, - alignment, machine); + alignment, machine, encoding); return true; } diff --git a/src/binaryToObject/main.cpp b/src/binaryToObject/main.cpp index c95f193d3d..41f2951645 100644 --- a/src/binaryToObject/main.cpp +++ b/src/binaryToObject/main.cpp @@ -73,8 +73,10 @@ writeObject(uint8_t* data, unsigned size, FILE* out, const char* startName, success = writeElf64Object (data, size, out, startName, endName, architecture, alignment, writable, executable); - } else if (strcmp("i386", architecture) == 0 || - strcmp("arm", architecture) == 0) { + } else if (strcmp("i386", architecture) == 0 + or strcmp("arm", architecture) == 0 + or strcmp("powerpc", architecture) == 0) + { found = true; success = writeElf32Object (data, size, out, startName, endName, architecture, alignment, diff --git a/src/common.h b/src/common.h index 13957bedfd..5c7160e54c 100644 --- a/src/common.h +++ b/src/common.h @@ -88,7 +88,7 @@ alias(void* p, unsigned offset) # define ARCH_x86_32 # elif defined __x86_64__ # define ARCH_x86_64 -# elif defined __POWERPC__ +# elif (defined __POWERPC__) || (defined __powerpc__) # define ARCH_powerpc # elif defined __arm__ # define ARCH_arm diff --git a/src/compile-powerpc.S b/src/compile-powerpc.S index 68e4d8acd2..546432beb3 100644 --- a/src/compile-powerpc.S +++ b/src/compile-powerpc.S @@ -13,16 +13,21 @@ .text #define BYTES_PER_WORD 4 -#define LINKAGE_AREA 6 -#define ARGUMENT_BASE BYTES_PER_WORD * LINKAGE_AREA - -#define LOCAL(x) L##x #ifdef __APPLE__ # define GLOBAL(x) _##x +# define LOCAL(x) L##x +# define LINKAGE_AREA 6 +# define RETURN_ADDRESS_OFFSET 8 #else -# define GLOBAL(x) x +# define GLOBAL(x) x +# define LOCAL(x) .L##x +# define LINKAGE_AREA 2 +# define RETURN_ADDRESS_OFFSET 4 +# include "powerpc-regs.S" #endif + +#define ARGUMENT_BASE BYTES_PER_WORD * LINKAGE_AREA #define THREAD_STACK 2148 #define THREAD_CONTINUATION 2156 @@ -42,7 +47,7 @@ GLOBAL(vmInvoke): // save return address mflr r0 - stw r0,8(r1) + stw r0,RETURN_ADDRESS_OFFSET(r1) // r3: thread // r4: function @@ -53,12 +58,10 @@ GLOBAL(vmInvoke): // r9: temporary - // save return type - stw r8,44(r1) - - // allocate stack space, adding room for callee-saved registers + // allocate stack space, adding room for callee-saved registers and + // return type subfic r9,r7,-80 - stwux r1,r1,r9 + stwux r1,r1,r9 // save callee-saved registers add r9,r7,r1 @@ -83,6 +86,9 @@ GLOBAL(vmInvoke): stw r30,68(r9) stw r31,72(r9) + // save return type + stw r8,74(r9) + // we use r13 to hold the thread pointer, by convention mr r13,r3 @@ -213,11 +219,11 @@ LOCAL(vmInvoke_exit): lwz r31,72(r9) // handle return value based on expected type - lwz r8,44(r1) + lwz r8,74(r9) LOCAL(vmInvoke_return): // load return address - lwz r0,8(r1) + lwz r0,RETURN_ADDRESS_OFFSET(r1) mtlr r0 // return diff --git a/src/compiler.cpp b/src/compiler.cpp index 18dc98e06f..2d809b1c5e 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -2171,9 +2171,9 @@ class MemorySite: public Site { } virtual Site* makeNextWord(Context* c, unsigned index) { - // todo: endianness? return memorySite - (c, base, offset + (index == 1 ? BytesPerWord : -BytesPerWord), + (c, base, offset + ((index == 1) xor c->arch->bigEndian() + ? BytesPerWord : -BytesPerWord), this->index, scale); } @@ -2184,12 +2184,11 @@ class MemorySite: public Site { } virtual SiteMask nextWordMask(Context* c, unsigned index) { - // todo: endianness? int frameIndex; if (base == c->arch->stack()) { assert(c, this->index == NoRegister); frameIndex = static_cast(offsetToFrameIndex(c, offset)) - + (index == 1 ? 1 : -1); + + ((index == 1) xor c->arch->bigEndian() ? 1 : -1); } else { frameIndex = NoFrameIndex; } diff --git a/src/powerpc-regs.S b/src/powerpc-regs.S new file mode 100644 index 0000000000..da5940f403 --- /dev/null +++ b/src/powerpc-regs.S @@ -0,0 +1,64 @@ +#define r0 0 +#define r1 1 +#define r2 2 +#define r3 3 +#define r4 4 +#define r5 5 +#define r6 6 +#define r7 7 +#define r8 8 +#define r9 9 +#define r10 10 +#define r11 11 +#define r12 12 +#define r13 13 +#define r14 14 +#define r15 15 +#define r16 16 +#define r17 17 +#define r18 18 +#define r19 19 +#define r20 20 +#define r21 21 +#define r22 22 +#define r23 23 +#define r24 24 +#define r25 25 +#define r26 26 +#define r27 27 +#define r28 28 +#define r29 29 +#define r30 30 +#define r31 31 +#define f0 0 +#define f1 1 +#define f2 2 +#define f3 3 +#define f4 4 +#define f5 5 +#define f6 6 +#define f7 7 +#define f8 8 +#define f9 9 +#define f10 10 +#define f11 11 +#define f12 12 +#define f13 13 +#define f14 14 +#define f15 15 +#define f16 16 +#define f17 17 +#define f18 18 +#define f19 19 +#define f20 20 +#define f21 21 +#define f22 22 +#define f23 23 +#define f24 24 +#define f25 25 +#define f26 26 +#define f27 27 +#define f28 28 +#define f29 29 +#define f30 30 +#define f31 31 diff --git a/src/powerpc.S b/src/powerpc.S index 2b26f7985f..96bf382cfb 100644 --- a/src/powerpc.S +++ b/src/powerpc.S @@ -13,22 +13,28 @@ .text #define BYTES_PER_WORD 4 -#define LINKAGE_AREA 6 #define GPR_COUNT 8 -#define MEMORY_BASE BYTES_PER_WORD * (LINKAGE_AREA + GPR_COUNT) -#define LOCAL(x) L##x #ifdef __APPLE__ # define GLOBAL(x) _##x +# define LOCAL(x) L##x +# define LINKAGE_AREA 6 +# define MEMORY_BASE BYTES_PER_WORD * (LINKAGE_AREA + GPR_COUNT) +# define RETURN_ADDRESS_OFFSET 8 #else -# define GLOBAL(x) x +# define GLOBAL(x) x +# define LOCAL(x) .L##x +# define LINKAGE_AREA 2 +# define MEMORY_BASE BYTES_PER_WORD * LINKAGE_AREA +# define RETURN_ADDRESS_OFFSET 4 +# include "powerpc-regs.S" #endif .globl GLOBAL(vmNativeCall) GLOBAL(vmNativeCall): // save return address mflr r0 - stw r0,8(r1) + stw r0,RETURN_ADDRESS_OFFSET(r1) // r3 aka r13: function // r4 : stackTotal @@ -42,17 +48,26 @@ GLOBAL(vmNativeCall): // r16 : temporary // r17 : temporary // r18 : temporary - - // save registers used for local variables - stw r13,24(r1) - stw r14,28(r1) - stw r15,32(r1) - stw r16,36(r1) - stw r17,40(r1) - stw r18,44(r1) - // allocate stack space - stwux r1,r1,r4 + // allocate stack space, adding room for callee-saved registers and + // scratch space for copying a FP return value into GPRs + subfic r10,r4,-48 + stwux r1,r1,r10 + + // save callee-saved registers used for local variables + add r10,r4,r1 + + // save registers used for local variables + stw r13,0(r10) + stw r14,4(r10) + stw r15,8(r10) + stw r16,12(r10) + stw r17,16(r10) + stw r18,20(r10) + stw r19,24(r10) + + // remember where we saved the local variables + mr r19,r10 // save our argument registers so we can clobber them mr r13,r3 @@ -84,12 +99,14 @@ LOCAL(test): lfd f6,40(r8) lfd f7,48(r8) lfd f8,56(r8) +#ifdef __APPLE__ lfd f9,64(r8) lfd f10,72(r8) lfd f11,80(r8) lfd f12,88(r8) lfd f13,96(r8) - +#endif + LOCAL(gpr): // do we need to load the general-purpose registers? cmpwi r7,0 @@ -128,25 +145,26 @@ LOCAL(float): LOCAL(copy): // move floating point return value to GPRs via memory - stfd f1,8(r1) - lwz r3,8(r1) - lwz r4,12(r1) + stfd f1,32(r19) + lwz r3,32(r19) + lwz r4,36(r19) b LOCAL(exit) LOCAL(exit): + // restore callee-saved registers used for local variables + lwz r13,0(r19) + lwz r14,4(r19) + lwz r15,8(r19) + lwz r16,12(r19) + lwz r17,16(r19) + lwz r18,20(r19) + lwz r19,24(r19) + // restore stack pointer lwz r1,0(r1) - // restore registers used for local variables - lwz r13,24(r1) - lwz r14,28(r1) - lwz r15,32(r1) - lwz r16,36(r1) - lwz r17,40(r1) - lwz r18,44(r1) - // load return address - lwz r0,8(r1) + lwz r0,RETURN_ADDRESS_OFFSET(r1) mtlr r0 // return @@ -171,7 +189,7 @@ GLOBAL(vmRun): // r5: checkpoint mflr r0 - stw r0,8(r1) + stw r0,RETURN_ADDRESS_OFFSET(r1) stwu r1,-(MEMORY_BASE+88)(r1) @@ -226,6 +244,6 @@ GLOBAL(vmRun_returnAddress): lwz r31,MEMORY_BASE+72(r1) lwz r1,0(r1) - lwz r0,8(r1) + lwz r0,RETURN_ADDRESS_OFFSET(r1) mtlr r0 blr diff --git a/src/powerpc.cpp b/src/powerpc.cpp index 6c721651ba..3644520647 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -162,7 +162,15 @@ carry16(intptr_t v) return static_cast(v) < 0 ? 1 : 0; } +#ifdef __APPLE__ const unsigned FrameFooterSize = 6; +const unsigned ReturnAddressOffset = 2; +const unsigned AlignArguments = false; +#else +const unsigned FrameFooterSize = 2; +const unsigned ReturnAddressOffset = 1; +const unsigned AlignArguments = true; +#endif const unsigned StackAlignmentInBytes = 16; const unsigned StackAlignmentInWords = StackAlignmentInBytes / BytesPerWord; @@ -1777,7 +1785,7 @@ nextFrame(ArchitectureContext* c UNUSED, int32_t* start, unsigned size, // todo: check for and handle tail calls } - *ip = static_cast(*stack)[offset + 2]; + *ip = static_cast(*stack)[offset + ReturnAddressOffset]; *stack = static_cast(*stack) + offset; } @@ -1940,7 +1948,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual bool argumentAlignment() { - return false; + return AlignArguments; } virtual unsigned argumentRegisterCount() { @@ -2023,7 +2031,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual void* frameIp(void* stack) { - return stack ? static_cast(stack)[2] : 0; + return stack ? static_cast(stack)[ReturnAddressOffset] : 0; } virtual unsigned frameHeaderSize() { @@ -2039,7 +2047,7 @@ class MyArchitecture: public Assembler::Architecture { } virtual int returnAddressOffset() { - return 8 / BytesPerWord; + return ReturnAddressOffset; } virtual int framePointerOffset() { @@ -2261,7 +2269,7 @@ class MyAssembler: public Assembler { Register returnAddress(0); emit(&c, mflr(returnAddress.low)); - Memory returnAddressDst(StackRegister, 8); + Memory returnAddressDst(StackRegister, ReturnAddressOffset * BytesPerWord); moveRM(&c, BytesPerWord, &returnAddress, BytesPerWord, &returnAddressDst); Register stack(StackRegister); @@ -2314,7 +2322,7 @@ class MyAssembler: public Assembler { Register returnAddress(0); emit(&c, mflr(returnAddress.low)); - Memory returnAddressDst(StackRegister, 8); + Memory returnAddressDst(StackRegister, ReturnAddressOffset * BytesPerWord); moveRM(&c, BytesPerWord, &returnAddress, BytesPerWord, &returnAddressDst); Register stack(StackRegister); @@ -2337,7 +2345,7 @@ class MyAssembler: public Assembler { moveMR(&c, BytesPerWord, &stackSrc, BytesPerWord, &stack); Register returnAddress(0); - Memory returnAddressSrc(StackRegister, 8); + Memory returnAddressSrc(StackRegister, ReturnAddressOffset * BytesPerWord); moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &returnAddress); emit(&c, mtlr(returnAddress.low)); @@ -2351,7 +2359,8 @@ class MyAssembler: public Assembler { if (TailCalls) { if (offset) { Register tmp(0); - Memory returnAddressSrc(StackRegister, 8 + (footprint * BytesPerWord)); + Memory returnAddressSrc + (StackRegister, (ReturnAddressOffset + footprint) * BytesPerWord); moveMR(&c, BytesPerWord, &returnAddressSrc, BytesPerWord, &tmp); emit(&c, mtlr(tmp.low)); @@ -2366,7 +2375,8 @@ class MyAssembler: public Assembler { assert(&c, offset > 0); Register ras(returnAddressSurrogate); - Memory dst(StackRegister, 8 + (offset * BytesPerWord)); + Memory dst + (StackRegister, (ReturnAddressOffset + offset) * BytesPerWord); moveRM(&c, BytesPerWord, &ras, BytesPerWord, &dst); } diff --git a/src/powerpc.h b/src/powerpc.h index b519ac8064..5fe4543cc7 100644 --- a/src/powerpc.h +++ b/src/powerpc.h @@ -14,8 +14,6 @@ #include "types.h" #include "common.h" -#define VA_LIST(x) (&(x)) - #ifdef __APPLE__ # include "mach/mach_types.h" # include "mach/ppc/thread_act.h" @@ -45,9 +43,17 @@ # define LINK_REGISTER(context) \ THREAD_STATE_LINK(context->uc_mcontext->FIELD(ss)) -#else -# error "non-Apple PowerPC-based platforms not yet supported" -#endif +#define VA_LIST(x) (&(x)) + +#else // not __APPLE__ +# define IP_REGISTER(context) (context->uc_mcontext.regs->gpr[32]) +# define STACK_REGISTER(context) (context->uc_mcontext.regs->gpr[1]) +# define THREAD_REGISTER(context) (context->uc_mcontext.regs->gpr[13]) +# define LINK_REGISTER(context) (context->uc_mcontext.regs->gpr[36]) + +#define VA_LIST(x) (x) + +#endif // not __APPLE__ extern "C" uint64_t vmNativeCall(void* function, unsigned stackTotal, void* memoryTable, @@ -150,13 +156,22 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, unsigned argumentCount, unsigned argumentsSize, unsigned returnType) { +#ifdef __APPLE__ +# define SKIP(var, count) var += count; +# define ALIGN(var) const unsigned LinkageArea = 24; + const unsigned FprCount = 13; +#else +# define SKIP(var, count) +# define ALIGN(var) if (var & 1) ++var; + const unsigned LinkageArea = 8; + const unsigned FprCount = 8; +#endif const unsigned GprCount = 8; uintptr_t gprTable[GprCount]; unsigned gprIndex = 0; - const unsigned FprCount = 13; uint64_t fprTable[FprCount]; unsigned fprIndex = 0; @@ -172,8 +187,8 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, double d = bitsToFloat(arguments[ai]); memcpy(fprTable + fprIndex, &d, 8); ++ fprIndex; - ++ gprIndex; - ++ stackSkip; + SKIP(gprIndex, 1); + SKIP(stackSkip, 1); } else { stack[stackIndex++] = arguments[ai]; } @@ -184,9 +199,10 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, if (fprIndex + (8 / BytesPerWord) <= FprCount) { memcpy(fprTable + fprIndex, arguments + ai, 8); ++ fprIndex; - gprIndex += 8 / BytesPerWord; - stackSkip += 8 / BytesPerWord; + SKIP(gprIndex, 8 / BytesPerWord); + SKIP(stackSkip, 8 / BytesPerWord); } else { + ALIGN(stackIndex); memcpy(stack + stackIndex, arguments + ai, 8); stackIndex += 8 / BytesPerWord; } @@ -195,10 +211,12 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, case INT64_TYPE: { if (gprIndex + (8 / BytesPerWord) <= GprCount) { + ALIGN(gprIndex); memcpy(gprTable + gprIndex, arguments + ai, 8); gprIndex += 8 / BytesPerWord; - stackSkip += 8 / BytesPerWord; + SKIP(stackSkip, 8 / BytesPerWord); } else { + ALIGN(stackIndex); memcpy(stack + stackIndex, arguments + ai, 8); stackIndex += 8 / BytesPerWord; } @@ -208,7 +226,7 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, default: { if (gprIndex < GprCount) { gprTable[gprIndex++] = arguments[ai]; - ++ stackSkip; + SKIP(stackSkip, 1); } else { stack[stackIndex++] = arguments[ai]; } @@ -219,8 +237,7 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t* argumentTypes, return vmNativeCall (function, - - ((((1 + stackSkip + stackIndex) * BytesPerWord) + LinkageArea + 15) - & -16), + (((1 + stackSkip + stackIndex) * BytesPerWord) + LinkageArea + 15) & -16, stack, stackIndex * BytesPerWord, (gprIndex ? gprTable : 0), (fprIndex ? fprTable : 0), returnType); From 039916b519eb8ea9d477e078cc6f572a8b4621bb Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 26 Feb 2011 17:08:08 -0700 Subject: [PATCH 22/32] fix incorrect offset in compile-powerpc.S --- src/compile-powerpc.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compile-powerpc.S b/src/compile-powerpc.S index 546432beb3..e97556e483 100644 --- a/src/compile-powerpc.S +++ b/src/compile-powerpc.S @@ -87,7 +87,7 @@ GLOBAL(vmInvoke): stw r31,72(r9) // save return type - stw r8,74(r9) + stw r8,76(r9) // we use r13 to hold the thread pointer, by convention mr r13,r3 @@ -219,7 +219,7 @@ LOCAL(vmInvoke_exit): lwz r31,72(r9) // handle return value based on expected type - lwz r8,74(r9) + lwz r8,76(r9) LOCAL(vmInvoke_return): // load return address From 5f50226ae0308df101a8c40ed137f681d739196f Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 27 Feb 2011 22:54:59 -0700 Subject: [PATCH 23/32] enable Linux/PowerPC cross build --- makefile | 13 ++- src/binaryToObject/elf.cpp | 167 +++++++++++++++++--------------- src/binaryToObject/endianness.h | 38 ++++++++ src/binaryToObject/mach-o.cpp | 28 +----- 4 files changed, 139 insertions(+), 107 deletions(-) create mode 100644 src/binaryToObject/endianness.h diff --git a/makefile b/makefile index 50f813d75b..bca5d1719a 100644 --- a/makefile +++ b/makefile @@ -169,7 +169,7 @@ endif build-cflags = $(common-cflags) -fPIC -fvisibility=hidden \ "-I$(JAVA_HOME)/include/linux" -I$(src) -pthread -converter-cflags = -D__STDC_CONSTANT_MACROS +converter-cflags = -D__STDC_CONSTANT_MACROS -Isrc/binaryToObject cflags = $(build-cflags) @@ -201,6 +201,15 @@ endif ifeq ($(arch),powerpc) asm = powerpc pointer-size = 4 + + ifneq ($(arch),$(build-arch)) + converter-cflags += -DOPPOSITE_ENDIAN + cxx = powerpc-linux-gnu-g++ + cc = powerpc-linux-gnu-gcc + ar = powerpc-linux-gnu-ar + ranlib = powerpc-linux-gnu-ranlib + strip = powerpc-linux-gnu-strip + endif endif ifeq ($(arch),arm) asm = arm @@ -243,7 +252,7 @@ ifeq ($(platform),darwin) shared = -dynamiclib ifeq ($(arch),powerpc) - ifneq (,$(filter i386 x86_64,$(build-arch))) + ifneq (,$(filter i386 x86_64 arm,$(build-arch))) converter-cflags += -DOPPOSITE_ENDIAN endif openjdk-extra-cflags += -arch ppc -mmacosx-version-min=10.4 diff --git a/src/binaryToObject/elf.cpp b/src/binaryToObject/elf.cpp index 44915282bb..51193dd2c7 100644 --- a/src/binaryToObject/elf.cpp +++ b/src/binaryToObject/elf.cpp @@ -12,6 +12,8 @@ #include "stdio.h" #include "string.h" +#include "endianness.h" + #define EI_NIDENT 16 #define EI_MAG0 0 @@ -218,99 +220,108 @@ writeObject(const uint8_t* data, unsigned size, FILE* out, const unsigned stringTableSectionNumber = 3; FileHeader fileHeader; - fileHeader.e_ident[EI_MAG0] = ELFMAG0; - fileHeader.e_ident[EI_MAG1] = ELFMAG1; - fileHeader.e_ident[EI_MAG2] = ELFMAG2; - fileHeader.e_ident[EI_MAG3] = ELFMAG3; - fileHeader.e_ident[EI_CLASS] = Class; - fileHeader.e_ident[EI_DATA] = encoding; - fileHeader.e_ident[EI_VERSION] = EV_CURRENT; - fileHeader.e_ident[EI_OSABI] = OSABI; - fileHeader.e_ident[EI_ABIVERSION] = 0; - fileHeader.e_type = ET_REL; - fileHeader.e_machine = machine; - fileHeader.e_version = EV_CURRENT; - fileHeader.e_entry = 0; - fileHeader.e_phoff = 0; - fileHeader.e_shoff = sizeof(FileHeader); - fileHeader.e_flags = (machine == EM_ARM ? 0x04000000 : 0); - fileHeader.e_ehsize = sizeof(FileHeader); - fileHeader.e_phentsize = 0; - fileHeader.e_phnum = 0; - fileHeader.e_shentsize = sizeof(SectionHeader); - fileHeader.e_shnum = sectionCount; - fileHeader.e_shstrndx = sectionStringTableSectionNumber; + memset(&fileHeader, 0, sizeof(FileHeader)); + fileHeader.e_ident[EI_MAG0] = V1(ELFMAG0); + fileHeader.e_ident[EI_MAG1] = V1(ELFMAG1); + fileHeader.e_ident[EI_MAG2] = V1(ELFMAG2); + fileHeader.e_ident[EI_MAG3] = V1(ELFMAG3); + fileHeader.e_ident[EI_CLASS] = V1(Class); + fileHeader.e_ident[EI_DATA] = V1(encoding); + fileHeader.e_ident[EI_VERSION] = V1(EV_CURRENT); + fileHeader.e_ident[EI_OSABI] = V1(OSABI); + fileHeader.e_ident[EI_ABIVERSION] = V1(0); + fileHeader.e_type = V2(ET_REL); + fileHeader.e_machine = V2(machine); + fileHeader.e_version = V4(EV_CURRENT); + fileHeader.e_entry = VW(0); + fileHeader.e_phoff = VW(0); + fileHeader.e_shoff = VW(sizeof(FileHeader)); + fileHeader.e_flags = V4(machine == EM_ARM ? 0x04000000 : 0); + fileHeader.e_ehsize = V2(sizeof(FileHeader)); + fileHeader.e_phentsize = V2(0); + fileHeader.e_phnum = V2(0); + fileHeader.e_shentsize = V2(sizeof(SectionHeader)); + fileHeader.e_shnum = V2(sectionCount); + fileHeader.e_shstrndx = V2(sectionStringTableSectionNumber); SectionHeader nullSection; memset(&nullSection, 0, sizeof(SectionHeader)); SectionHeader bodySection; - bodySection.sh_name = sectionNameOffset; - bodySection.sh_type = SHT_PROGBITS; - bodySection.sh_flags = sectionFlags; - bodySection.sh_addr = 0; - bodySection.sh_offset = sizeof(FileHeader) - + (sizeof(SectionHeader) * sectionCount); - bodySection.sh_size = size; - bodySection.sh_link = 0; - bodySection.sh_info = 0; - bodySection.sh_addralign = alignment; - bodySection.sh_entsize = 0; + bodySection.sh_name = V4(sectionNameOffset); + bodySection.sh_type = V4(SHT_PROGBITS); + bodySection.sh_flags = VW(sectionFlags); + bodySection.sh_addr = VW(0); + unsigned bodySectionOffset + = sizeof(FileHeader) + (sizeof(SectionHeader) * sectionCount); + bodySection.sh_offset = VW(bodySectionOffset); + unsigned bodySectionSize = size; + bodySection.sh_size = VW(bodySectionSize); + bodySection.sh_link = V4(0); + bodySection.sh_info = V4(0); + bodySection.sh_addralign = VW(alignment); + bodySection.sh_entsize = VW(0); SectionHeader sectionStringTableSection; - sectionStringTableSection.sh_name = sectionStringTableNameOffset; - sectionStringTableSection.sh_type = SHT_STRTAB; - sectionStringTableSection.sh_flags = 0; - sectionStringTableSection.sh_addr = 0; - sectionStringTableSection.sh_offset - = bodySection.sh_offset + bodySection.sh_size; - sectionStringTableSection.sh_size = sectionStringTableLength; - sectionStringTableSection.sh_link = 0; - sectionStringTableSection.sh_info = 0; - sectionStringTableSection.sh_addralign = 1; - sectionStringTableSection.sh_entsize = 0; + sectionStringTableSection.sh_name = V4(sectionStringTableNameOffset); + sectionStringTableSection.sh_type = V4(SHT_STRTAB); + sectionStringTableSection.sh_flags = VW(0); + sectionStringTableSection.sh_addr = VW(0); + unsigned sectionStringTableSectionOffset + = bodySectionOffset + bodySectionSize; + sectionStringTableSection.sh_offset = VW(sectionStringTableSectionOffset); + unsigned sectionStringTableSectionSize = sectionStringTableLength; + sectionStringTableSection.sh_size = VW(sectionStringTableSectionSize); + sectionStringTableSection.sh_link = V4(0); + sectionStringTableSection.sh_info = V4(0); + sectionStringTableSection.sh_addralign = VW(1); + sectionStringTableSection.sh_entsize = VW(0); SectionHeader stringTableSection; - stringTableSection.sh_name = stringTableNameOffset; - stringTableSection.sh_type = SHT_STRTAB; - stringTableSection.sh_flags = 0; - stringTableSection.sh_addr = 0; - stringTableSection.sh_offset = sectionStringTableSection.sh_offset - + sectionStringTableSection.sh_size; - stringTableSection.sh_size = stringTableLength; - stringTableSection.sh_link = 0; - stringTableSection.sh_info = 0; - stringTableSection.sh_addralign = 1; - stringTableSection.sh_entsize = 0; + stringTableSection.sh_name = V4(stringTableNameOffset); + stringTableSection.sh_type = V4(SHT_STRTAB); + stringTableSection.sh_flags = VW(0); + stringTableSection.sh_addr = VW(0); + unsigned stringTableSectionOffset + = sectionStringTableSectionOffset + sectionStringTableSectionSize; + stringTableSection.sh_offset = VW(stringTableSectionOffset); + unsigned stringTableSectionSize = stringTableLength; + stringTableSection.sh_size = VW(stringTableSectionSize); + stringTableSection.sh_link = V4(0); + stringTableSection.sh_info = V4(0); + stringTableSection.sh_addralign = VW(1); + stringTableSection.sh_entsize = VW(0); SectionHeader symbolTableSection; - symbolTableSection.sh_name = symbolTableNameOffset; - symbolTableSection.sh_type = SHT_SYMTAB; - symbolTableSection.sh_flags = 0; - symbolTableSection.sh_addr = 0; - symbolTableSection.sh_offset = stringTableSection.sh_offset - + stringTableSection.sh_size; - symbolTableSection.sh_size = sizeof(Symbol) * symbolCount; - symbolTableSection.sh_link = stringTableSectionNumber; - symbolTableSection.sh_info = 0; - symbolTableSection.sh_addralign = BITS_PER_WORD / 8; - symbolTableSection.sh_entsize = sizeof(Symbol); + symbolTableSection.sh_name = V4(symbolTableNameOffset); + symbolTableSection.sh_type = V4(SHT_SYMTAB); + symbolTableSection.sh_flags = VW(0); + symbolTableSection.sh_addr = VW(0); + unsigned symbolTableSectionOffset + = stringTableSectionOffset + stringTableSectionSize; + symbolTableSection.sh_offset = VW(symbolTableSectionOffset); + unsigned symbolTableSectionSize = sizeof(Symbol) * symbolCount; + symbolTableSection.sh_size = VW(symbolTableSectionSize); + symbolTableSection.sh_link = V4(stringTableSectionNumber); + symbolTableSection.sh_info = V4(0); + symbolTableSection.sh_addralign = VW(BITS_PER_WORD / 8); + symbolTableSection.sh_entsize = VW(sizeof(Symbol)); Symbol startSymbol; - startSymbol.st_name = startNameOffset; - startSymbol.st_value = 0; - startSymbol.st_size = 0; - startSymbol.st_info = SYMBOL_INFO(STB_GLOBAL, STT_NOTYPE); - startSymbol.st_other = STV_DEFAULT; - startSymbol.st_shndx = bodySectionNumber; + startSymbol.st_name = V4(startNameOffset); + startSymbol.st_value = VW(0); + startSymbol.st_size = VW(0); + startSymbol.st_info = V1(SYMBOL_INFO(STB_GLOBAL, STT_NOTYPE)); + startSymbol.st_other = V1(STV_DEFAULT); + startSymbol.st_shndx = V2(bodySectionNumber); Symbol endSymbol; - endSymbol.st_name = endNameOffset; - endSymbol.st_value = size; - endSymbol.st_size = 0; - endSymbol.st_info = SYMBOL_INFO(STB_GLOBAL, STT_NOTYPE); - endSymbol.st_other = STV_DEFAULT; - endSymbol.st_shndx = bodySectionNumber; + endSymbol.st_name = V4(endNameOffset); + endSymbol.st_value = VW(size); + endSymbol.st_size = VW(0); + endSymbol.st_info = V1(SYMBOL_INFO(STB_GLOBAL, STT_NOTYPE)); + endSymbol.st_other = V1(STV_DEFAULT); + endSymbol.st_shndx = V2(bodySectionNumber); fwrite(&fileHeader, 1, sizeof(fileHeader), out); fwrite(&nullSection, 1, sizeof(nullSection), out); diff --git a/src/binaryToObject/endianness.h b/src/binaryToObject/endianness.h new file mode 100644 index 0000000000..46cfcd8b46 --- /dev/null +++ b/src/binaryToObject/endianness.h @@ -0,0 +1,38 @@ +#ifndef ENDIANNESS_H +#define ENDIANNESS_H + +#define V1(v) (v) + +#ifdef OPPOSITE_ENDIAN +# define V2(v) \ + ((((v) >> 8) & 0xFF) | \ + (((v) << 8))) +# define V4(v) \ + ((((v) >> 24) & 0x000000FF) | \ + (((v) >> 8) & 0x0000FF00) | \ + (((v) << 8) & 0x00FF0000) | \ + (((v) << 24))) +# define V8(v) \ + (((static_cast(v) >> 56) & UINT64_C(0x00000000000000FF)) | \ + ((static_cast(v) >> 40) & UINT64_C(0x000000000000FF00)) | \ + ((static_cast(v) >> 24) & UINT64_C(0x0000000000FF0000)) | \ + ((static_cast(v) >> 8) & UINT64_C(0x00000000FF000000)) | \ + ((static_cast(v) << 8) & UINT64_C(0x000000FF00000000)) | \ + ((static_cast(v) << 24) & UINT64_C(0x0000FF0000000000)) | \ + ((static_cast(v) << 40) & UINT64_C(0x00FF000000000000)) | \ + ((static_cast(v) << 56))) +#else +# define V2(v) (v) +# define V4(v) (v) +# define V8(v) (v) +#endif + +#if (BITS_PER_WORD == 64) +# define VW(v) V8(v) +#elif (BITS_PER_WORD == 32) +# define VW(v) V4(v) +#else +# error +#endif + +#endif//ENDIANNESS_H diff --git a/src/binaryToObject/mach-o.cpp b/src/binaryToObject/mach-o.cpp index d832703200..742e3870d1 100644 --- a/src/binaryToObject/mach-o.cpp +++ b/src/binaryToObject/mach-o.cpp @@ -12,31 +12,7 @@ #include "stdio.h" #include "string.h" -#define V1(v) v - -#ifdef OPPOSITE_ENDIAN -# define V2(v) \ - ((((v) >> 8) & 0xFF) | \ - (((v) << 8))) -# define V4(v) \ - ((((v) >> 24) & 0x000000FF) | \ - (((v) >> 8) & 0x0000FF00) | \ - (((v) << 8) & 0x00FF0000) | \ - (((v) << 24))) -# define V8(v) \ - (((static_cast(v) >> 56) & UINT64_C(0x00000000000000FF)) | \ - ((static_cast(v) >> 40) & UINT64_C(0x000000000000FF00)) | \ - ((static_cast(v) >> 24) & UINT64_C(0x0000000000FF0000)) | \ - ((static_cast(v) >> 8) & UINT64_C(0x00000000FF000000)) | \ - ((static_cast(v) << 8) & UINT64_C(0x000000FF00000000)) | \ - ((static_cast(v) << 24) & UINT64_C(0x0000FF0000000000)) | \ - ((static_cast(v) << 40) & UINT64_C(0x00FF000000000000)) | \ - ((static_cast(v) << 56))) -#else -# define V2(v) v -# define V4(v) v -# define V8(v) v -#endif +#include "endianness.h" #define MH_MAGIC_64 0xfeedfacf #define MH_MAGIC 0xfeedface @@ -63,7 +39,6 @@ #define CPU_SUBTYPE_POWERPC_ALL 0 #if (BITS_PER_WORD == 64) -# define VW(v) V8(v) # define Magic MH_MAGIC_64 # define Segment LC_SEGMENT_64 # define FileHeader mach_header_64 @@ -71,7 +46,6 @@ # define Section section_64 # define NList struct nlist_64 #elif (BITS_PER_WORD == 32) -# define VW(v) V4(v) # define Magic MH_MAGIC # define Segment LC_SEGMENT # define FileHeader mach_header From 255fc9f9d380db755d76478b7d4210d893b7b674 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sun, 27 Feb 2011 23:03:13 -0700 Subject: [PATCH 24/32] handle long conditional immediate branches properly on PowerPC Due to encoding limitations, the immediate operand of conditional branches can be no more than 32KB forward or backward. Since the JIT-compiled form of some methods can be larger than 32KB, and we also do conditional jumps to code outside the current method in some cases, we must work around this limitation. The strategy of this commit is to provide inline, intermediate jump tables where necessary. A given conditional branch whose target is too far for a direct jump will instead point to an unconditional branch in the nearest jump table which points to the actual target. Unconditional immediate branches are also limited on PowerPC, but this limit is 32MB, which is not an impediment in practice. If it does become a problem, we'll need to encode such branches using multiple instructions. --- src/arm.cpp | 23 ++- src/assembler.h | 4 +- src/compile.cpp | 29 ++-- src/compiler.cpp | 52 ++++--- src/compiler.h | 7 +- src/powerpc.cpp | 364 ++++++++++++++++++++++++++++++++++++++--------- src/x86.cpp | 7 +- 7 files changed, 377 insertions(+), 109 deletions(-) diff --git a/src/arm.cpp b/src/arm.cpp index c026635ed4..38ba3a6ce4 100644 --- a/src/arm.cpp +++ b/src/arm.cpp @@ -670,7 +670,9 @@ padding(MyBlock* b, unsigned offset) unsigned total = 0; for (PoolEvent* e = b->poolEventHead; e; e = e->next) { if (e->offset <= offset) { - total += BytesPerWord; + if (b->next) { + total += BytesPerWord; + } for (PoolOffset* o = e->poolOffsetHead; o; o = o->next) { total += BytesPerWord; } @@ -2333,9 +2335,12 @@ class MyAssembler: public Assembler { } } - virtual void writeTo(uint8_t* dst) { + virtual void setDestination(uint8_t* dst) { c.result = dst; - + } + + virtual void write() { + uint8_t* dst = c.result; unsigned dstOffset = 0; for (MyBlock* b = c.firstBlock; b; b = b->next) { if (DebugPool) { @@ -2356,10 +2361,12 @@ class MyAssembler: public Assembler { o, o->offset, b); } - poolSize += BytesPerWord; - unsigned entry = dstOffset + poolSize; + if (b->next) { + entry += BytesPerWord; + } + o->entry->address = dst + entry; unsigned instruction = o->block->start @@ -2370,9 +2377,13 @@ class MyAssembler: public Assembler { int32_t* p = reinterpret_cast(dst + instruction); *p = (v & PoolOffsetMask) | ((~PoolOffsetMask) & *p); + + poolSize += BytesPerWord; } - write4(dst + dstOffset, ::b((poolSize + BytesPerWord - 8) >> 2)); + if (b->next) { + write4(dst + dstOffset, ::b((poolSize + BytesPerWord - 8) >> 2)); + } dstOffset += poolSize + BytesPerWord; } diff --git a/src/assembler.h b/src/assembler.h index 15d08c130a..09a0e3cc50 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -428,7 +428,9 @@ class Assembler { unsigned bSize, OperandType bType, Operand* bOperand, unsigned cSize, OperandType cType, Operand* cOperand) = 0; - virtual void writeTo(uint8_t* dst) = 0; + virtual void setDestination(uint8_t* dst) = 0; + + virtual void write() = 0; virtual Promise* offset(bool forTrace = false) = 0; diff --git a/src/compile.cpp b/src/compile.cpp index e1728451eb..c9b00f1d9b 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -374,7 +374,7 @@ methodForIp(MyThread* t, void* ip) // we must use a version of the method tree at least as recent as the // compiled form of the method containing the specified address (see - // compile(MyThread*, Allocator*, BootContext*, object)): + // compile(MyThread*, FixedAllocator*, BootContext*, object)): loadMemoryBarrier(); return treeQuery(t, root(t, MethodTree), reinterpret_cast(ip), @@ -2229,7 +2229,7 @@ FixedAllocator* codeAllocator(MyThread* t); void -compile(MyThread* t, Allocator* allocator, BootContext* bootContext, +compile(MyThread* t, FixedAllocator* allocator, BootContext* bootContext, object method); int64_t @@ -5583,7 +5583,8 @@ finish(MyThread* t, Allocator* allocator, Assembler* a, const char* name, { uint8_t* start = static_cast(allocator->allocate(pad(length))); - a->writeTo(start); + a->setDestination(start); + a->write(); logCompile(t, start, length, 0, name, 0); @@ -5851,7 +5852,7 @@ makeSimpleFrameMapTable(MyThread* t, Context* context, uint8_t* start, } void -finish(MyThread* t, Allocator* allocator, Context* context) +finish(MyThread* t, FixedAllocator* allocator, Context* context) { Compiler* c = context->compiler; @@ -5885,9 +5886,13 @@ finish(MyThread* t, Allocator* allocator, Context* context) // parallelism (the downside being that it may end up being a waste // of cycles if another thread compiles the same method in parallel, // which might be mitigated by fine-grained, per-method locking): - unsigned codeSize = c->compile - (context->leaf ? 0 : stackOverflowThunk(t), - difference(&(t->stackLimit), t)); + c->compile(context->leaf ? 0 : stackOverflowThunk(t), + difference(&(t->stackLimit), t)); + + // we must acquire the class lock here at the latest + + unsigned codeSize = c->resolve + (allocator->base + allocator->offset + BytesPerWord); unsigned total = pad(codeSize) + pad(c->poolSize()) + BytesPerWord; @@ -5921,7 +5926,7 @@ finish(MyThread* t, Allocator* allocator, Context* context) } } - c->writeTo(start); + c->write(); BootContext* bc = context->bootContext; if (bc) { @@ -8646,7 +8651,8 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) uint8_t* start = p->thunks.table.start; #define THUNK(s) \ - tableContext.context.assembler->writeTo(start); \ + tableContext.context.assembler->setDestination(start); \ + tableContext.context.assembler->write(); \ start += p->thunks.table.length; \ { void* call; \ tableContext.promise.listener->resolve \ @@ -8737,7 +8743,8 @@ compileVirtualThunk(MyThread* t, unsigned index, unsigned* size) uint8_t* start = static_cast(codeAllocator(t)->allocate(*size)); - a->writeTo(start); + a->setDestination(start); + a->write(); logCompile(t, start, *size, 0, "virtualThunk", 0); @@ -8774,7 +8781,7 @@ virtualThunk(MyThread* t, unsigned index) } void -compile(MyThread* t, Allocator* allocator, BootContext* bootContext, +compile(MyThread* t, FixedAllocator* allocator, BootContext* bootContext, object method) { PROTECT(t, method); diff --git a/src/compiler.cpp b/src/compiler.cpp index 2d809b1c5e..01522a8ef7 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -386,6 +386,7 @@ class Context { lastEvent(0), forkState(0), subroutine(0), + firstBlock(0), logicalIp(-1), constantCount(0), logicalCodeLength(0), @@ -432,6 +433,7 @@ class Context { Event* lastEvent; ForkState* forkState; MySubroutine* subroutine; + Block* firstBlock; int logicalIp; unsigned constantCount; unsigned logicalCodeLength; @@ -5706,7 +5708,7 @@ block(Context* c, Event* head) return new (c->zone->allocate(sizeof(Block))) Block(head); } -unsigned +void compile(Context* c, uintptr_t stackOverflowHandler, unsigned stackLimitOffset) { if (c->logicalCode[c->logicalIp]->lastEvent == 0) { @@ -5836,19 +5838,7 @@ compile(Context* c, uintptr_t stackOverflowHandler, unsigned stackLimitOffset) } } - block = firstBlock; - while (block->nextBlock or block->nextInstruction) { - Block* next = block->nextBlock - ? block->nextBlock - : block->nextInstruction->firstEvent->block; - - next->start = block->assemblerBlock->resolve - (block->start, next->assemblerBlock); - - block = next; - } - - return block->assemblerBlock->resolve(block->start, 0) + a->footerSize(); + c->firstBlock = firstBlock; } unsigned @@ -6883,25 +6873,43 @@ class MyCompiler: public Compiler { appendBarrier(&c, StoreLoadBarrier); } - virtual unsigned compile(uintptr_t stackOverflowHandler, - unsigned stackLimitOffset) + virtual void compile(uintptr_t stackOverflowHandler, + unsigned stackLimitOffset) { - return c.machineCodeSize = local::compile - (&c, stackOverflowHandler, stackLimitOffset); + local::compile(&c, stackOverflowHandler, stackLimitOffset); + } + + virtual unsigned resolve(uint8_t* dst) { + c.machineCode = dst; + c.assembler->setDestination(dst); + + Block* block = c.firstBlock; + while (block->nextBlock or block->nextInstruction) { + Block* next = block->nextBlock + ? block->nextBlock + : block->nextInstruction->firstEvent->block; + + next->start = block->assemblerBlock->resolve + (block->start, next->assemblerBlock); + + block = next; + } + + return c.machineCodeSize = block->assemblerBlock->resolve + (block->start, 0) + c.assembler->footerSize(); } virtual unsigned poolSize() { return c.constantCount * BytesPerWord; } - virtual void writeTo(uint8_t* dst) { - c.machineCode = dst; - c.assembler->writeTo(dst); + virtual void write() { + c.assembler->write(); int i = 0; for (ConstantPoolNode* n = c.firstConstant; n; n = n->next) { intptr_t* target = reinterpret_cast - (dst + pad(c.machineCodeSize) + i); + (c.machineCode + pad(c.machineCodeSize) + i); if (n->promise->resolved()) { *target = n->promise->value(); diff --git a/src/compiler.h b/src/compiler.h index 282941b722..3349c5e713 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -188,10 +188,11 @@ class Compiler { virtual void storeStoreBarrier() = 0; virtual void storeLoadBarrier() = 0; - virtual unsigned compile(uintptr_t stackOverflowHandler, - unsigned stackLimitOffset) = 0; + virtual void compile(uintptr_t stackOverflowHandler, + unsigned stackLimitOffset) = 0; + virtual unsigned resolve(uint8_t* dst) = 0; virtual unsigned poolSize() = 0; - virtual void writeTo(uint8_t* dst) = 0; + virtual void write() = 0; virtual void dispose() = 0; }; diff --git a/src/powerpc.cpp b/src/powerpc.cpp index 3644520647..8a246e0aa1 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -178,20 +178,44 @@ const unsigned StackAlignmentInWords = StackAlignmentInBytes / BytesPerWord; const int StackRegister = 1; const int ThreadRegister = 13; +const bool DebugJumps = false; + +class Context; +class MyBlock; +class JumpOffset; +class JumpEvent; + +void +resolve(MyBlock*); + +unsigned +padding(MyBlock*, unsigned); + class MyBlock: public Assembler::Block { public: - MyBlock(unsigned offset): - next(0), offset(offset), start(~0), size(0) + MyBlock(Context* context, unsigned offset): + context(context), next(0), jumpOffsetHead(0), jumpOffsetTail(0), + lastJumpOffsetTail(0), jumpEventHead(0), jumpEventTail(0), + lastEventOffset(0), offset(offset), start(~0), size(0) { } virtual unsigned resolve(unsigned start, Assembler::Block* next) { this->start = start; this->next = static_cast(next); - return start + size; + ::resolve(this); + + return start + size + padding(this, size); } + Context* context; MyBlock* next; + JumpOffset* jumpOffsetHead; + JumpOffset* jumpOffsetTail; + JumpOffset* lastJumpOffsetTail; + JumpEvent* jumpEventHead; + JumpEvent* jumpEventTail; + unsigned lastEventOffset; unsigned offset; unsigned start; unsigned size; @@ -199,15 +223,14 @@ class MyBlock: public Assembler::Block { class Task; class ConstantPoolEntry; -class JumpPromise; class Context { public: Context(System* s, Allocator* a, Zone* zone): s(s), zone(zone), client(0), code(s, a, 1024), tasks(0), result(0), - firstBlock(new (zone->allocate(sizeof(MyBlock))) MyBlock(0)), - lastBlock(firstBlock), constantPool(0), jumps(0), constantPoolCount(0), - jumpCount(0) + firstBlock(new (zone->allocate(sizeof(MyBlock))) MyBlock(this, 0)), + lastBlock(firstBlock), jumpOffsetHead(0), jumpOffsetTail(0), + constantPool(0), constantPoolCount(0) { } System* s; @@ -218,10 +241,10 @@ class Context { uint8_t* result; MyBlock* firstBlock; MyBlock* lastBlock; + JumpOffset* jumpOffsetHead; + JumpOffset* jumpOffsetTail; ConstantPoolEntry* constantPool; - JumpPromise* jumps; unsigned constantPoolCount; - unsigned jumpCount; }; class Task { @@ -324,38 +347,6 @@ offset(Context* c) Offset(c, c->lastBlock, c->code.length()); } -class JumpPromise: public Promise { - public: - JumpPromise(Context* c, uintptr_t target): - c(c), target(target), next(c->jumps), index(c->jumpCount++) - { - c->jumps = this; - } - - virtual bool resolved() { - return c->result != 0; - } - - virtual int64_t value() { - assert(c, resolved()); - - return reinterpret_cast - (c->result + c->code.length() + (index * BytesPerWord)); - } - - Context* c; - uintptr_t target; - JumpPromise* next; - unsigned index; -}; - -Promise* -jump(Context* c, uintptr_t target) -{ - return new (c->zone->allocate(sizeof(JumpPromise))) - JumpPromise(c, target); -} - bool bounded(int right, int left, int32_t v) { @@ -363,13 +354,21 @@ bounded(int right, int left, int32_t v) } void* -updateOffset(System* s, uint8_t* instruction, bool conditional, int64_t value) +updateOffset(System* s, uint8_t* instruction, bool conditional, int64_t value, + void* jumpAddress) { int32_t v = reinterpret_cast(value) - instruction; int32_t mask; if (conditional) { - expect(s, bounded(2, 16, v)); + if (not bounded(2, 16, v)) { + *static_cast(jumpAddress) = isa::b(0); + updateOffset(s, static_cast(jumpAddress), false, value, 0); + + v = static_cast(jumpAddress) - instruction; + + expect(s, bounded(2, 16, v)); + } mask = 0xFFFC; } else { expect(s, bounded(2, 6, v)); @@ -384,20 +383,23 @@ updateOffset(System* s, uint8_t* instruction, bool conditional, int64_t value) class OffsetListener: public Promise::Listener { public: - OffsetListener(System* s, uint8_t* instruction, bool conditional): + OffsetListener(System* s, uint8_t* instruction, bool conditional, + void* jumpAddress): s(s), instruction(instruction), + jumpAddress(jumpAddress), conditional(conditional) { } virtual bool resolve(int64_t value, void** location) { - void* p = updateOffset(s, instruction, conditional, value); + void* p = updateOffset(s, instruction, conditional, value, jumpAddress); if (location) *location = p; return false; } System* s; uint8_t* instruction; + void* jumpAddress; bool conditional; }; @@ -408,6 +410,7 @@ class OffsetTask: public Task { Task(next), promise(promise), instructionOffset(instructionOffset), + jumpAddress(0), conditional(conditional) { } @@ -415,25 +418,181 @@ class OffsetTask: public Task { if (promise->resolved()) { updateOffset (c->s, c->result + instructionOffset->value(), conditional, - promise->value()); + promise->value(), jumpAddress); } else { new (promise->listen(sizeof(OffsetListener))) OffsetListener(c->s, c->result + instructionOffset->value(), - conditional); + conditional, jumpAddress); } } Promise* promise; Promise* instructionOffset; + void* jumpAddress; bool conditional; }; +class JumpOffset { + public: + JumpOffset(MyBlock* block, OffsetTask* task, unsigned offset): + block(block), task(task), next(0), offset(offset) + { } + + MyBlock* block; + OffsetTask* task; + JumpOffset* next; + unsigned offset; +}; + +class JumpEvent { + public: + JumpEvent(JumpOffset* jumpOffsetHead, JumpOffset* jumpOffsetTail, + unsigned offset): + jumpOffsetHead(jumpOffsetHead), jumpOffsetTail(jumpOffsetTail), next(0), + offset(offset) + { } + + JumpOffset* jumpOffsetHead; + JumpOffset* jumpOffsetTail; + JumpEvent* next; + unsigned offset; +}; + void appendOffsetTask(Context* c, Promise* promise, Promise* instructionOffset, bool conditional) { - c->tasks = new (c->zone->allocate(sizeof(OffsetTask))) OffsetTask + OffsetTask* task = new (c->zone->allocate(sizeof(OffsetTask))) OffsetTask (c->tasks, promise, instructionOffset, conditional); + + c->tasks = task; + + if (conditional) { + JumpOffset* offset = new (c->zone->allocate(sizeof(JumpOffset))) JumpOffset + (c->lastBlock, task, c->code.length() - c->lastBlock->offset); + + if (c->lastBlock->jumpOffsetTail) { + c->lastBlock->jumpOffsetTail->next = offset; + } else { + c->lastBlock->jumpOffsetHead = offset; + } + c->lastBlock->jumpOffsetTail = offset; + } +} + +void +appendJumpEvent(Context* c, MyBlock* b, unsigned offset, JumpOffset* head, + JumpOffset* tail) +{ + JumpEvent* e = new (c->zone->allocate(sizeof(JumpEvent))) JumpEvent + (head, tail, offset); + + if (b->jumpEventTail) { + b->jumpEventTail->next = e; + } else { + b->jumpEventHead = e; + } + b->jumpEventTail = e; +} + +unsigned +padding(MyBlock* b, unsigned offset) +{ + unsigned total = 0; + for (JumpEvent** e = &(b->jumpEventHead); *e;) { + if ((*e)->offset <= offset) { + for (JumpOffset** o = &((*e)->jumpOffsetHead); *o;) { + if ((*o)->task->promise->resolved() + and (*o)->task->instructionOffset->resolved()) + { + int32_t v = reinterpret_cast((*o)->task->promise->value()) + - (b->context->result + (*o)->task->instructionOffset->value()); + + if (bounded(2, 16, v)) { + // this conditional jump needs no indirection -- a direct + // jump will suffice + *o = (*o)->next; + continue; + } + } + + total += BytesPerWord; + o = &((*o)->next); + } + + if ((*e)->jumpOffsetHead == 0) { + *e = (*e)->next; + } else { + if (b->next) { + total += BytesPerWord; + } + e = &((*e)->next); + } + } else { + break; + } + } + + return total; +} + +void +resolve(MyBlock* b) +{ + Context* c = b->context; + + if (b->jumpOffsetHead) { + if (c->jumpOffsetTail) { + c->jumpOffsetTail->next = b->jumpOffsetHead; + } else { + c->jumpOffsetHead = b->jumpOffsetHead; + } + c->jumpOffsetTail = b->jumpOffsetTail; + } + + if (c->jumpOffsetHead) { + bool append; + if (b->next == 0 or b->next->jumpEventHead) { + append = true; + } else { + int32_t v = (b->start + b->size + b->next->size + BytesPerWord) + - (c->jumpOffsetHead->offset + c->jumpOffsetHead->block->start); + + append = not bounded(2, 16, v); + + if (DebugJumps) { + fprintf(stderr, + "current %p %d %d next %p %d %d\n", + b, b->start, b->size, b->next, b->start + b->size, + b->next->size); + fprintf(stderr, + "offset %p %d is of distance %d to next block; append? %d\n", + c->jumpOffsetHead, c->jumpOffsetHead->offset, v, append); + } + } + + if (append) { +#ifndef NDEBUG + int32_t v = (b->start + b->size) + - (c->jumpOffsetHead->offset + c->jumpOffsetHead->block->start); + + expect(c, bounded(2, 16, v)); +#endif // not NDEBUG + + appendJumpEvent(c, b, b->size, c->jumpOffsetHead, c->jumpOffsetTail); + + if (DebugJumps) { + for (JumpOffset* o = c->jumpOffsetHead; o; o = o->next) { + fprintf(stderr, + "include %p %d in jump event %p at offset %d in block %p\n", + o, o->offset, b->jumpEventTail, b->size, b); + } + } + + c->jumpOffsetHead = 0; + c->jumpOffsetTail = 0; + } + } } inline unsigned @@ -491,6 +650,11 @@ inline int newTemp(Context* con) { return con->client->acquireTemporary(); } inline void freeTemp(Context* con, int r) { con->client->releaseTemporary(r); } inline int64_t getValue(Assembler::Constant* c) { return c->value->value(); } +inline void +write4(uint8_t* dst, uint32_t v) +{ + memcpy(dst, &v, 4); +} void shiftLeftR(Context* con, unsigned size, Assembler::Register* a, Assembler::Register* b, Assembler::Register* t) { @@ -1533,7 +1697,7 @@ branchLong(Context* c, TernaryOperation op, Assembler::Operand* al, if (next) { updateOffset (c->s, c->code.data + next, true, reinterpret_cast - (c->code.data + c->code.length())); + (c->code.data + c->code.length()), 0); } } @@ -1987,7 +2151,7 @@ class MyArchitecture: public Assembler::Architecture { case AlignedCall: case AlignedJump: { updateOffset(c.s, static_cast(returnAddress) - 4, false, - reinterpret_cast(newTarget)); + reinterpret_cast(newTarget), 0); } break; case LongCall: @@ -2260,7 +2424,9 @@ class MyAssembler: public Assembler { { Register stack(StackRegister); Memory stackLimit(ThreadRegister, stackLimitOffsetFromThread); - Constant handlerConstant(jump(&c, handler)); + Constant handlerConstant + (new (c.zone->allocate(sizeof(ResolvedPromise))) + ResolvedPromise(handler)); branchRM(&c, JumpIfGreaterOrEqual, BytesPerWord, &stack, &stackLimit, &handlerConstant); } @@ -2482,22 +2648,62 @@ class MyAssembler: public Assembler { } } - virtual void writeTo(uint8_t* dst) { + virtual void setDestination(uint8_t* dst) { c.result = dst; + } + virtual void write() { + uint8_t* dst = c.result; + unsigned dstOffset = 0; for (MyBlock* b = c.firstBlock; b; b = b->next) { - memcpy(dst + b->start, c.code.data + b->offset, b->size); - } + if (DebugJumps) { + fprintf(stderr, "write block %p\n", b); + } - for (JumpPromise* j = c.jumps; j; j = j->next) { - uint8_t* instruction - = dst + c.code.length() + (c.jumpCount - j->index - 1); - int32_t op = ::b(0); - memcpy(instruction, &op, BytesPerWord); - updateOffset(c.s, instruction, false, j->target); + unsigned blockOffset = 0; + for (JumpEvent* e = b->jumpEventHead; e; e = e->next) { + unsigned size = e->offset - blockOffset; + memcpy(dst + dstOffset, c.code.data + b->offset + blockOffset, size); + blockOffset = e->offset; + dstOffset += size; + + unsigned jumpTableSize = 0; + for (JumpOffset* o = e->jumpOffsetHead; o; o = o->next) { + if (DebugJumps) { + fprintf(stderr, "visit offset %p %d in block %p\n", + o, o->offset, b); + } + + uint8_t* address = dst + dstOffset + jumpTableSize; + + if (b->next) { + address += BytesPerWord; + } + + o->task->jumpAddress = address; + + jumpTableSize += BytesPerWord; + } + + assert(&c, jumpTableSize); + + if (b->next) { + write4(dst + dstOffset, ::b(jumpTableSize + BytesPerWord)); + } + + dstOffset += jumpTableSize + BytesPerWord; + } + + unsigned size = b->size - blockOffset; + + memcpy(dst + dstOffset, + c.code.data + b->offset + blockOffset, + size); + + dstOffset += size; } - unsigned index = c.code.length() + (c.jumpCount * BytesPerWord); + unsigned index = c.code.length(); assert(&c, index % BytesPerWord == 0); for (ConstantPoolEntry* e = c.constantPool; e; e = e->next) { e->address = dst + index; @@ -2523,7 +2729,7 @@ class MyAssembler: public Assembler { b->size = c.code.length() - b->offset; if (startNew) { c.lastBlock = new (c.zone->allocate(sizeof(MyBlock))) - MyBlock(c.code.length()); + MyBlock(&c, c.code.length()); } else { c.lastBlock = 0; } @@ -2531,7 +2737,37 @@ class MyAssembler: public Assembler { } virtual void endEvent() { - // ignore + MyBlock* b = c.lastBlock; + unsigned thisEventOffset = c.code.length() - b->offset; + if (b->jumpOffsetHead) { + int32_t v = (thisEventOffset + BytesPerWord) + - b->jumpOffsetHead->offset; + + if (v > 0 and not bounded(2, 16, v)) { + appendJumpEvent + (&c, b, b->lastEventOffset, b->jumpOffsetHead, + b->lastJumpOffsetTail); + + if (DebugJumps) { + for (JumpOffset* o = b->jumpOffsetHead; + o != b->lastJumpOffsetTail->next; o = o->next) + { + fprintf(stderr, + "in endEvent, include %p %d in jump event %p " + "at offset %d in block %p\n", + o, o->offset, b->jumpEventTail, b->lastEventOffset, b); + } + } + + b->jumpOffsetHead = b->lastJumpOffsetTail->next; + b->lastJumpOffsetTail->next = 0; + if (b->jumpOffsetHead == 0) { + b->jumpOffsetTail = 0; + } + } + } + b->lastEventOffset = thisEventOffset; + b->lastJumpOffsetTail = b->jumpOffsetTail; } virtual unsigned length() { @@ -2539,7 +2775,7 @@ class MyAssembler: public Assembler { } virtual unsigned footerSize() { - return (c.jumpCount + c.constantPoolCount) * BytesPerWord; + return c.constantPoolCount * BytesPerWord; } virtual void dispose() { diff --git a/src/x86.cpp b/src/x86.cpp index 956d99b1c9..5c250f449a 100644 --- a/src/x86.cpp +++ b/src/x86.cpp @@ -3616,9 +3616,12 @@ class MyAssembler: public Assembler { } } - virtual void writeTo(uint8_t* dst) { + virtual void setDestination(uint8_t* dst) { c.result = dst; - + } + + virtual void write() { + uint8_t* dst = c.result; for (MyBlock* b = c.firstBlock; b; b = b->next) { unsigned index = 0; unsigned padding = 0; From 25f1a9f1e88bf7cf9fff8d9c3847603ec0dc7c03 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 28 Feb 2011 10:14:01 -0700 Subject: [PATCH 25/32] fix Thread::exit/Thread::dispose race condition There was a race between these two functions such that one thread A would run dispose on thread B just before thread B finishes exit, with the result that Thread::lock and/or Thread::systemThread would be disposed twice, resulting in a crash. --- src/machine.cpp | 23 ++++++++++++++--------- src/machine.h | 1 + 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/machine.cpp b/src/machine.cpp index c174f4aafd..a561006ca7 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -2413,20 +2413,23 @@ Thread::exit() } else { threadPeer(this, javaThread) = 0; + System::Monitor* myLock = lock; + System::Thread* mySystemThread = systemThread; + { ACQUIRE_RAW(this, m->stateLock); while (flags & SystemFlag) { m->stateLock->wait(systemThread, 0); } + + atomicOr(&flags, Thread::DisposeFlag); enter(this, Thread::ZombieState); } - lock->dispose(); - lock = 0; + myLock->dispose(); - systemThread->dispose(); - systemThread = 0; + mySystemThread->dispose(); } } } @@ -2434,12 +2437,14 @@ Thread::exit() void Thread::dispose() { - if (lock) { - lock->dispose(); - } + if ((flags & Thread::DisposeFlag) == 0) { + if (lock) { + lock->dispose(); + } - if (systemThread) { - systemThread->dispose(); + if (systemThread) { + systemThread->dispose(); + } } m->heap->free(defaultHeap, ThreadHeapSizeInBytes); diff --git a/src/machine.h b/src/machine.h index c342b9f695..6c3633000f 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1369,6 +1369,7 @@ class Thread { static const unsigned StressFlag = 1 << 4; static const unsigned ActiveFlag = 1 << 5; static const unsigned SystemFlag = 1 << 6; + static const unsigned DisposeFlag = 1 << 7; class Protector { public: From 7ad59731c0e823466edd36ade5d59e18cc86120d Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 28 Feb 2011 16:48:58 -0700 Subject: [PATCH 26/32] reserve register 2 for system use on Linux/PowerPC The SYSV ABI specifies that it be reserved. In practice, it is used for thread-local storage. --- src/powerpc.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/powerpc.cpp b/src/powerpc.cpp index 8a246e0aa1..e75fcc3791 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -2096,6 +2096,10 @@ class MyArchitecture: public Assembler::Architecture { case 0: // r0 has special meaning in addi and other instructions case StackRegister: case ThreadRegister: +#ifndef __APPLE__ + // r2 is reserved for system uses on SYSV + case 2: +#endif return true; default: From a0962d7ab21dc784772ec0ca589cbe91ed802c62 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Mon, 28 Feb 2011 16:50:17 -0700 Subject: [PATCH 27/32] look for __powerpc__ as well as __POWERPC__ in jni-util.h The former is used on GNU/Linux. --- classpath/jni-util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classpath/jni-util.h b/classpath/jni-util.h index 4270976131..d373aaf268 100644 --- a/classpath/jni-util.h +++ b/classpath/jni-util.h @@ -64,7 +64,7 @@ typedef unsigned __int64 uint64_t; # define ARCH_x86_32 # elif defined __x86_64__ # define ARCH_x86_64 -# elif defined __POWERPC__ +# elif (defined __POWERPC__) || (defined __powerpc__) # define ARCH_powerpc # elif defined __arm__ # define ARCH_arm From 8f519531d4433b56b57a899038a408cfdc9ec569 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 1 Mar 2011 10:59:00 -0700 Subject: [PATCH 28/32] UseFramePointer should always be true on PowerPC The Apple and SYSV ABIs specify that the stack/frame pointer is always saved at the tip of the stack. --- src/assembler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/assembler.h b/src/assembler.h index 09a0e3cc50..f57636cb14 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -22,7 +22,7 @@ const bool TailCalls = true; const bool TailCalls = false; #endif -#ifdef AVIAN_USE_FRAME_POINTER +#if (defined AVIAN_USE_FRAME_POINTER) || (defined ARCH_powerpc) const bool UseFramePointer = true; #else const bool UseFramePointer = false; From 30feba8b56603ef1211e6e70b67a02786a182645 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 1 Mar 2011 11:01:13 -0700 Subject: [PATCH 29/32] fix PowerPC tails=true stack undwinding --- src/powerpc.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/powerpc.cpp b/src/powerpc.cpp index e75fcc3791..e7e247dacb 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -1939,11 +1939,11 @@ nextFrame(ArchitectureContext* c UNUSED, int32_t* start, unsigned size, // check for post-non-tail-call stack adjustment of the form "lwzx // r0,0(r1); stwu r0,offset(r1)": if (instruction < start + (size / BytesPerWord) - 1 - and (static_cast(instruction[1]) >> 16) == 0x9421) + and (static_cast(instruction[1]) >> 16) == 0x9401) { - offset += static_cast(instruction[1]); - } else if ((static_cast(*instruction) >> 16) == 0x9421) { - offset += static_cast(*instruction); + offset += static_cast(instruction[1]) / BytesPerWord; + } else if ((static_cast(*instruction) >> 16) == 0x9401) { + offset += static_cast(*instruction) / BytesPerWord; } // todo: check for and handle tail calls From bb4be4de7eeb9ffd69fbccb001ca26b3d9f4518b Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 1 Mar 2011 11:24:44 -0700 Subject: [PATCH 30/32] fix Linux/PowerPC continuations=true build --- src/compile-powerpc.S | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/compile-powerpc.S b/src/compile-powerpc.S index e97556e483..56fc5222da 100644 --- a/src/compile-powerpc.S +++ b/src/compile-powerpc.S @@ -157,7 +157,11 @@ LOCAL(vmInvoke_continuationTest): LOCAL(vmInvoke_getPC): mflr r10 +#ifdef __APPLE__ la r10,lo16(GLOBAL(vmInvoke_returnAddress)-LOCAL(vmInvoke_getPC))(r10) +#else + lwz r10,LOCAL(vmInvoke_returnAddress_address)-LOCAL(vmInvoke_getPC)(r10) +#endif stwx r10,r1,r7 lwz r7,CONTINUATION_FRAME_POINTER_OFFSET(r5) @@ -228,6 +232,9 @@ LOCAL(vmInvoke_return): // return blr + +LOCAL(vmInvoke_returnAddress_address): + .long GLOBAL(vmInvoke_returnAddress) .globl GLOBAL(vmJumpAndInvoke) GLOBAL(vmJumpAndInvoke): @@ -276,7 +283,11 @@ LOCAL(vmJumpAndInvoke_argumentTest): LOCAL(vmJumpAndInvoke_getPC): mflr r10 +#ifdef __APPLE__ la r10,lo16(GLOBAL(vmInvoke_returnAddress)-LOCAL(vmJumpAndInvoke_getPC))(r10) +#else + lwz r10,LOCAL(vmInvoke_returnAddress_address)-LOCAL(vmJumpAndInvoke_getPC)(r10) +#endif mtlr r10 mtctr r4 From 6d3975adb755a7c1cccdb3934d5356ccea2c4bad Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 1 Mar 2011 12:06:35 -0700 Subject: [PATCH 31/32] fix OS X PowerPC continuations=true build regression --- src/compile-powerpc.S | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/compile-powerpc.S b/src/compile-powerpc.S index 56fc5222da..a074a5f186 100644 --- a/src/compile-powerpc.S +++ b/src/compile-powerpc.S @@ -232,9 +232,11 @@ LOCAL(vmInvoke_return): // return blr - + +#ifndef __APPLE__ LOCAL(vmInvoke_returnAddress_address): .long GLOBAL(vmInvoke_returnAddress) +#endif .globl GLOBAL(vmJumpAndInvoke) GLOBAL(vmJumpAndInvoke): From 7a91074a3203c1abff87501ab6b322721f8a6736 Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Tue, 1 Mar 2011 12:20:23 -0700 Subject: [PATCH 32/32] fix OS X cross-arch build regression --- makefile | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/makefile b/makefile index bca5d1719a..35db15f9f9 100644 --- a/makefile +++ b/makefile @@ -202,13 +202,15 @@ ifeq ($(arch),powerpc) asm = powerpc pointer-size = 4 - ifneq ($(arch),$(build-arch)) - converter-cflags += -DOPPOSITE_ENDIAN - cxx = powerpc-linux-gnu-g++ - cc = powerpc-linux-gnu-gcc - ar = powerpc-linux-gnu-ar - ranlib = powerpc-linux-gnu-ranlib - strip = powerpc-linux-gnu-strip + ifneq ($(platform),darwin) + ifneq ($(arch),$(build-arch)) + converter-cflags += -DOPPOSITE_ENDIAN + cxx = powerpc-linux-gnu-g++ + cc = powerpc-linux-gnu-gcc + ar = powerpc-linux-gnu-ar + ranlib = powerpc-linux-gnu-ranlib + strip = powerpc-linux-gnu-strip + endif endif endif ifeq ($(arch),arm)