diff --git a/src/bootimage.cpp b/src/bootimage.cpp index 7a9d82e7a3..bc9b847cd8 100644 --- a/src/bootimage.cpp +++ b/src/bootimage.cpp @@ -87,7 +87,7 @@ makeCodeImage(Thread* t, Zone* zone, BootImage* image, uint8_t* code, object method = tripleFirst(t, calls); uintptr_t address; if (methodFlags(t, method) & ACC_NATIVE) { - address = reinterpret_cast(code + image->nativeThunk); + address = reinterpret_cast(code + image->thunks.native.start); } else { address = methodCompiled(t, method); } @@ -389,7 +389,7 @@ main(int ac, const char** av) Processor* p = makeProcessor(s, h, false); BootImage image; - const unsigned CodeCapacity = 32 * 1024 * 1024; + const unsigned CodeCapacity = 16 * 1024 * 1024; uint8_t* code = static_cast(h->allocate(CodeCapacity)); p->initialize(&image, code, CodeCapacity); diff --git a/src/bootimage.h b/src/bootimage.h index 4472ac28ae..b76a77b7fa 100644 --- a/src/bootimage.h +++ b/src/bootimage.h @@ -24,6 +24,30 @@ const unsigned BootHeapOffset = 1 << (BootShift + 1); class BootImage { public: + class Thunk { + public: + Thunk(): + start(0), frameSavedOffset(0), length(0) + { } + + Thunk(unsigned start, unsigned frameSavedOffset, unsigned length): + start(start), frameSavedOffset(frameSavedOffset), length(length) + { } + + unsigned start; + unsigned frameSavedOffset; + unsigned length; + }; + + class ThunkCollection { + public: + Thunk default_; + Thunk defaultVirtual; + Thunk native; + Thunk aioob; + Thunk table; + }; + static const unsigned Magic = 0x22377322; unsigned magic; @@ -43,13 +67,7 @@ class BootImage { uintptr_t codeBase; - unsigned defaultThunk; - unsigned defaultVirtualThunk; - unsigned nativeThunk; - unsigned aioobThunk; - - unsigned thunkTable; - unsigned thunkSize; + ThunkCollection thunks; unsigned compileMethodCall; unsigned compileVirtualMethodCall; diff --git a/src/compile-powerpc.S b/src/compile-powerpc.S index 8936899b53..b732f893ea 100644 --- a/src/compile-powerpc.S +++ b/src/compile-powerpc.S @@ -24,11 +24,12 @@ # define GLOBAL(x) x #endif -#define THREAD_CONTINUATION 112 +#define THREAD_STACK 2152 +#define THREAD_CONTINUATION 2156 #define THREAD_EXCEPTION 44 -#define THREAD_EXCEPTION_STACK_ADJUSTMENT 116 -#define THREAD_EXCEPTION_OFFSET 120 -#define THREAD_EXCEPTION_HANDLER 124 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2160 +#define THREAD_EXCEPTION_OFFSET 2164 +#define THREAD_EXCEPTION_HANDLER 2168 #define CONTINUATION_NEXT 4 #define CONTINUATION_ADDRESS 16 @@ -103,9 +104,21 @@ LOCAL(vmInvoke_argumentTest): mtctr r4 bctrl -LOCAL(vmInvoke_returnAddress): +.globl GLOBAL(vmInvoke_returnAddress) +GLOBAL(vmInvoke_returnAddress): // restore stack pointer lwz r1,0(r1) + + // clear MyThread::stack to avoid confusing another thread calling + // java.lang.Thread.getStackTrace on this one. See + // MyProcess::getStackTrace in compile.cpp for details on how we get + // a reliable stack trace from a thread that might be interrupted at + // any point in its execution. + li r5,0 + stw r5,THREAD_STACK(r13) + +.globl GLOBAL(vmInvoke_safeStack) +GLOBAL(vmInvoke_safeStack): #ifdef AVIAN_CONTINUATIONS // call the next continuation, if any @@ -138,7 +151,7 @@ LOCAL(vmInvoke_continuationTest): LOCAL(vmInvoke_getPC): mflr r10 - la r10,lo16(LOCAL(vmInvoke_returnAddress)-LOCAL(vmInvoke_getPC))(r10) + la r10,lo16(GLOBAL(vmInvoke_returnAddress)-LOCAL(vmInvoke_getPC))(r10) stwx r10,r1,r7 lwz r7,CONTINUATION_FRAME_POINTER_OFFSET(r5) @@ -271,7 +284,7 @@ LOCAL(vmJumpAndInvoke_argumentTest): LOCAL(vmJumpAndInvoke_getPC): mflr r10 - la r10,lo16(LOCAL(vmInvoke_returnAddress)-LOCAL(vmJumpAndInvoke_getPC))(r10) + la r10,lo16(GLOBAL(vmInvoke_returnAddress)-LOCAL(vmJumpAndInvoke_getPC))(r10) mtlr r10 mtctr r4 diff --git a/src/compile-x86.S b/src/compile-x86.S index e680190bbb..7dd9349f40 100644 --- a/src/compile-x86.S +++ b/src/compile-x86.S @@ -22,6 +22,8 @@ #ifdef __x86_64__ +#define THREAD_STACK 2216 + #if defined __MINGW32__ || defined __CYGWIN32__ #define CALLEE_SAVED_REGISTER_FOOTPRINT 64 @@ -79,6 +81,16 @@ GLOBAL(vmInvoke_returnAddress): // restore stack pointer movq %rbp,%rsp + // clear MyThread::stack to avoid confusing another thread calling + // java.lang.Thread.getStackTrace on this one. See + // MyProcess::getStackTrace in compile.cpp for details on how we get + // a reliable stack trace from a thread that might be interrupted at + // any point in its execution. + movq $0,THREAD_STACK(%rbx) + +.globl GLOBAL(vmInvoke_safeStack) +GLOBAL(vmInvoke_safeStack): + #ifdef AVIAN_CONTINUATIONS # include "continuations-x86.S" #endif // AVIAN_CONTINUATIONS @@ -207,6 +219,16 @@ LOCAL(vmInvoke_argumentTest): GLOBAL(vmInvoke_returnAddress): // restore stack pointer movq %rbp,%rsp + + // clear MyThread::stack to avoid confusing another thread calling + // java.lang.Thread.getStackTrace on this one. See + // MyProcess::getStackTrace in compile.cpp for details on how we get + // a reliable stack trace from a thread that might be interrupted at + // any point in its execution. + movq $0,THREAD_STACK(%rbx) + +.globl GLOBAL(vmInvoke_safeStack) +GLOBAL(vmInvoke_safeStack): #ifdef AVIAN_CONTINUATIONS # include "continuations-x86.S" @@ -283,6 +305,8 @@ LOCAL(vmJumpAndInvoke_argumentTest): #elif defined __i386__ +#define THREAD_STACK 2144 + #define CALLEE_SAVED_REGISTER_FOOTPRINT 16 .globl GLOBAL(vmInvoke) @@ -329,13 +353,23 @@ LOCAL(vmInvoke_argumentTest): // call function call *12(%ebp) -.globl vmInvoke_returnAddress -vmInvoke_returnAddress: +.globl GLOBAL(vmInvoke_returnAddress) +GLOBAL(vmInvoke_returnAddress): // restore stack pointer, preserving the area containing saved // registers movl %ebp,%ecx subl $CALLEE_SAVED_REGISTER_FOOTPRINT,%ecx movl %ecx,%esp + + // clear MyThread::stack to avoid confusing another thread calling + // java.lang.Thread.getStackTrace on this one. See + // MyProcess::getStackTrace in compile.cpp for details on how we get + // a reliable stack trace from a thread that might be interrupted at + // any point in its execution. + movl $0,THREAD_STACK(%ebx) + +.globl GLOBAL(vmInvoke_safeStack) +GLOBAL(vmInvoke_safeStack): #ifdef AVIAN_CONTINUATIONS # include "continuations-x86.S" @@ -397,15 +431,15 @@ GLOBAL(vmJumpAndInvoke): // set return address #if defined __MINGW32__ || defined __CYGWIN32__ - movl $vmInvoke_returnAddress,%esi + movl $GLOBAL(vmInvoke_returnAddress),%esi #else call LOCAL(getPC) # if defined __APPLE__ LOCAL(vmJumpAndInvoke_offset): - leal vmInvoke_returnAddress-LOCAL(vmJumpAndInvoke_offset)(%esi),%esi + leal GLOBAL(vmInvoke_returnAddress)-LOCAL(vmJumpAndInvoke_offset)(%esi),%esi # else addl $_GLOBAL_OFFSET_TABLE_,%esi - movl vmInvoke_returnAddress@GOT(%esi),%esi + movl GLOBAL(vmInvoke_returnAddress)@GOT(%esi),%esi # endif #endif movl %esi,(%ecx) diff --git a/src/compile.cpp b/src/compile.cpp index 89cac7125d..b84d2ae6e8 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -22,6 +22,12 @@ extern "C" uint64_t vmInvoke(void* thread, void* function, void* arguments, unsigned argumentFootprint, unsigned frameSize, unsigned returnType); +extern "C" void +vmInvoke_returnAddress(); + +extern "C" void +vmInvoke_safeStack(); + extern "C" void vmJumpAndInvoke(void* thread, void* function, void* base, void* stack, unsigned argumentFootprint, uintptr_t* arguments, @@ -55,6 +61,15 @@ const unsigned InitialZoneCapacityInBytes = 64 * 1024; const unsigned ExecutableAreaSizeInBytes = 16 * 1024 * 1024; +inline bool +isVmInvokeUnsafeStack(void* ip) +{ + return reinterpret_cast(ip) + >= reinterpret_cast(voidPointer(vmInvoke_returnAddress)) + and reinterpret_cast(ip) + < reinterpret_cast (voidPointer(vmInvoke_safeStack)); +} + class MyThread: public Thread { public: class CallTrace { @@ -69,17 +84,13 @@ class MyThread: public Thread { originalMethod(method), next(t->trace) { - t->trace = this; - t->base = 0; - t->stack = 0; - t->continuation = 0; + doTransition(t, 0, 0, 0, 0, this); } ~CallTrace() { - t->stack = stack; - t->base = base; - t->continuation = continuation; - t->trace = next; + assert(t, t->stack == 0); + + doTransition(t, 0, stack, base, continuation, next); } MyThread* t; @@ -92,6 +103,95 @@ class MyThread: public Thread { CallTrace* next; }; + class Context { + public: + class MyProtector: public Thread::Protector { + public: + MyProtector(MyThread* t, Context* context): + Protector(t), context(context) + { } + + virtual void visit(Heap::Visitor* v) { + v->visit(&(context->continuation)); + } + + Context* context; + }; + + Context(MyThread* t, void* ip, void* stack, void* base, + object continuation, CallTrace* trace): + ip(ip), + stack(stack), + base(base), + continuation(continuation), + trace(trace), + protector(t, this) + { } + + void* ip; + void* stack; + void* base; + object continuation; + CallTrace* trace; + MyProtector protector; + }; + + class TraceContext: public Context { + public: + TraceContext(MyThread* t, void* ip, void* stack, void* base, + object continuation, CallTrace* trace): + Context(t, ip, stack, base, continuation, trace), + t(t), + next(t->traceContext) + { + t->traceContext = this; + } + + TraceContext(MyThread* t): + Context(t, t->ip, t->stack, t->base, t->continuation, t->trace), + t(t), + next(t->traceContext) + { + t->traceContext = this; + } + + ~TraceContext() { + t->traceContext = next; + } + + MyThread* t; + TraceContext* next; + }; + + static void doTransition(MyThread* t, void* ip, void* stack, void* base, + object continuation, MyThread::CallTrace* trace) + { + // in this function, we "atomically" update the thread context + // fields in such a way to ensure that another thread may + // interrupt us at any time and still get a consistent, accurate + // stack trace. See MyProcess::getStackTrace for details. + + assert(t, t->transition == 0); + + Context c(t, ip, stack, base, continuation, trace); + + compileTimeMemoryBarrier(); + + t->transition = &c; + + compileTimeMemoryBarrier(); + + t->ip = ip; + t->base = base; + t->stack = stack; + t->continuation = continuation; + t->trace = trace; + + compileTimeMemoryBarrier(); + + t->transition = 0; + } + MyThread(Machine* m, object javaThread, MyThread* parent, bool useNativeFeatures): Thread(m, javaThread, parent), @@ -109,7 +209,9 @@ class MyThread: public Thread { reference(0), arch(parent ? parent->arch - : makeArchitecture(m->system, useNativeFeatures)) + : makeArchitecture(m->system, useNativeFeatures)), + transition(0), + traceContext(0) { arch->acquire(); } @@ -127,8 +229,17 @@ class MyThread: public Thread { CallTrace* trace; Reference* reference; Assembler::Architecture* arch; + Context* transition; + TraceContext* traceContext; }; +void +transition(MyThread* t, void* ip, void* stack, void* base, object continuation, + MyThread::CallTrace* trace) +{ + MyThread::doTransition(t, ip, stack, base, continuation, trace); +} + unsigned parameterOffset(MyThread* t, object method) { @@ -246,6 +357,7 @@ class MyStackWalker: public Processor::StackWalker { enum State { Start, Next, + Trace, Continuation, Method, NativeMethod, @@ -269,14 +381,23 @@ class MyStackWalker: public Processor::StackWalker { MyStackWalker(MyThread* t): t(t), state(Start), - ip_(t->ip), - base(t->base), - stack(t->stack), - trace(t->trace), method_(0), - continuation(t->continuation), protector(this) - { } + { + if (t->traceContext) { + ip_ = t->traceContext->ip; + base = t->traceContext->base; + stack = t->traceContext->stack; + trace = t->traceContext->trace; + continuation = t->traceContext->continuation; + } else { + ip_ = 0; + base = t->base; + stack = t->stack; + trace = t->trace; + continuation = t->continuation; + } + } MyStackWalker(MyStackWalker* w): t(w->t), @@ -325,24 +446,27 @@ class MyStackWalker: public Processor::StackWalker { } else if (continuation) { method_ = continuationMethod(t, continuation); state = Continuation; - } else if (trace) { - continuation = trace->continuation; - stack = trace->stack; - base = trace->base; - ip_ = t->arch->frameIp(stack); - trace = trace->next; - - if (trace and trace->nativeMethod) { - method_ = trace->nativeMethod; - state = NativeMethod; - } } else { - state = Finish; + state = Trace; } + } else { + state = Trace; + } + break; + + case Trace: { + if (trace) { + continuation = trace->continuation; + stack = trace->stack; + base = trace->base; + ip_ = t->arch->frameIp(stack); + trace = trace->next; + + state = Start; } else { state = Finish; } - break; + } break; case Continuation: case Method: @@ -1746,11 +1870,25 @@ releaseLock(MyThread* t, object method, void* stack) void findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, - void** targetStack) + void** targetStack, object* targetContinuation) { - void* ip = t->ip; - void* base = t->base; - void* stack = t->stack; + void* ip; + void* base; + void* stack; + object continuation; + + if (t->traceContext) { + ip = t->traceContext->ip; + base = t->traceContext->base; + stack = t->traceContext->stack; + continuation = t->traceContext->continuation; + } else { + ip = 0; + base = t->base; + stack = t->stack; + continuation = t->continuation; + } + if (ip == 0) { ip = t->arch->frameIp(stack); } @@ -1773,6 +1911,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, + t->arch->frameReturnAddressSize(); *targetStack = sp; + *targetContinuation = continuation; sp[localOffset(t, localSize(t, method), method)] = t->exception; @@ -1792,9 +1931,10 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, *targetBase = base; *targetStack = static_cast(stack) + t->arch->frameReturnAddressSize(); + *targetContinuation = continuation; - while (Continuations and t->continuation) { - object c = t->continuation; + while (Continuations and *targetContinuation) { + object c = *targetContinuation; object method = continuationMethod(t, c); @@ -1812,6 +1952,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, t->exceptionOffset = localOffset(t, localSize(t, method), method) * BytesPerWord; + break; } else if (t->exception) { releaseLock(t, method, @@ -1821,7 +1962,7 @@ findUnwindTarget(MyThread* t, void** targetIp, void** targetBase, - t->arch->returnAddressOffset()); } - t->continuation = continuationNext(t, c); + *targetContinuation = continuationNext(t, c); } } } @@ -1831,12 +1972,9 @@ object makeCurrentContinuation(MyThread* t, void** targetIp, void** targetBase, void** targetStack) { - void* ip = t->ip; + void* ip = t->arch->frameIp(t->stack); void* base = t->base; void* stack = t->stack; - if (ip == 0) { - ip = t->arch->frameIp(stack); - } object context = t->continuation ? continuationContext(t, t->continuation) @@ -1921,7 +2059,11 @@ unwind(MyThread* t) void* ip; void* base; void* stack; - findUnwindTarget(t, &ip, &base, &stack); + object continuation; + findUnwindTarget(t, &ip, &base, &stack, &continuation); + + transition(t, ip, stack, base, continuation, t->trace); + vmJump(ip, base, stack, t, 0, 0); } @@ -2445,11 +2587,15 @@ traceSize(Thread* t) void NO_RETURN throwArrayIndexOutOfBounds(MyThread* t) { - ensure(t, FixedSizeOfArrayIndexOutOfBoundsException + traceSize(t)); - - t->tracing = true; - t->exception = makeArrayIndexOutOfBoundsException(t, 0); - t->tracing = false; + if (ensure(t, FixedSizeOfArrayIndexOutOfBoundsException + traceSize(t))) { + t->tracing = true; + t->exception = makeArrayIndexOutOfBoundsException(t, 0); + t->tracing = false; + } else { + // not enough memory available for a new exception and stack trace + // -- use a preallocated instance instead + t->exception = t->m->arrayIndexOutOfBoundsException; + } unwind(t); } @@ -2502,7 +2648,7 @@ makeNew64(Thread* t, object class_) void gcIfNecessary(MyThread* t) { - if (UNLIKELY(t->backupHeap)) { + if (UNLIKELY(t->useBackupHeap)) { collect(t, Heap::MinorCollection); } } @@ -2624,12 +2770,13 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall, traceFlags |= TraceElement::TailCall; TraceElement* trace = frame->trace(target, traceFlags); - Compiler::Operand* returnAddress = c->promiseConstant - (new (frame->context->zone.allocate(sizeof(TraceElementPromise))) - TraceElementPromise(t->m->system, trace), Compiler::AddressType); + + Promise* returnAddressPromise = new + (frame->context->zone.allocate(sizeof(TraceElementPromise))) + TraceElementPromise(t->m->system, trace); Compiler::Operand* result = c->stackCall - (returnAddress, + (c->promiseConstant(returnAddressPromise, Compiler::AddressType), flags, trace, rSize, @@ -2637,7 +2784,8 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall, methodParameterFootprint(t, target)); c->store - (BytesPerWord, returnAddress, BytesPerWord, c->memory + (BytesPerWord, frame->addressOperand(returnAddressPromise), + BytesPerWord, c->memory (c->register_(t->arch->thread()), Compiler::AddressType, difference(&(t->tailAddress), t))); @@ -2686,8 +2834,10 @@ compileDirectInvoke(MyThread* t, Frame* frame, object target, bool tailCall) } else { BootContext* bc = frame->context->bootContext; if (bc) { - if (methodClass(t, target) == methodClass(t, frame->context->method) - or (not classNeedsInit(t, methodClass(t, target)))) + if ((methodClass(t, target) == methodClass(t, frame->context->method) + or (not classNeedsInit(t, methodClass(t, target)))) + and (not (TailCalls and tailCall + and (methodFlags(t, target) & ACC_NATIVE)))) { Promise* p = new (bc->zone->allocate(sizeof(ListenPromise))) ListenPromise(t->m->system, bc->zone); @@ -5535,11 +5685,11 @@ finish(MyThread* t, Allocator* allocator, Context* context) ::strcmp (reinterpret_cast (&byteArrayBody(t, className(t, methodClass(t, context->method)), 0)), - "org/eclipse/swt/widgets/Control") == 0 and + "java/lang/System") == 0 and ::strcmp (reinterpret_cast (&byteArrayBody(t, methodName(t, context->method), 0)), - "gtk_motion_notify_event") == 0) + "") == 0) { trap(); } @@ -5669,11 +5819,11 @@ finish(MyThread* t, Allocator* allocator, Context* context) ::strcmp (reinterpret_cast (&byteArrayBody(t, className(t, methodClass(t, context->method)), 0)), - "AllFloats") == 0 and + "java/lang/System") == 0 and ::strcmp (reinterpret_cast (&byteArrayBody(t, methodName(t, context->method), 0)), - "multiplyByFive") == 0) + "") == 0) { trap(); } @@ -6222,17 +6372,20 @@ invokeNative(MyThread* t) if (UNLIKELY(t->exception)) { unwind(t); } else { + uintptr_t* stack = static_cast(t->stack); + if (TailCalls and t->arch->argumentFootprint(parameterFootprint) > t->arch->stackAlignmentInWords()) { - t->stack = static_cast(t->stack) - + (t->arch->argumentFootprint(parameterFootprint) - - t->arch->stackAlignmentInWords()); + stack += t->arch->argumentFootprint(parameterFootprint) + - t->arch->stackAlignmentInWords(); } - t->stack = static_cast(t->stack) - + t->arch->frameReturnAddressSize(); + stack += t->arch->frameReturnAddressSize(); + + transition(t, t->arch->frameIp(t->stack), stack, t->base, t->continuation, + t->trace); return result; } @@ -6405,12 +6558,9 @@ visitArguments(MyThread* t, Heap::Visitor* v, void* stack, object method) void visitStack(MyThread* t, Heap::Visitor* v) { - void* ip = t->ip; + void* ip = t->arch->frameIp(t->stack); void* base = t->base; void* stack = t->stack; - if (ip == 0) { - ip = t->arch->frameIp(stack); - } MyThread::CallTrace* trace = t->trace; object targetMethod = (trace ? trace->targetMethod : 0); @@ -6489,23 +6639,19 @@ callContinuation(MyThread* t, object continuation, object result, { assert(t, t->exception == 0); - t->continuation = continuation; - if (exception) { t->exception = exception; - t->ip = ip; - t->base = base; - t->stack = stack; + MyThread::TraceContext c(t, ip, stack, base, continuation, t->trace); - findUnwindTarget(t, &ip, &base, &stack); - - t->ip = 0; + findUnwindTarget(t, &ip, &base, &stack, &continuation); } t->trace->nativeMethod = 0; t->trace->targetMethod = 0; + transition(t, ip, stack, base, continuation, t->trace); + vmJump(ip, base, stack, t, reinterpret_cast(result), 0); } @@ -6688,7 +6834,8 @@ callContinuation(MyThread* t, object continuation, object result, void* ip; void* base; void* stack; - findUnwindTarget(t, &ip, &base, &stack); + object threadContinuation; + findUnwindTarget(t, &ip, &base, &stack, &threadContinuation); switch (action) { case Call: { @@ -6700,7 +6847,7 @@ callContinuation(MyThread* t, object continuation, object result, } break; case Rewind: { - t->continuation = nextContinuation; + transition(t, 0, 0, 0, nextContinuation, t->trace); jumpAndInvoke (t, rewindMethod(t), base, stack, @@ -6709,6 +6856,8 @@ callContinuation(MyThread* t, object continuation, object result, } break; case Throw: { + transition(t, ip, stack, base, threadContinuation, t->trace); + vmJump(ip, base, stack, t, 0, 0); } break; @@ -6954,7 +7103,7 @@ invoke(Thread* thread, object method, ArgumentList* arguments) } if (t->exception) { - if (t->backupHeap) { + if (UNLIKELY(t->useBackupHeap)) { collect(t, Heap::MinorCollection); } return 0; @@ -7002,32 +7151,32 @@ class SegFaultHandler: public System::SignalHandler { if (t and t->state == Thread::ActiveState) { object node = methodForIp(t, *ip); if (node) { - void* oldIp = t->ip; - void* oldBase = t->base; - void* oldStack = t->stack; - // add one to the IP since findLineNumber will subtract one // when we make the trace: - t->ip = static_cast(*ip) + 1; - t->base = *base; - t->stack = static_cast(*stack) - - t->arch->frameReturnAddressSize(); + MyThread::TraceContext context + (t, static_cast(*ip) + 1, + static_cast(*stack) - t->arch->frameReturnAddressSize(), + *base, t->continuation, t->trace); - ensure(t, FixedSizeOfNullPointerException + traceSize(t)); - - t->tracing = true; - t->exception = makeNullPointerException(t); - t->tracing = false; + if (ensure(t, FixedSizeOfNullPointerException + traceSize(t))) { + t->tracing = true; + t->exception = makeNullPointerException(t); + t->tracing = false; + } else { + // not enough memory available for a new NPE and stack trace + // -- use a preallocated instance instead + t->exception = t->m->nullPointerException; + } // printTrace(t, t->exception); - findUnwindTarget(t, ip, base, stack); + object continuation; + findUnwindTarget(t, ip, base, stack, &continuation); - t->ip = oldIp; - t->base = oldBase; - t->stack = oldStack; + transition(t, ip, stack, base, continuation, t->trace); *thread = t; + return true; } } @@ -7042,6 +7191,15 @@ class SegFaultHandler: public System::SignalHandler { Machine* m; }; +bool +isThunk(MyThread* t, void* ip); + +bool +isVirtualThunk(MyThread* t, void* ip); + +bool +isThunkUnsafeStack(MyThread* t, void* ip); + void boot(MyThread* t, BootImage* image); @@ -7055,17 +7213,33 @@ processor(MyThread* t); class MyProcessor: public Processor { public: + class Thunk { + public: + Thunk(): + start(0), frameSavedOffset(0), length(0) + { } + + Thunk(uint8_t* start, unsigned frameSavedOffset, unsigned length): + start(start), frameSavedOffset(frameSavedOffset), length(length) + { } + + uint8_t* start; + unsigned frameSavedOffset; + unsigned length; + }; + + class ThunkCollection { + public: + Thunk default_; + Thunk defaultVirtual; + Thunk native; + Thunk aioob; + Thunk table; + }; + MyProcessor(System* s, Allocator* allocator, bool useNativeFeatures): s(s), allocator(allocator), - defaultThunk(0), - bootDefaultThunk(0), - defaultVirtualThunk(0), - nativeThunk(0), - bootNativeThunk(0), - aioobThunk(0), - thunkTable(0), - bootThunkTable(0), callTable(0), methodTree(0), methodTreeSentinal(0), @@ -7077,8 +7251,6 @@ class MyProcessor: public Processor { rewindMethod(0), bootImage(0), codeAllocator(s, 0, 0), - thunkSize(0), - bootThunkSize(0), callTableSize(0), useNativeFeatures(useNativeFeatures) { } @@ -7389,42 +7561,58 @@ class MyProcessor: public Processor { { } virtual void visit(void* ip, void* base, void* stack) { - void* oldIp = target->ip; - void* oldBase = target->base; - void* oldStack = target->stack; + MyThread::TraceContext c(target); if (methodForIp(t, ip)) { - target->ip = ip; - target->base = base; - target->stack = stack; + // we caught the thread in Java code - use the register values + c.ip = ip; + c.base = base; + c.stack = stack; + } else if (target->transition) { + // we caught the thread in native code while in the middle + // of updating the context fields (MyThread::stack, + // MyThread::base, etc.) + static_cast(c) = *(target->transition); + } else if (isVmInvokeUnsafeStack(ip)) { + // we caught the thread in native code just after returning + // from java code, but before clearing MyThread::stack + // (which now contains a garbage value), and the most recent + // Java frame, if any, can be found in + // MyThread::continuation or MyThread::trace + c.ip = 0; + c.base = 0; + c.stack = 0; + } else if (target->stack + and (not isThunkUnsafeStack(t, ip)) + and (not isVirtualThunk(t, ip))) + { + // we caught the thread in a thunk or native code, and the + // saved stack and base pointers indicate the most recent + // Java frame on the stack + c.ip = t->arch->frameIp(target->stack); + c.base = target->base; + c.stack = target->stack; + } else if (isThunk(t, ip) or isVirtualThunk(t, ip)) { + // we caught the thread in a thunk where the stack and base + // registers indicate the most recent Java frame on the + // stack + c.ip = t->arch->frameIp(stack); + c.base = base; + c.stack = stack; } else { - uint8_t* thunkStart = p->thunkTable; - uint8_t* thunkEnd = thunkStart + (p->thunkSize * ThunkCount); - - uint8_t* bootThunkStart = p->bootThunkTable; - uint8_t* bootThunkEnd = bootThunkStart - + (p->bootThunkSize * ThunkCount); - - if ((static_cast(ip) >= thunkStart - and static_cast(ip) < thunkEnd) - or (static_cast(ip) >= bootThunkStart - and static_cast(ip) < bootThunkEnd)) - { - target->ip = t->arch->frameIp(stack); - target->base = base; - target->stack = stack; - } + // we caught the thread in native code, and the most recent + // Java frame, if any, can be found in + // MyThread::continuation or MyThread::trace + c.ip = 0; + c.base = 0; + c.stack = 0; } - ensure(t, traceSize(target)); - - t->tracing = true; - trace = makeTrace(t, target); - t->tracing = false; - - target->ip = oldIp; - target->base = oldBase; - target->stack = oldStack; + if (ensure(t, traceSize(target))) { + t->tracing = true; + trace = makeTrace(t, target); + t->tracing = false; + } } MyThread* t; @@ -7435,7 +7623,7 @@ class MyProcessor: public Processor { t->m->system->visit(t->systemThread, target->systemThread, &visitor); - if (t->backupHeap) { + if (UNLIKELY(t->useBackupHeap)) { PROTECT(t, visitor.trace); collect(t, Heap::MinorCollection); @@ -7564,14 +7752,6 @@ class MyProcessor: public Processor { System* s; Allocator* allocator; - uint8_t* defaultThunk; - uint8_t* bootDefaultThunk; - uint8_t* defaultVirtualThunk; - uint8_t* nativeThunk; - uint8_t* bootNativeThunk; - uint8_t* aioobThunk; - uint8_t* thunkTable; - uint8_t* bootThunkTable; object callTable; object methodTree; object methodTreeSentinal; @@ -7584,12 +7764,99 @@ class MyProcessor: public Processor { BootImage* bootImage; SegFaultHandler segFaultHandler; FixedAllocator codeAllocator; - unsigned thunkSize; - unsigned bootThunkSize; + ThunkCollection thunks; + ThunkCollection bootThunks; unsigned callTableSize; bool useNativeFeatures; }; +bool +isThunk(MyProcessor::ThunkCollection* thunks, void* ip) +{ + uint8_t* thunkStart = thunks->default_.start; + uint8_t* thunkEnd = thunks->table.start + + (thunks->table.length * ThunkCount); + + return (reinterpret_cast(ip) + >= reinterpret_cast(thunkStart) + and reinterpret_cast(ip) + < reinterpret_cast(thunkEnd)); +} + +bool +isThunk(MyThread* t, void* ip) +{ + MyProcessor* p = processor(t); + + return isThunk(&(p->thunks), ip) or isThunk(&(p->bootThunks), ip); +} + +bool +isThunkUnsafeStack(MyProcessor::Thunk* thunk, void* ip) +{ + return reinterpret_cast(ip) + >= reinterpret_cast(thunk->start) + and reinterpret_cast(ip) + < reinterpret_cast(thunk->start + thunk->frameSavedOffset); +} + +bool +isThunkUnsafeStack(MyProcessor::ThunkCollection* thunks, void* ip) +{ + const unsigned NamedThunkCount = 4; + + MyProcessor::Thunk table[NamedThunkCount + ThunkCount]; + + table[0] = thunks->default_; + table[1] = thunks->defaultVirtual; + table[2] = thunks->native; + table[3] = thunks->aioob; + + for (unsigned i = 0; i < ThunkCount; ++i) { + new (table + NamedThunkCount + i) MyProcessor::Thunk + (thunks->table.start + (i * thunks->table.length), + thunks->table.frameSavedOffset, + thunks->table.length); + } + + for (unsigned i = 0; i < NamedThunkCount + ThunkCount; ++i) { + if (isThunkUnsafeStack(table + i, ip)) { + return true; + } + } + + return false; +} + +bool +isVirtualThunk(MyThread* t, void* ip) +{ + MyProcessor* p = processor(t); + + for (unsigned i = 0; i < wordArrayLength(t, p->virtualThunks); i += 2) { + uintptr_t start = wordArrayBody(t, p->virtualThunks, i); + uintptr_t end = start + wordArrayBody(t, p->virtualThunks, i + 1); + + if (reinterpret_cast(ip) >= start + and reinterpret_cast(ip) < end) + { + return true; + } + } + + return false; +} + +bool +isThunkUnsafeStack(MyThread* t, void* ip) +{ + MyProcessor* p = processor(t); + + return isThunk(t, ip) + and (isThunkUnsafeStack(&(p->thunks), ip) + or isThunkUnsafeStack(&(p->bootThunks), ip)); +} + object findCallNode(MyThread* t, void* address) { @@ -7852,15 +8119,24 @@ fixupMethods(Thread* t, BootImage* image, uint8_t* code) } } +MyProcessor::Thunk +thunkToThunk(const BootImage::Thunk& thunk, uint8_t* base) +{ + return MyProcessor::Thunk + (base + thunk.start, thunk.frameSavedOffset, thunk.length); +} + void fixupThunks(MyThread* t, BootImage* image, uint8_t* code) { MyProcessor* p = processor(t); - p->bootDefaultThunk = code + image->defaultThunk; - p->bootNativeThunk = code + image->nativeThunk; - p->bootThunkTable = code + image->thunkTable; - p->bootThunkSize = image->thunkSize; + p->bootThunks.default_ = thunkToThunk(image->thunks.default_, code); + p->bootThunks.defaultVirtual + = thunkToThunk(image->thunks.defaultVirtual, code); + p->bootThunks.native = thunkToThunk(image->thunks.native, code); + p->bootThunks.aioob = thunkToThunk(image->thunks.aioob, code); + p->bootThunks.table = thunkToThunk(image->thunks.table, code); updateCall(t, LongCall, code + image->compileMethodCall, voidPointer(local::compileMethod)); @@ -7887,7 +8163,7 @@ fixupVirtualThunks(MyThread* t, BootImage* image, uint8_t* code) { MyProcessor* p = processor(t); - for (unsigned i = 0; i < wordArrayLength(t, p->virtualThunks); ++i) { + for (unsigned i = 0; i < wordArrayLength(t, p->virtualThunks); i += 2) { if (wordArrayBody(t, p->virtualThunks, i)) { wordArrayBody(t, p->virtualThunks, i) = (wordArrayBody(t, p->virtualThunks, i) - image->codeBase) @@ -7967,7 +8243,14 @@ getThunk(MyThread* t, Thunk thunk) MyProcessor* p = processor(t); return reinterpret_cast - (p->thunkTable + (thunk * p->thunkSize)); + (p->thunks.table.start + (thunk * p->thunks.table.length)); +} + +BootImage::Thunk +thunkToThunk(const MyProcessor::Thunk& thunk, uint8_t* base) +{ + return BootImage::Thunk + (thunk.start - base, thunk.frameSavedOffset, thunk.length); } void @@ -7991,6 +8274,8 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); + p->thunks.default_.frameSavedOffset = a->length(); + Assembler::Register thread(t->arch->thread()); a->pushFrame(1, BytesPerWord, RegisterOperand, &thread); @@ -8003,6 +8288,8 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) a->apply(Jump, BytesPerWord, RegisterOperand, &result); a->endBlock(false)->resolve(0, 0); + + p->thunks.default_.length = a->length(); } ThunkContext defaultVirtualContext(t, &zone); @@ -8033,6 +8320,8 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); + p->thunks.defaultVirtual.frameSavedOffset = a->length(); + Assembler::Register thread(t->arch->thread()); a->pushFrame(1, BytesPerWord, RegisterOperand, &thread); @@ -8045,6 +8334,8 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) a->apply(Jump, BytesPerWord, RegisterOperand, &result); a->endBlock(false)->resolve(0, 0); + + p->thunks.defaultVirtual.length = a->length(); } ThunkContext nativeContext(t, &zone); @@ -8053,6 +8344,8 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); + p->thunks.native.frameSavedOffset = a->length(); + Assembler::Register thread(t->arch->thread()); a->pushFrame(1, BytesPerWord, RegisterOperand, &thread); @@ -8062,6 +8355,8 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) a->popFrameAndUpdateStackAndReturn(difference(&(t->stack), t)); a->endBlock(false)->resolve(0, 0); + + p->thunks.native.length = a->length(); } ThunkContext aioobContext(t, &zone); @@ -8070,6 +8365,8 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); + p->thunks.aioob.frameSavedOffset = a->length(); + Assembler::Register thread(t->arch->thread()); a->pushFrame(1, BytesPerWord, RegisterOperand, &thread); @@ -8077,6 +8374,8 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) a->apply(LongCall, BytesPerWord, ConstantOperand, &proc); a->endBlock(false)->resolve(0, 0); + + p->thunks.aioob.length = a->length(); } ThunkContext tableContext(t, &zone); @@ -8085,15 +8384,17 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) a->saveFrame(difference(&(t->stack), t), difference(&(t->base), t)); + p->thunks.table.frameSavedOffset = a->length(); + Assembler::Constant proc(&(tableContext.promise)); a->apply(LongJump, BytesPerWord, ConstantOperand, &proc); a->endBlock(false)->resolve(0, 0); - } - p->thunkSize = pad(tableContext.context.assembler->length()); + p->thunks.table.length = a->length(); + } - p->defaultThunk = finish + p->thunks.default_.start = finish (t, allocator, defaultContext.context.assembler, "default"); BootImage* image = p->bootImage; @@ -8104,12 +8405,11 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) (reinterpret_cast(voidPointer(compileMethod)), &call); if (image) { - image->defaultThunk = p->defaultThunk - imageBase; image->compileMethodCall = static_cast(call) - imageBase; } } - p->defaultVirtualThunk = finish + p->thunks.defaultVirtual.start = finish (t, allocator, defaultVirtualContext.context.assembler, "defaultVirtual"); { void* call; @@ -8117,13 +8417,12 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) (reinterpret_cast(voidPointer(compileVirtualMethod)), &call); if (image) { - image->defaultVirtualThunk = p->defaultVirtualThunk - imageBase; image->compileVirtualMethodCall = static_cast(call) - imageBase; } } - p->nativeThunk = finish + p->thunks.native.start = finish (t, allocator, nativeContext.context.assembler, "native"); { void* call; @@ -8131,12 +8430,11 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) (reinterpret_cast(voidPointer(invokeNative)), &call); if (image) { - image->nativeThunk = p->nativeThunk - imageBase; image->invokeNativeCall = static_cast(call) - imageBase; } } - p->aioobThunk = finish + p->thunks.aioob.start = finish (t, allocator, aioobContext.context.assembler, "aioob"); { void* call; @@ -8145,27 +8443,31 @@ compileThunks(MyThread* t, Allocator* allocator, MyProcessor* p) &call); if (image) { - image->aioobThunk = p->aioobThunk - imageBase; image->throwArrayIndexOutOfBoundsCall = static_cast(call) - imageBase; } } - p->thunkTable = static_cast - (allocator->allocate(p->thunkSize * ThunkCount)); + p->thunks.table.start = static_cast + (allocator->allocate(p->thunks.table.length * ThunkCount)); if (image) { - image->thunkTable = p->thunkTable - imageBase; - image->thunkSize = p->thunkSize; + image->thunks.default_ = thunkToThunk(p->thunks.default_, imageBase); + image->thunks.defaultVirtual + = thunkToThunk(p->thunks.defaultVirtual, imageBase); + image->thunks.native = thunkToThunk(p->thunks.native, imageBase); + image->thunks.aioob = thunkToThunk(p->thunks.aioob, imageBase); + image->thunks.table = thunkToThunk(p->thunks.table, imageBase); } - logCompile(t, p->thunkTable, p->thunkSize * ThunkCount, 0, "thunkTable", 0); + logCompile(t, p->thunks.table.start, p->thunks.table.length * ThunkCount, 0, + "thunkTable", 0); - uint8_t* start = p->thunkTable; + uint8_t* start = p->thunks.table.start; #define THUNK(s) \ tableContext.context.assembler->writeTo(start); \ - start += p->thunkSize; \ + start += p->thunks.table.length; \ { void* call; \ tableContext.promise.listener->resolve \ (reinterpret_cast(voidPointer(s)), &call); \ @@ -8212,37 +8514,38 @@ receiveMethod(MyThread* t) uintptr_t defaultThunk(MyThread* t) { - return reinterpret_cast(processor(t)->defaultThunk); + return reinterpret_cast(processor(t)->thunks.default_.start); } uintptr_t bootDefaultThunk(MyThread* t) { - return reinterpret_cast(processor(t)->bootDefaultThunk); + return reinterpret_cast(processor(t)->bootThunks.default_.start); } uintptr_t defaultVirtualThunk(MyThread* t) { - return reinterpret_cast(processor(t)->defaultVirtualThunk); + return reinterpret_cast + (processor(t)->thunks.defaultVirtual.start); } uintptr_t nativeThunk(MyThread* t) { - return reinterpret_cast(processor(t)->nativeThunk); + return reinterpret_cast(processor(t)->thunks.native.start); } uintptr_t bootNativeThunk(MyThread* t) { - return reinterpret_cast(processor(t)->bootNativeThunk); + return reinterpret_cast(processor(t)->bootThunks.native.start); } uintptr_t aioobThunk(MyThread* t) { - return reinterpret_cast(processor(t)->aioobThunk); + return reinterpret_cast(processor(t)->thunks.aioob.start); } bool @@ -8253,7 +8556,7 @@ unresolved(MyThread* t, uintptr_t methodAddress) } uintptr_t -compileVirtualThunk(MyThread* t, unsigned index) +compileVirtualThunk(MyThread* t, unsigned index, unsigned* size) { Context context(t); Assembler* a = context.assembler; @@ -8270,12 +8573,13 @@ compileVirtualThunk(MyThread* t, unsigned index) a->endBlock(false)->resolve(0, 0); - uint8_t* start = static_cast - (codeAllocator(t)->allocate(a->length())); + *size = a->length(); + + uint8_t* start = static_cast(codeAllocator(t)->allocate(*size)); a->writeTo(start); - logCompile(t, start, a->length(), 0, "virtualThunk", 0); + logCompile(t, start, *size, 0, "virtualThunk", 0); return reinterpret_cast(start); } @@ -8285,8 +8589,10 @@ virtualThunk(MyThread* t, unsigned index) { MyProcessor* p = processor(t); - if (p->virtualThunks == 0 or wordArrayLength(t, p->virtualThunks) <= index) { - object newArray = makeWordArray(t, nextPowerOfTwo(index + 1)); + if (p->virtualThunks == 0 + or wordArrayLength(t, p->virtualThunks) <= index * 2) + { + object newArray = makeWordArray(t, nextPowerOfTwo((index + 1) * 2)); if (p->virtualThunks) { memcpy(&wordArrayBody(t, newArray, 0), &wordArrayBody(t, p->virtualThunks, 0), @@ -8295,16 +8601,18 @@ virtualThunk(MyThread* t, unsigned index) p->virtualThunks = newArray; } - if (wordArrayBody(t, p->virtualThunks, index) == 0) { + if (wordArrayBody(t, p->virtualThunks, index * 2) == 0) { ACQUIRE(t, t->m->classLock); - if (wordArrayBody(t, p->virtualThunks, index) == 0) { - uintptr_t thunk = compileVirtualThunk(t, index); - wordArrayBody(t, p->virtualThunks, index) = thunk; + if (wordArrayBody(t, p->virtualThunks, index * 2) == 0) { + unsigned size; + uintptr_t thunk = compileVirtualThunk(t, index, &size); + wordArrayBody(t, p->virtualThunks, index * 2) = thunk; + wordArrayBody(t, p->virtualThunks, (index * 2) + 1) = size; } } - return wordArrayBody(t, p->virtualThunks, index); + return wordArrayBody(t, p->virtualThunks, index * 2); } void diff --git a/src/continuations-x86.S b/src/continuations-x86.S index aeee640388..c55679d0ba 100644 --- a/src/continuations-x86.S +++ b/src/continuations-x86.S @@ -10,11 +10,11 @@ #ifdef __x86_64__ -#define THREAD_CONTINUATION 192 +#define THREAD_CONTINUATION 2224 #define THREAD_EXCEPTION 80 -#define THREAD_EXCEPTION_STACK_ADJUSTMENT 200 -#define THREAD_EXCEPTION_OFFSET 208 -#define THREAD_EXCEPTION_HANDLER 216 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2232 +#define THREAD_EXCEPTION_OFFSET 2240 +#define THREAD_EXCEPTION_HANDLER 2248 #define CONTINUATION_NEXT 8 #define CONTINUATION_ADDRESS 32 @@ -89,11 +89,11 @@ LOCAL(vmInvoke_exit): #elif defined __i386__ -#define THREAD_CONTINUATION 108 +#define THREAD_CONTINUATION 2148 #define THREAD_EXCEPTION 44 -#define THREAD_EXCEPTION_STACK_ADJUSTMENT 112 -#define THREAD_EXCEPTION_OFFSET 116 -#define THREAD_EXCEPTION_HANDLER 120 +#define THREAD_EXCEPTION_STACK_ADJUSTMENT 2152 +#define THREAD_EXCEPTION_OFFSET 2156 +#define THREAD_EXCEPTION_HANDLER 2160 #define CONTINUATION_NEXT 4 #define CONTINUATION_ADDRESS 16 @@ -138,15 +138,15 @@ LOCAL(vmInvoke_continuationTest): // set the return address to vmInvoke_returnAddress movl CONTINUATION_RETURN_ADDRESS_OFFSET(%ecx),%edi #if defined __MINGW32__ || defined __CYGWIN32__ - movl $vmInvoke_returnAddress,%esi + movl $GLOBAL(vmInvoke_returnAddress),%esi #else call LOCAL(getPC) # if defined __APPLE__ LOCAL(vmInvoke_offset): - leal vmInvoke_returnAddress-LOCAL(vmInvoke_offset)(%esi),%esi + leal GLOBAL(vmInvoke_returnAddress)-LOCAL(vmInvoke_offset)(%esi),%esi # else addl $_GLOBAL_OFFSET_TABLE_,%esi - movl vmInvoke_returnAddress@GOT(%esi),%esi + movl GLOBAL(vmInvoke_returnAddress)@GOT(%esi),%esi # endif #endif movl %esi,(%esp,%edi,1) diff --git a/src/machine.cpp b/src/machine.cpp index 3b3c1fb215..44230b0fd2 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -570,12 +570,11 @@ postCollect(Thread* t) t->heapOffset = 0; t->heapIndex = 0; - if (t->backupHeap) { - t->m->heap->free - (t->backupHeap, t->backupHeapSizeInWords * BytesPerWord); - t->backupHeap = 0; + if (t->useBackupHeap) { + memset(t->backupHeap, 0, ThreadBackupHeapSizeInBytes); + + t->useBackupHeap = false; t->backupHeapIndex = 0; - t->backupHeapSizeInWords = 0; } for (Thread* c = t->child; c; c = c->peer) { @@ -1978,7 +1977,6 @@ boot(Thread* t) m->bootstrapClassMap = makeHashMap(t, 0, 0); m->stringMap = makeWeakHashMap(t, 0, 0); - m->processor->boot(t, 0); { object bootCode = makeCode(t, 0, 0, 0, 0, 0, 1); @@ -2123,6 +2121,8 @@ Machine::Machine(System* system, Heap* heap, Finder* finder, tenuredWeakReferences(0), shutdownHooks(0), objectsToFinalize(0), + nullPointerException(0), + arrayIndexOutOfBoundsException(0), unsafe(false), triedBuiltinOnLoad(false), heapPoolIndex(0) @@ -2196,9 +2196,8 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent): defaultHeap(static_cast (m->heap->allocate(ThreadHeapSizeInBytes))), heap(defaultHeap), - backupHeap(0), backupHeapIndex(0), - backupHeapSizeInWords(0), + useBackupHeap(false), waiting(false), tracing(false) #ifdef VM_STRESS @@ -2210,6 +2209,7 @@ void Thread::init() { memset(defaultHeap, 0, ThreadHeapSizeInBytes); + memset(backupHeap, 0, ThreadBackupHeapSizeInBytes); if (parent == 0) { assert(this, m->rootThread == 0); @@ -2248,6 +2248,11 @@ Thread::init() m->jniMethodTable = makeVector(this, 0, 0); + m->nullPointerException = makeNullPointerException(this); + + m->arrayIndexOutOfBoundsException + = makeArrayIndexOutOfBoundsException(this, 0); + m->localThread->set(this); } else { peer = parent->child; @@ -2539,15 +2544,15 @@ object allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type, unsigned sizeInBytes, bool objectMask) { - if (t->backupHeap) { + if (UNLIKELY(t->useBackupHeap)) { expect(t, t->backupHeapIndex + ceiling(sizeInBytes, BytesPerWord) - <= t->backupHeapSizeInWords); + <= ThreadBackupHeapSizeInWords); object o = reinterpret_cast(t->backupHeap + t->backupHeapIndex); t->backupHeapIndex += ceiling(sizeInBytes, BytesPerWord); cast(o, 0) = 0; return o; - } else if (t->tracing) { + } else if (UNLIKELY(t->tracing)) { expect(t, t->heapIndex + ceiling(sizeInBytes, BytesPerWord) <= ThreadHeapSizeInWords); return allocateSmall(t, sizeInBytes); @@ -3676,6 +3681,8 @@ visitRoots(Machine* m, Heap::Visitor* v) v->visit(&(m->jniMethodTable)); v->visit(&(m->shutdownHooks)); v->visit(&(m->objectsToFinalize)); + v->visit(&(m->nullPointerException)); + v->visit(&(m->arrayIndexOutOfBoundsException)); for (Thread* t = m->rootThread; t; t = t->peer) { ::visitRoots(t, v); diff --git a/src/machine.h b/src/machine.h index 8f705ba166..0773c1acf2 100644 --- a/src/machine.h +++ b/src/machine.h @@ -49,6 +49,10 @@ const uintptr_t FixedMark = 3; const unsigned ThreadHeapSizeInBytes = 64 * 1024; const unsigned ThreadHeapSizeInWords = ThreadHeapSizeInBytes / BytesPerWord; +const unsigned ThreadBackupHeapSizeInBytes = 2 * 1024; +const unsigned ThreadBackupHeapSizeInWords += ThreadBackupHeapSizeInBytes / BytesPerWord; + const unsigned ThreadHeapPoolSize = 64; const unsigned FixedFootprintThresholdInBytes @@ -1207,6 +1211,8 @@ class Machine { object tenuredWeakReferences; object shutdownHooks; object objectsToFinalize; + object nullPointerException; + object arrayIndexOutOfBoundsException; bool unsafe; bool triedBuiltinOnLoad; JavaVMVTable javaVMVTable; @@ -1360,9 +1366,9 @@ class Thread { Runnable runnable; uintptr_t* defaultHeap; uintptr_t* heap; - uintptr_t* backupHeap; + uintptr_t backupHeap[ThreadBackupHeapSizeInWords]; unsigned backupHeapIndex; - unsigned backupHeapSizeInWords; + bool useBackupHeap; bool waiting; bool tracing; #ifdef VM_STRESS @@ -1550,20 +1556,23 @@ class FixedAllocator: public Allocator { unsigned capacity; }; -inline void +inline bool ensure(Thread* t, unsigned sizeInBytes) { if (t->heapIndex + ceiling(sizeInBytes, BytesPerWord) > ThreadHeapSizeInWords) { - expect(t, t->backupHeap == 0); - t->backupHeap = static_cast - (t->m->heap->allocate(pad(sizeInBytes))); + if (sizeInBytes <= ThreadBackupHeapSizeInBytes) { + expect(t, not t->useBackupHeap); - memset(t->backupHeap, 0, sizeInBytes); + t->useBackupHeap = true; - t->backupHeapIndex = 0; - t->backupHeapSizeInWords = ceiling(sizeInBytes, BytesPerWord); + return true; + } else { + return false; + } + } else { + return true; } } diff --git a/src/powerpc.cpp b/src/powerpc.cpp index 391970d755..ac753150c9 100644 --- a/src/powerpc.cpp +++ b/src/powerpc.cpp @@ -2421,7 +2421,7 @@ class MyAssembler: public Assembler { for (ConstantPoolEntry* e = c.constantPool; e; e = e->next) { *static_cast(e->address) = e->constant->value(); - fprintf(stderr, "constant %p at %p\n", reinterpret_cast(e->constant->value()), e->address); +// fprintf(stderr, "constant %p at %p\n", reinterpret_cast(e->constant->value()), e->address); } }