2010-12-06 03:21:09 +00:00
|
|
|
/* Copyright (c) 2008-2010, Avian Contributors
|
2008-02-19 18:06:52 +00:00
|
|
|
|
|
|
|
Permission to use, copy, modify, and/or distribute this software
|
|
|
|
for any purpose with or without fee is hereby granted, provided
|
|
|
|
that the above copyright notice and this permission notice appear
|
|
|
|
in all copies.
|
|
|
|
|
|
|
|
There is NO WARRANTY for this software. See license.txt for
|
|
|
|
details. */
|
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
#include "types.h"
|
|
|
|
|
2008-06-15 18:49:37 +00:00
|
|
|
#define LOCAL(x) .L##x
|
|
|
|
|
2010-12-20 19:11:29 +00:00
|
|
|
#if defined __APPLE__ \
|
|
|
|
|| ((defined __MINGW32__ || defined __CYGWIN32__) && ! defined __x86_64__)
|
2009-05-29 01:13:15 +00:00
|
|
|
# define GLOBAL(x) _##x
|
|
|
|
#else
|
|
|
|
# define GLOBAL(x) x
|
|
|
|
#endif
|
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
.text
|
|
|
|
|
|
|
|
#ifdef __x86_64__
|
|
|
|
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
#define THREAD_STACK 2224
|
|
|
|
#define THREAD_SCRATCH 2232
|
fix Thread.getStackTrace race conditions
Implementing Thread.getStackTrace is tricky. A thread may interrupt
another thread at any time to grab a stack trace, including while the
latter is executing Java code, JNI code, helper thunks, VM code, or
while transitioning between any of these.
To create a stack trace we use several context fields associated with
the target thread, including snapshots of the instruction pointer,
stack pointer, and frame pointer. These fields must be current,
accurate, and consistent with each other in order to get a reliable
trace. Otherwise, we risk crashing the VM by trying to walk garbage
stack frames or by misinterpreting the size and/or content of
legitimate frames.
This commit addresses sensitive transition points such as entering the
helper thunks which bridge the transitions from Java to native code
(where we must save the stack and frame registers for use from native
code) and stack unwinding (where we must atomically update the thread
context fields to indicate which frame we are unwinding to). When
grabbing a trace for another thread, we determine what kind of code we
caught the thread executing in and use that information to choose the
thread context values with which to begin the trace. See
MyProcessor::getStackTrace::Visitor::visit for details.
In order to atomically update the thread context fields, we do the
following:
1. Create a temporary "transition" object to serve as a staging area
and populate it with the new field values.
2. Update a transition pointer in the thread object to point to the
object created above. As long as this pointer is non-null,
interrupting threads will use the context values in the staging
object instead of those in the thread object.
3. Update the fields in the thread object.
4. Clear the transition pointer in the thread object.
We use a memory barrier between each of these steps to ensure they are
made visible to other threads in program order. See
MyThread::doTransition for details.
2010-06-16 01:10:48 +00:00
|
|
|
|
2011-02-01 18:01:28 +00:00
|
|
|
#ifdef AVIAN_USE_FRAME_POINTER
|
|
|
|
# define ALIGNMENT_ADJUSTMENT 0
|
|
|
|
#else
|
|
|
|
# define ALIGNMENT_ADJUSTMENT 8
|
|
|
|
#endif
|
|
|
|
|
2009-12-03 02:37:22 +00:00
|
|
|
#if defined __MINGW32__ || defined __CYGWIN32__
|
2009-07-26 02:48:36 +00:00
|
|
|
|
2011-02-01 18:01:28 +00:00
|
|
|
#define CALLEE_SAVED_REGISTER_FOOTPRINT 64 + ALIGNMENT_ADJUSTMENT
|
2009-07-26 02:48:36 +00:00
|
|
|
|
|
|
|
.globl GLOBAL(vmInvoke)
|
|
|
|
GLOBAL(vmInvoke):
|
2009-06-11 15:48:27 +00:00
|
|
|
pushq %rbp
|
|
|
|
movq %rsp,%rbp
|
|
|
|
|
|
|
|
// %rcx: thread
|
|
|
|
// %rdx: function
|
|
|
|
// %r8 : arguments
|
|
|
|
// %r9 : argumentsFootprint
|
|
|
|
// 48(%rbp) : frameSize
|
|
|
|
// 56(%rbp) : returnType (ignored)
|
|
|
|
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
// allocate stack space for callee-saved registers
|
2009-07-26 02:48:36 +00:00
|
|
|
subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
|
|
|
|
// remember this stack position, since we won't be able to rely on
|
|
|
|
// %rbp being restored when the call returns
|
|
|
|
movq %rsp,THREAD_SCRATCH(%rcx)
|
2009-06-11 15:48:27 +00:00
|
|
|
|
|
|
|
// save callee-saved registers
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
movq %rbx,0(%rsp)
|
|
|
|
movq %r12,8(%rsp)
|
|
|
|
movq %r13,16(%rsp)
|
|
|
|
movq %r14,24(%rsp)
|
|
|
|
movq %r15,32(%rsp)
|
|
|
|
movq %rsi,40(%rsp)
|
|
|
|
movq %rdi,48(%rsp)
|
|
|
|
|
|
|
|
// allocate stack space for arguments
|
|
|
|
movl 48(%rbp),%eax
|
|
|
|
subq %rax,%rsp
|
2009-06-11 15:48:27 +00:00
|
|
|
|
|
|
|
// we use rbx to hold the thread pointer, by convention
|
|
|
|
mov %rcx,%rbx
|
|
|
|
|
|
|
|
// copy arguments into place
|
|
|
|
movq $0,%r11
|
2009-07-26 02:48:36 +00:00
|
|
|
jmp LOCAL(vmInvoke_argumentTest)
|
2009-06-11 15:48:27 +00:00
|
|
|
|
2009-07-26 02:48:36 +00:00
|
|
|
LOCAL(vmInvoke_argumentLoop):
|
2009-06-11 15:48:27 +00:00
|
|
|
movq (%r8,%r11,1),%rsi
|
|
|
|
movq %rsi,(%rsp,%r11,1)
|
|
|
|
addq $8,%r11
|
|
|
|
|
2009-07-26 02:48:36 +00:00
|
|
|
LOCAL(vmInvoke_argumentTest):
|
2009-06-11 15:48:27 +00:00
|
|
|
cmpq %r9,%r11
|
2009-07-26 02:48:36 +00:00
|
|
|
jb LOCAL(vmInvoke_argumentLoop)
|
2009-06-11 15:48:27 +00:00
|
|
|
|
|
|
|
// call function
|
|
|
|
call *%rdx
|
2009-07-26 02:48:36 +00:00
|
|
|
|
|
|
|
.globl GLOBAL(vmInvoke_returnAddress)
|
|
|
|
GLOBAL(vmInvoke_returnAddress):
|
2009-06-11 15:48:27 +00:00
|
|
|
// restore stack pointer
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
movq THREAD_SCRATCH(%rbx),%rsp
|
2009-07-26 02:48:36 +00:00
|
|
|
|
fix Thread.getStackTrace race conditions
Implementing Thread.getStackTrace is tricky. A thread may interrupt
another thread at any time to grab a stack trace, including while the
latter is executing Java code, JNI code, helper thunks, VM code, or
while transitioning between any of these.
To create a stack trace we use several context fields associated with
the target thread, including snapshots of the instruction pointer,
stack pointer, and frame pointer. These fields must be current,
accurate, and consistent with each other in order to get a reliable
trace. Otherwise, we risk crashing the VM by trying to walk garbage
stack frames or by misinterpreting the size and/or content of
legitimate frames.
This commit addresses sensitive transition points such as entering the
helper thunks which bridge the transitions from Java to native code
(where we must save the stack and frame registers for use from native
code) and stack unwinding (where we must atomically update the thread
context fields to indicate which frame we are unwinding to). When
grabbing a trace for another thread, we determine what kind of code we
caught the thread executing in and use that information to choose the
thread context values with which to begin the trace. See
MyProcessor::getStackTrace::Visitor::visit for details.
In order to atomically update the thread context fields, we do the
following:
1. Create a temporary "transition" object to serve as a staging area
and populate it with the new field values.
2. Update a transition pointer in the thread object to point to the
object created above. As long as this pointer is non-null,
interrupting threads will use the context values in the staging
object instead of those in the thread object.
3. Update the fields in the thread object.
4. Clear the transition pointer in the thread object.
We use a memory barrier between each of these steps to ensure they are
made visible to other threads in program order. See
MyThread::doTransition for details.
2010-06-16 01:10:48 +00:00
|
|
|
// 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):
|
|
|
|
|
2009-07-26 02:48:36 +00:00
|
|
|
#ifdef AVIAN_CONTINUATIONS
|
|
|
|
# include "continuations-x86.S"
|
|
|
|
#endif // AVIAN_CONTINUATIONS
|
|
|
|
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
// restore callee-saved registers
|
|
|
|
movq 0(%rsp),%rbx
|
|
|
|
movq 8(%rsp),%r12
|
|
|
|
movq 16(%rsp),%r13
|
|
|
|
movq 24(%rsp),%r14
|
|
|
|
movq 32(%rsp),%r15
|
|
|
|
movq 40(%rsp),%rsi
|
|
|
|
movq 48(%rsp),%rdi
|
2009-06-11 15:48:27 +00:00
|
|
|
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
addq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp
|
|
|
|
|
2009-06-11 15:48:27 +00:00
|
|
|
// return
|
|
|
|
popq %rbp
|
|
|
|
ret
|
2009-07-26 02:48:36 +00:00
|
|
|
|
|
|
|
.globl GLOBAL(vmJumpAndInvoke)
|
|
|
|
GLOBAL(vmJumpAndInvoke):
|
|
|
|
#ifdef AVIAN_CONTINUATIONS
|
|
|
|
// %rcx: thread
|
|
|
|
// %rdx: address
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
// %r8 : stack
|
|
|
|
// %r9 : argumentFootprint
|
|
|
|
// 40(%rsp): arguments
|
|
|
|
// 48(%rsp): frameSize
|
2009-07-26 02:48:36 +00:00
|
|
|
|
|
|
|
// allocate new frame, adding room for callee-saved registers
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
movl 48(%rsp),%eax
|
|
|
|
subq %rax,%r8
|
|
|
|
subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%r8
|
2009-05-05 01:04:17 +00:00
|
|
|
|
2009-07-26 02:48:36 +00:00
|
|
|
movq %rcx,%rbx
|
|
|
|
|
|
|
|
// set return address
|
2009-12-03 19:46:29 +00:00
|
|
|
leaq GLOBAL(vmInvoke_returnAddress)(%rip),%r10
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
movq %r10,(%r8)
|
2009-06-11 15:48:27 +00:00
|
|
|
|
2009-07-26 02:48:36 +00:00
|
|
|
// copy arguments into place
|
|
|
|
movq $0,%r11
|
2009-12-03 19:46:29 +00:00
|
|
|
movl 40(%rsp),%eax
|
2009-07-26 02:48:36 +00:00
|
|
|
jmp LOCAL(vmJumpAndInvoke_argumentTest)
|
|
|
|
|
|
|
|
LOCAL(vmJumpAndInvoke_argumentLoop):
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
movq (%rax,%r11,1),%r10
|
|
|
|
movq %r10,8(%r8,%r11,1)
|
2009-07-26 02:48:36 +00:00
|
|
|
addq $8,%r11
|
|
|
|
|
|
|
|
LOCAL(vmJumpAndInvoke_argumentTest):
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
cmpq %9,%r11
|
2009-07-26 02:48:36 +00:00
|
|
|
jb LOCAL(vmJumpAndInvoke_argumentLoop)
|
|
|
|
|
|
|
|
// the arguments have been copied, so we can set the real stack
|
|
|
|
// pointer now
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
movq %r8,%rsp
|
2009-07-26 02:48:36 +00:00
|
|
|
|
|
|
|
jmp *%rdx
|
|
|
|
#else // not AVIAN_CONTINUATIONS
|
|
|
|
// vmJumpAndInvoke should only be called when continuations are
|
|
|
|
// enabled
|
|
|
|
int3
|
|
|
|
#endif // not AVIAN_CONTINUATIONS
|
2009-05-05 01:04:17 +00:00
|
|
|
|
2009-12-03 06:15:27 +00:00
|
|
|
#else // not __MINGW32__ || __CYGWIN32__
|
2007-09-26 23:23:03 +00:00
|
|
|
|
2011-02-01 18:01:28 +00:00
|
|
|
#define CALLEE_SAVED_REGISTER_FOOTPRINT 48 + ALIGNMENT_ADJUSTMENT
|
2009-05-29 01:54:32 +00:00
|
|
|
|
2009-05-29 01:13:15 +00:00
|
|
|
.globl GLOBAL(vmInvoke)
|
|
|
|
GLOBAL(vmInvoke):
|
2007-09-26 23:23:03 +00:00
|
|
|
pushq %rbp
|
|
|
|
movq %rsp,%rbp
|
2007-12-11 21:26:59 +00:00
|
|
|
|
|
|
|
// %rdi: thread
|
|
|
|
// %rsi: function
|
2009-02-17 02:49:28 +00:00
|
|
|
// %rdx: arguments
|
|
|
|
// %rcx: argumentFootprint
|
|
|
|
// %r8 : frameSize
|
|
|
|
// %r9 : returnType (ignored)
|
|
|
|
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
// allocate stack space for callee-saved registers
|
2009-05-29 01:54:32 +00:00
|
|
|
subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp
|
2009-02-17 02:49:28 +00:00
|
|
|
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
// remember this stack position, since we won't be able to rely on
|
|
|
|
// %rbp being restored when the call returns
|
|
|
|
movq %rsp,THREAD_SCRATCH(%rdi)
|
|
|
|
|
2009-02-17 02:49:28 +00:00
|
|
|
// save callee-saved registers
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
movq %rbx,0(%rsp)
|
|
|
|
movq %r12,8(%rsp)
|
|
|
|
movq %r13,16(%rsp)
|
|
|
|
movq %r14,24(%rsp)
|
|
|
|
movq %r15,32(%rsp)
|
|
|
|
|
|
|
|
// allocate stack space for arguments
|
|
|
|
subq %r8,%rsp
|
|
|
|
|
2009-02-16 15:21:12 +00:00
|
|
|
// we use rbx to hold the thread pointer, by convention
|
2007-12-11 21:26:59 +00:00
|
|
|
mov %rdi,%rbx
|
2007-12-20 01:42:12 +00:00
|
|
|
|
2007-12-26 23:59:55 +00:00
|
|
|
// copy arguments into place
|
2007-12-11 21:26:59 +00:00
|
|
|
movq $0,%r9
|
2009-05-03 20:57:11 +00:00
|
|
|
jmp LOCAL(vmInvoke_argumentTest)
|
2007-09-26 23:23:03 +00:00
|
|
|
|
2009-05-03 20:57:11 +00:00
|
|
|
LOCAL(vmInvoke_argumentLoop):
|
2009-02-17 02:49:28 +00:00
|
|
|
movq (%rdx,%r9,1),%r8
|
|
|
|
movq %r8,(%rsp,%r9,1)
|
|
|
|
addq $8,%r9
|
2007-09-26 23:23:03 +00:00
|
|
|
|
2009-05-03 20:57:11 +00:00
|
|
|
LOCAL(vmInvoke_argumentTest):
|
2007-12-11 21:26:59 +00:00
|
|
|
cmpq %rcx,%r9
|
2009-05-03 20:57:11 +00:00
|
|
|
jb LOCAL(vmInvoke_argumentLoop)
|
2007-09-26 23:23:03 +00:00
|
|
|
|
|
|
|
// call function
|
2007-12-11 21:26:59 +00:00
|
|
|
call *%rsi
|
2007-09-26 23:23:03 +00:00
|
|
|
|
2009-05-29 01:13:15 +00:00
|
|
|
.globl GLOBAL(vmInvoke_returnAddress)
|
|
|
|
GLOBAL(vmInvoke_returnAddress):
|
2009-02-17 02:49:28 +00:00
|
|
|
// restore stack pointer
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
movq THREAD_SCRATCH(%rbx),%rsp
|
fix Thread.getStackTrace race conditions
Implementing Thread.getStackTrace is tricky. A thread may interrupt
another thread at any time to grab a stack trace, including while the
latter is executing Java code, JNI code, helper thunks, VM code, or
while transitioning between any of these.
To create a stack trace we use several context fields associated with
the target thread, including snapshots of the instruction pointer,
stack pointer, and frame pointer. These fields must be current,
accurate, and consistent with each other in order to get a reliable
trace. Otherwise, we risk crashing the VM by trying to walk garbage
stack frames or by misinterpreting the size and/or content of
legitimate frames.
This commit addresses sensitive transition points such as entering the
helper thunks which bridge the transitions from Java to native code
(where we must save the stack and frame registers for use from native
code) and stack unwinding (where we must atomically update the thread
context fields to indicate which frame we are unwinding to). When
grabbing a trace for another thread, we determine what kind of code we
caught the thread executing in and use that information to choose the
thread context values with which to begin the trace. See
MyProcessor::getStackTrace::Visitor::visit for details.
In order to atomically update the thread context fields, we do the
following:
1. Create a temporary "transition" object to serve as a staging area
and populate it with the new field values.
2. Update a transition pointer in the thread object to point to the
object created above. As long as this pointer is non-null,
interrupting threads will use the context values in the staging
object instead of those in the thread object.
3. Update the fields in the thread object.
4. Clear the transition pointer in the thread object.
We use a memory barrier between each of these steps to ensure they are
made visible to other threads in program order. See
MyThread::doTransition for details.
2010-06-16 01:10:48 +00:00
|
|
|
|
|
|
|
// 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):
|
2009-05-03 20:57:11 +00:00
|
|
|
|
2009-05-29 01:13:15 +00:00
|
|
|
#ifdef AVIAN_CONTINUATIONS
|
2009-07-26 02:48:36 +00:00
|
|
|
# include "continuations-x86.S"
|
2009-05-29 01:13:15 +00:00
|
|
|
#endif // AVIAN_CONTINUATIONS
|
2009-02-17 02:49:28 +00:00
|
|
|
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
// restore callee-saved registers
|
|
|
|
movq 0(%rsp),%rbx
|
|
|
|
movq 8(%rsp),%r12
|
|
|
|
movq 16(%rsp),%r13
|
|
|
|
movq 24(%rsp),%r14
|
|
|
|
movq 32(%rsp),%r15
|
2009-02-17 02:49:28 +00:00
|
|
|
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
addq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp
|
|
|
|
|
2009-02-17 02:49:28 +00:00
|
|
|
// return
|
2007-09-26 23:23:03 +00:00
|
|
|
popq %rbp
|
|
|
|
ret
|
2009-05-03 20:57:11 +00:00
|
|
|
|
2009-05-29 01:13:15 +00:00
|
|
|
.globl GLOBAL(vmJumpAndInvoke)
|
|
|
|
GLOBAL(vmJumpAndInvoke):
|
|
|
|
#ifdef AVIAN_CONTINUATIONS
|
2009-05-27 01:02:39 +00:00
|
|
|
// %rdi: thread
|
|
|
|
// %rsi: address
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
// %rdx: stack
|
|
|
|
// %rcx: argumentFootprint
|
|
|
|
// %r8 : arguments
|
|
|
|
// %r9 : frameSize
|
2009-05-29 01:54:32 +00:00
|
|
|
|
|
|
|
// allocate new frame, adding room for callee-saved registers
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
subq %r9,%rdx
|
|
|
|
subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rdx
|
2009-05-03 20:57:11 +00:00
|
|
|
|
2009-05-29 01:54:32 +00:00
|
|
|
movq %rdi,%rbx
|
2009-05-27 01:02:39 +00:00
|
|
|
|
2009-05-23 22:15:06 +00:00
|
|
|
// set return address
|
2009-12-03 06:15:27 +00:00
|
|
|
movq GLOBAL(vmInvoke_returnAddress)@GOTPCREL(%rip),%r10
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
movq %r10,(%rdx)
|
2009-05-23 22:15:06 +00:00
|
|
|
|
|
|
|
// copy arguments into place
|
|
|
|
movq $0,%r11
|
|
|
|
jmp LOCAL(vmJumpAndInvoke_argumentTest)
|
|
|
|
|
|
|
|
LOCAL(vmJumpAndInvoke_argumentLoop):
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
movq (%r8,%r11,1),%r10
|
|
|
|
movq %r10,8(%rdx,%r11,1)
|
2009-05-23 22:15:06 +00:00
|
|
|
addq $8,%r11
|
|
|
|
|
|
|
|
LOCAL(vmJumpAndInvoke_argumentTest):
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
cmpq %rcx,%r11
|
2009-05-23 22:15:06 +00:00
|
|
|
jb LOCAL(vmJumpAndInvoke_argumentLoop)
|
2009-05-24 17:18:17 +00:00
|
|
|
|
2009-05-29 01:54:32 +00:00
|
|
|
// the arguments have been copied, so we can set the real stack
|
|
|
|
// pointer now
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
movq %rdx,%rsp
|
2009-05-23 22:15:06 +00:00
|
|
|
|
2009-05-03 20:57:11 +00:00
|
|
|
jmp *%rsi
|
2009-05-29 01:13:15 +00:00
|
|
|
#else // not AVIAN_CONTINUATIONS
|
|
|
|
// vmJumpAndInvoke should only be called when continuations are
|
|
|
|
// enabled
|
|
|
|
int3
|
|
|
|
#endif // not AVIAN_CONTINUATIONS
|
2009-07-26 02:48:36 +00:00
|
|
|
|
2009-12-03 02:37:22 +00:00
|
|
|
#endif // not __MINGW32__ || __CYGWIN32__
|
2009-05-03 20:57:11 +00:00
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
#elif defined __i386__
|
2009-05-24 06:32:49 +00:00
|
|
|
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
#define THREAD_STACK 2148
|
|
|
|
#define THREAD_SCRATCH 2152
|
2011-01-26 00:22:43 +00:00
|
|
|
|
2011-02-01 18:01:28 +00:00
|
|
|
#ifdef AVIAN_USE_FRAME_POINTER
|
|
|
|
# define ALIGNMENT_ADJUSTMENT 0
|
|
|
|
#else
|
|
|
|
# define ALIGNMENT_ADJUSTMENT 12
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define CALLEE_SAVED_REGISTER_FOOTPRINT 16 + ALIGNMENT_ADJUSTMENT
|
2011-01-26 00:22:43 +00:00
|
|
|
|
2009-05-29 01:13:15 +00:00
|
|
|
.globl GLOBAL(vmInvoke)
|
|
|
|
GLOBAL(vmInvoke):
|
2007-09-26 23:23:03 +00:00
|
|
|
pushl %ebp
|
|
|
|
movl %esp,%ebp
|
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
// 8(%ebp): thread
|
|
|
|
// 12(%ebp): function
|
2009-02-17 02:49:28 +00:00
|
|
|
// 16(%ebp): arguments
|
|
|
|
// 20(%ebp): argumentFootprint
|
|
|
|
// 24(%ebp): frameSize
|
|
|
|
// 28(%ebp): returnType
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
|
|
|
|
// allocate stack space for callee-saved registers
|
2009-05-29 01:54:32 +00:00
|
|
|
subl $CALLEE_SAVED_REGISTER_FOOTPRINT,%esp
|
2009-02-17 02:49:28 +00:00
|
|
|
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
// remember this stack position, since we won't be able to rely on
|
|
|
|
// %rbp being restored when the call returns
|
|
|
|
movl 8(%ebp),%eax
|
|
|
|
movl %esp,THREAD_SCRATCH(%eax)
|
|
|
|
|
|
|
|
movl %ebx,0(%esp)
|
|
|
|
movl %esi,4(%esp)
|
|
|
|
movl %edi,8(%esp)
|
2009-02-17 02:49:28 +00:00
|
|
|
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
// allocate stack space for arguments
|
|
|
|
subl 24(%ebp),%esp
|
2007-12-11 21:26:59 +00:00
|
|
|
|
2009-02-16 15:21:12 +00:00
|
|
|
// we use ebx to hold the thread pointer, by convention
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
mov %eax,%ebx
|
2007-09-26 23:23:03 +00:00
|
|
|
|
|
|
|
// copy arguments into place
|
|
|
|
movl $0,%ecx
|
2009-02-17 02:49:28 +00:00
|
|
|
movl 16(%ebp),%edx
|
2009-05-24 06:32:49 +00:00
|
|
|
jmp LOCAL(vmInvoke_argumentTest)
|
2007-09-26 23:23:03 +00:00
|
|
|
|
2009-05-24 06:32:49 +00:00
|
|
|
LOCAL(vmInvoke_argumentLoop):
|
2009-02-17 02:49:28 +00:00
|
|
|
movl (%edx,%ecx,1),%eax
|
|
|
|
movl %eax,(%esp,%ecx,1)
|
|
|
|
addl $4,%ecx
|
2007-09-26 23:23:03 +00:00
|
|
|
|
2009-05-24 06:32:49 +00:00
|
|
|
LOCAL(vmInvoke_argumentTest):
|
2007-12-11 21:26:59 +00:00
|
|
|
cmpl 20(%ebp),%ecx
|
2009-05-24 06:32:49 +00:00
|
|
|
jb LOCAL(vmInvoke_argumentLoop)
|
2007-09-26 23:23:03 +00:00
|
|
|
|
|
|
|
// call function
|
2007-12-11 21:26:59 +00:00
|
|
|
call *12(%ebp)
|
2009-05-24 06:32:49 +00:00
|
|
|
|
2010-06-17 00:37:22 +00:00
|
|
|
.globl GLOBAL(vmInvoke_returnAddress)
|
|
|
|
GLOBAL(vmInvoke_returnAddress):
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
// restore stack pointer
|
|
|
|
movl THREAD_SCRATCH(%ebx),%esp
|
fix Thread.getStackTrace race conditions
Implementing Thread.getStackTrace is tricky. A thread may interrupt
another thread at any time to grab a stack trace, including while the
latter is executing Java code, JNI code, helper thunks, VM code, or
while transitioning between any of these.
To create a stack trace we use several context fields associated with
the target thread, including snapshots of the instruction pointer,
stack pointer, and frame pointer. These fields must be current,
accurate, and consistent with each other in order to get a reliable
trace. Otherwise, we risk crashing the VM by trying to walk garbage
stack frames or by misinterpreting the size and/or content of
legitimate frames.
This commit addresses sensitive transition points such as entering the
helper thunks which bridge the transitions from Java to native code
(where we must save the stack and frame registers for use from native
code) and stack unwinding (where we must atomically update the thread
context fields to indicate which frame we are unwinding to). When
grabbing a trace for another thread, we determine what kind of code we
caught the thread executing in and use that information to choose the
thread context values with which to begin the trace. See
MyProcessor::getStackTrace::Visitor::visit for details.
In order to atomically update the thread context fields, we do the
following:
1. Create a temporary "transition" object to serve as a staging area
and populate it with the new field values.
2. Update a transition pointer in the thread object to point to the
object created above. As long as this pointer is non-null,
interrupting threads will use the context values in the staging
object instead of those in the thread object.
3. Update the fields in the thread object.
4. Clear the transition pointer in the thread object.
We use a memory barrier between each of these steps to ensure they are
made visible to other threads in program order. See
MyThread::doTransition for details.
2010-06-16 01:10:48 +00:00
|
|
|
|
|
|
|
// 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.
|
2010-06-16 01:47:06 +00:00
|
|
|
movl $0,THREAD_STACK(%ebx)
|
fix Thread.getStackTrace race conditions
Implementing Thread.getStackTrace is tricky. A thread may interrupt
another thread at any time to grab a stack trace, including while the
latter is executing Java code, JNI code, helper thunks, VM code, or
while transitioning between any of these.
To create a stack trace we use several context fields associated with
the target thread, including snapshots of the instruction pointer,
stack pointer, and frame pointer. These fields must be current,
accurate, and consistent with each other in order to get a reliable
trace. Otherwise, we risk crashing the VM by trying to walk garbage
stack frames or by misinterpreting the size and/or content of
legitimate frames.
This commit addresses sensitive transition points such as entering the
helper thunks which bridge the transitions from Java to native code
(where we must save the stack and frame registers for use from native
code) and stack unwinding (where we must atomically update the thread
context fields to indicate which frame we are unwinding to). When
grabbing a trace for another thread, we determine what kind of code we
caught the thread executing in and use that information to choose the
thread context values with which to begin the trace. See
MyProcessor::getStackTrace::Visitor::visit for details.
In order to atomically update the thread context fields, we do the
following:
1. Create a temporary "transition" object to serve as a staging area
and populate it with the new field values.
2. Update a transition pointer in the thread object to point to the
object created above. As long as this pointer is non-null,
interrupting threads will use the context values in the staging
object instead of those in the thread object.
3. Update the fields in the thread object.
4. Clear the transition pointer in the thread object.
We use a memory barrier between each of these steps to ensure they are
made visible to other threads in program order. See
MyThread::doTransition for details.
2010-06-16 01:10:48 +00:00
|
|
|
|
|
|
|
.globl GLOBAL(vmInvoke_safeStack)
|
|
|
|
GLOBAL(vmInvoke_safeStack):
|
2007-09-26 23:23:03 +00:00
|
|
|
|
2009-05-29 01:13:15 +00:00
|
|
|
#ifdef AVIAN_CONTINUATIONS
|
2009-07-26 02:48:36 +00:00
|
|
|
# include "continuations-x86.S"
|
2009-05-29 01:13:15 +00:00
|
|
|
#endif // AVIAN_CONTINUATIONS
|
|
|
|
|
2009-05-24 06:32:49 +00:00
|
|
|
// restore callee-saved registers
|
2009-03-19 14:44:08 +00:00
|
|
|
movl 0(%esp),%ebx
|
|
|
|
movl 4(%esp),%esi
|
|
|
|
movl 8(%esp),%edi
|
2007-09-26 23:23:03 +00:00
|
|
|
|
2009-05-29 01:54:32 +00:00
|
|
|
addl $CALLEE_SAVED_REGISTER_FOOTPRINT,%esp
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
|
|
|
|
// handle return value based on expected type
|
|
|
|
movl 28(%esp),%ecx
|
2009-03-19 14:44:08 +00:00
|
|
|
|
2009-05-24 06:32:49 +00:00
|
|
|
LOCAL(vmInvoke_void):
|
2007-09-26 23:23:03 +00:00
|
|
|
cmpl $VOID_TYPE,%ecx
|
2009-05-24 06:32:49 +00:00
|
|
|
jne LOCAL(vmInvoke_int64)
|
|
|
|
jmp LOCAL(vmInvoke_return)
|
2007-09-26 23:23:03 +00:00
|
|
|
|
2009-05-24 06:32:49 +00:00
|
|
|
LOCAL(vmInvoke_int64):
|
2007-09-26 23:23:03 +00:00
|
|
|
cmpl $INT64_TYPE,%ecx
|
2009-05-24 06:32:49 +00:00
|
|
|
jne LOCAL(vmInvoke_int32)
|
|
|
|
jmp LOCAL(vmInvoke_return)
|
2007-09-26 23:23:03 +00:00
|
|
|
|
2009-05-24 06:32:49 +00:00
|
|
|
LOCAL(vmInvoke_int32):
|
2007-09-26 23:23:03 +00:00
|
|
|
movl $0,%edx
|
|
|
|
|
2009-05-24 06:32:49 +00:00
|
|
|
LOCAL(vmInvoke_return):
|
2007-09-26 23:23:03 +00:00
|
|
|
popl %ebp
|
|
|
|
ret
|
2009-05-24 06:32:49 +00:00
|
|
|
|
|
|
|
LOCAL(getPC):
|
|
|
|
movl (%esp),%esi
|
|
|
|
ret
|
|
|
|
|
2009-05-29 01:13:15 +00:00
|
|
|
.globl GLOBAL(vmJumpAndInvoke)
|
|
|
|
GLOBAL(vmJumpAndInvoke):
|
|
|
|
#ifdef AVIAN_CONTINUATIONS
|
2009-05-24 17:18:17 +00:00
|
|
|
// 4(%esp): thread
|
|
|
|
// 8(%esp): address
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
// 12(%esp): stack
|
|
|
|
// 16(%esp): argumentFootprint
|
|
|
|
// 20(%esp): arguments
|
|
|
|
// 24(%esp): frameSize
|
2009-05-24 06:32:49 +00:00
|
|
|
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
movl 12(%esp),%ecx
|
2009-05-29 01:54:32 +00:00
|
|
|
|
|
|
|
// allocate new frame, adding room for callee-saved registers
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
subl 24(%esp),%ecx
|
2009-05-29 01:54:32 +00:00
|
|
|
subl $CALLEE_SAVED_REGISTER_FOOTPRINT,%ecx
|
|
|
|
|
|
|
|
movl 4(%esp),%ebx
|
2009-05-24 06:32:49 +00:00
|
|
|
|
|
|
|
// set return address
|
2009-12-03 02:37:22 +00:00
|
|
|
#if defined __MINGW32__ || defined __CYGWIN32__
|
2010-06-25 01:12:15 +00:00
|
|
|
movl $GLOBAL(vmInvoke_returnAddress),%esi
|
2009-12-03 02:29:57 +00:00
|
|
|
#else
|
2009-05-24 06:32:49 +00:00
|
|
|
call LOCAL(getPC)
|
2009-12-03 06:15:27 +00:00
|
|
|
# if defined __APPLE__
|
|
|
|
LOCAL(vmJumpAndInvoke_offset):
|
2010-06-25 01:12:15 +00:00
|
|
|
leal GLOBAL(vmInvoke_returnAddress)-LOCAL(vmJumpAndInvoke_offset)(%esi),%esi
|
2009-12-03 06:15:27 +00:00
|
|
|
# else
|
2009-05-24 06:32:49 +00:00
|
|
|
addl $_GLOBAL_OFFSET_TABLE_,%esi
|
2010-06-25 01:12:15 +00:00
|
|
|
movl GLOBAL(vmInvoke_returnAddress)@GOT(%esi),%esi
|
2009-12-03 06:15:27 +00:00
|
|
|
# endif
|
2009-12-03 02:29:57 +00:00
|
|
|
#endif
|
2009-05-24 17:18:17 +00:00
|
|
|
movl %esi,(%ecx)
|
2009-05-24 06:32:49 +00:00
|
|
|
|
|
|
|
// copy arguments into place
|
2009-05-24 17:18:17 +00:00
|
|
|
movl $0,%esi
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
movl 16(%esp),%edx
|
|
|
|
movl 20(%esp),%eax
|
2009-05-24 06:32:49 +00:00
|
|
|
jmp LOCAL(vmJumpAndInvoke_argumentTest)
|
|
|
|
|
|
|
|
LOCAL(vmJumpAndInvoke_argumentLoop):
|
2009-05-24 17:18:17 +00:00
|
|
|
movl (%eax,%esi,1),%edi
|
|
|
|
movl %edi,4(%ecx,%esi,1)
|
|
|
|
addl $4,%esi
|
2009-05-24 06:32:49 +00:00
|
|
|
|
|
|
|
LOCAL(vmJumpAndInvoke_argumentTest):
|
2009-05-24 17:18:17 +00:00
|
|
|
cmpl %edx,%esi
|
2009-05-24 06:32:49 +00:00
|
|
|
jb LOCAL(vmJumpAndInvoke_argumentLoop)
|
|
|
|
|
2009-05-24 17:18:17 +00:00
|
|
|
movl 8(%esp),%esi
|
2009-05-29 01:54:32 +00:00
|
|
|
|
|
|
|
// the arguments have been copied, so we can set the real stack
|
|
|
|
// pointer now
|
2009-05-24 17:18:17 +00:00
|
|
|
movl %ecx,%esp
|
|
|
|
|
2009-05-24 06:32:49 +00:00
|
|
|
jmp *%esi
|
2009-05-29 01:13:15 +00:00
|
|
|
#else // not AVIAN_CONTINUATIONS
|
|
|
|
// vmJumpAndInvoke should only be called when continuations are
|
|
|
|
// enabled
|
|
|
|
int3
|
|
|
|
#endif // AVIAN_CONTINUATIONS
|
2007-10-04 00:41:54 +00:00
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
#else
|
2009-06-11 15:48:27 +00:00
|
|
|
#error unsupported architecture
|
|
|
|
#endif //def __x86_64__
|