corda/src/compile-x86.S

478 lines
11 KiB
ArmAsm
Raw Normal View History

2009-03-15 18:02:36 +00:00
/* Copyright (c) 2008-2009, Avian Contributors
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. */
#include "types.h"
#define LOCAL(x) .L##x
#if defined __APPLE__ || defined __MINGW32__ || defined __CYGWIN32__
# define GLOBAL(x) _##x
#else
# define GLOBAL(x) x
#endif
.text
#ifdef __x86_64__
#define THREAD_STACK 2216
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
#if defined __MINGW32__ || defined __CYGWIN32__
#define CALLEE_SAVED_REGISTER_FOOTPRINT 64
.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)
// allocate stack space, adding room for callee-saved registers
movl 48(%rbp),%eax
subq %rax,%rsp
subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp
2009-06-11 15:48:27 +00:00
// save callee-saved registers
movq %rsp,%r11
addq %rax,%r11
movq %rbx,0(%r11)
movq %r12,8(%r11)
movq %r13,16(%r11)
movq %r14,24(%r11)
movq %r15,32(%r11)
movq %rsi,40(%r11)
movq %rdi,48(%r11)
// we use rbx to hold the thread pointer, by convention
mov %rcx,%rbx
// copy arguments into place
movq $0,%r11
jmp LOCAL(vmInvoke_argumentTest)
2009-06-11 15:48:27 +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
LOCAL(vmInvoke_argumentTest):
2009-06-11 15:48:27 +00:00
cmpq %r9,%r11
jb LOCAL(vmInvoke_argumentLoop)
2009-06-11 15:48:27 +00:00
// call function
call *%rdx
.globl GLOBAL(vmInvoke_returnAddress)
GLOBAL(vmInvoke_returnAddress):
2009-06-11 15:48:27 +00:00
// restore stack pointer
movq %rbp,%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):
#ifdef AVIAN_CONTINUATIONS
# include "continuations-x86.S"
#endif // AVIAN_CONTINUATIONS
// restore callee-saved registers (below the stack pointer, but in
// the red zone)
2009-06-11 15:48:27 +00:00
movq %rsp,%r11
subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%r11
2009-06-11 15:48:27 +00:00
movq 0(%r11),%rbx
movq 8(%r11),%r12
movq 16(%r11),%r13
movq 24(%r11),%r14
movq 32(%r11),%r15
movq 40(%r11),%rsi
movq 48(%r11),%rdi
// return
popq %rbp
ret
.globl GLOBAL(vmJumpAndInvoke)
GLOBAL(vmJumpAndInvoke):
#ifdef AVIAN_CONTINUATIONS
// %rcx: thread
// %rdx: address
// %r8 : base
// %r9 : (unused)
// 40(%rsp): argumentFootprint
// 48(%rsp): arguments
// 56(%rsp): frameSize
movq %r8,%rbp
// restore (pseudo)-stack pointer (we don't want to touch the real
// stack pointer, since we haven't copied the arguments yet)
movq %rbp,%r9
// allocate new frame, adding room for callee-saved registers
movl 56(%rsp),%eax
subq %rax,%r9
subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%r9
2009-05-05 01:04:17 +00:00
movq %rcx,%rbx
// set return address
leaq GLOBAL(vmInvoke_returnAddress)(%rip),%r10
movq %r10,(%r9)
2009-06-11 15:48:27 +00:00
// copy arguments into place
movq $0,%r11
movl 48(%rsp),%r8d
movl 40(%rsp),%eax
jmp LOCAL(vmJumpAndInvoke_argumentTest)
LOCAL(vmJumpAndInvoke_argumentLoop):
movq (%r8,%r11,1),%r10
movq %r10,8(%r9,%r11,1)
addq $8,%r11
LOCAL(vmJumpAndInvoke_argumentTest):
cmpq %rax,%r11
jb LOCAL(vmJumpAndInvoke_argumentLoop)
// the arguments have been copied, so we can set the real stack
// pointer now
movq %r9,%rsp
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
#else // not __MINGW32__ || __CYGWIN32__
2009-05-29 01:54:32 +00:00
#define CALLEE_SAVED_REGISTER_FOOTPRINT 48
.globl GLOBAL(vmInvoke)
GLOBAL(vmInvoke):
pushq %rbp
movq %rsp,%rbp
2007-12-11 21:26:59 +00:00
// %rdi: thread
// %rsi: function
// %rdx: arguments
// %rcx: argumentFootprint
// %r8 : frameSize
// %r9 : returnType (ignored)
// allocate stack space, adding room for callee-saved registers
2009-05-29 01:54:32 +00:00
subq %r8,%rsp
subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rsp
// save callee-saved registers
movq %rsp,%r9
addq %r8,%r9
movq %rbx,0(%r9)
movq %r12,8(%r9)
movq %r13,16(%r9)
movq %r14,24(%r9)
movq %r15,32(%r9)
2007-12-11 21:26:59 +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
// 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)
2009-05-03 20:57:11 +00:00
LOCAL(vmInvoke_argumentLoop):
movq (%rdx,%r9,1),%r8
movq %r8,(%rsp,%r9,1)
addq $8,%r9
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)
// call function
2007-12-11 21:26:59 +00:00
call *%rsi
.globl GLOBAL(vmInvoke_returnAddress)
GLOBAL(vmInvoke_returnAddress):
// restore stack pointer
movq %rbp,%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
#ifdef AVIAN_CONTINUATIONS
# include "continuations-x86.S"
#endif // AVIAN_CONTINUATIONS
2009-05-29 01:54:32 +00:00
// restore callee-saved registers (below the stack pointer, but in
// the red zone)
movq %rsp,%r9
2009-05-29 01:54:32 +00:00
subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%r9
movq 0(%r9),%rbx
movq 8(%r9),%r12
movq 16(%r9),%r13
movq 24(%r9),%r14
movq 32(%r9),%r15
// return
popq %rbp
ret
2009-05-03 20:57:11 +00:00
.globl GLOBAL(vmJumpAndInvoke)
GLOBAL(vmJumpAndInvoke):
#ifdef AVIAN_CONTINUATIONS
// %rdi: thread
// %rsi: address
// %rdx: base
2009-05-29 01:54:32 +00:00
// %rcx: (unused)
// %r8 : argumentFootprint
// %r9 : arguments
// 8(%rsp): frameSize
movq %rdx,%rbp
2009-05-29 01:54:32 +00:00
// restore (pseudo)-stack pointer (we don't want to touch the real
// stack pointer, since we haven't copied the arguments yet)
movq %rbp,%rcx
// allocate new frame, adding room for callee-saved registers
movl 8(%rsp),%eax
subq %rax,%rcx
subq $CALLEE_SAVED_REGISTER_FOOTPRINT,%rcx
2009-05-03 20:57:11 +00:00
2009-05-29 01:54:32 +00:00
movq %rdi,%rbx
2009-05-23 22:15:06 +00:00
// set return address
movq GLOBAL(vmInvoke_returnAddress)@GOTPCREL(%rip),%r10
2009-05-24 17:18:17 +00:00
movq %r10,(%rcx)
2009-05-23 22:15:06 +00:00
// copy arguments into place
movq $0,%r11
jmp LOCAL(vmJumpAndInvoke_argumentTest)
LOCAL(vmJumpAndInvoke_argumentLoop):
movq (%r9,%r11,1),%r10
2009-05-24 17:18:17 +00:00
movq %r10,8(%rcx,%r11,1)
2009-05-23 22:15:06 +00:00
addq $8,%r11
LOCAL(vmJumpAndInvoke_argumentTest):
cmpq %r8,%r11
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
2009-05-24 17:18:17 +00:00
movq %rcx,%rsp
2009-05-23 22:15:06 +00:00
2009-05-03 20:57:11 +00:00
jmp *%rsi
#else // not AVIAN_CONTINUATIONS
// vmJumpAndInvoke should only be called when continuations are
// enabled
int3
#endif // not AVIAN_CONTINUATIONS
#endif // not __MINGW32__ || __CYGWIN32__
2009-05-03 20:57:11 +00:00
#elif defined __i386__
#define THREAD_STACK 2144
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
2009-05-29 01:54:32 +00:00
#define CALLEE_SAVED_REGISTER_FOOTPRINT 16
.globl GLOBAL(vmInvoke)
GLOBAL(vmInvoke):
pushl %ebp
movl %esp,%ebp
2007-12-11 21:26:59 +00:00
// 8(%ebp): thread
// 12(%ebp): function
// 16(%ebp): arguments
// 20(%ebp): argumentFootprint
// 24(%ebp): frameSize
// 28(%ebp): returnType
// allocate stack space, adding room for callee-saved registers
subl 24(%ebp),%esp
2009-05-29 01:54:32 +00:00
subl $CALLEE_SAVED_REGISTER_FOOTPRINT,%esp
// save callee-saved registers
movl %esp,%ecx
addl 24(%ebp),%ecx
movl %ebx,0(%ecx)
movl %esi,4(%ecx)
movl %edi,8(%ecx)
2007-12-11 21:26:59 +00:00
// we use ebx to hold the thread pointer, by convention
mov 8(%ebp),%ebx
// copy arguments into place
movl $0,%ecx
movl 16(%ebp),%edx
jmp LOCAL(vmInvoke_argumentTest)
LOCAL(vmInvoke_argumentLoop):
movl (%edx,%ecx,1),%eax
movl %eax,(%esp,%ecx,1)
addl $4,%ecx
LOCAL(vmInvoke_argumentTest):
2007-12-11 21:26:59 +00:00
cmpl 20(%ebp),%ecx
jb LOCAL(vmInvoke_argumentLoop)
// call function
2007-12-11 21:26:59 +00:00
call *12(%ebp)
2010-06-17 00:37:22 +00:00
.globl GLOBAL(vmInvoke_returnAddress)
GLOBAL(vmInvoke_returnAddress):
2009-05-29 01:54:32 +00:00
// restore stack pointer, preserving the area containing saved
// registers
movl %ebp,%ecx
2009-05-29 01:54:32 +00:00
subl $CALLEE_SAVED_REGISTER_FOOTPRINT,%ecx
movl %ecx,%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):
#ifdef AVIAN_CONTINUATIONS
# include "continuations-x86.S"
#endif // AVIAN_CONTINUATIONS
// restore callee-saved registers
movl 0(%esp),%ebx
movl 4(%esp),%esi
movl 8(%esp),%edi
// handle return value based on expected type
movl 28(%ebp),%ecx
2009-05-29 01:54:32 +00:00
addl $CALLEE_SAVED_REGISTER_FOOTPRINT,%esp
LOCAL(vmInvoke_void):
cmpl $VOID_TYPE,%ecx
jne LOCAL(vmInvoke_int64)
jmp LOCAL(vmInvoke_return)
LOCAL(vmInvoke_int64):
cmpl $INT64_TYPE,%ecx
jne LOCAL(vmInvoke_int32)
jmp LOCAL(vmInvoke_return)
LOCAL(vmInvoke_int32):
movl $0,%edx
LOCAL(vmInvoke_return):
popl %ebp
ret
LOCAL(getPC):
movl (%esp),%esi
ret
.globl GLOBAL(vmJumpAndInvoke)
GLOBAL(vmJumpAndInvoke):
#ifdef AVIAN_CONTINUATIONS
2009-05-24 17:18:17 +00:00
// 4(%esp): thread
// 8(%esp): address
// 12(%esp): base
2009-05-29 01:54:32 +00:00
// 16(%esp): (unused)
2009-05-24 17:18:17 +00:00
// 20(%esp): argumentFootprint
// 24(%esp): arguments
// 28(%esp): frameSize
movl 12(%esp),%ebp
2009-05-29 01:54:32 +00:00
// restore (pseudo)-stack pointer (we don't want to touch the real
// stack pointer, since we haven't copied the arguments yet)
movl %ebp,%ecx
// allocate new frame, adding room for callee-saved registers
subl 28(%esp),%ecx
2009-05-29 01:54:32 +00:00
subl $CALLEE_SAVED_REGISTER_FOOTPRINT,%ecx
movl 4(%esp),%ebx
// set return address
#if defined __MINGW32__ || defined __CYGWIN32__
movl $GLOBAL(vmInvoke_returnAddress),%esi
#else
call LOCAL(getPC)
# if defined __APPLE__
LOCAL(vmJumpAndInvoke_offset):
leal GLOBAL(vmInvoke_returnAddress)-LOCAL(vmJumpAndInvoke_offset)(%esi),%esi
# else
addl $_GLOBAL_OFFSET_TABLE_,%esi
movl GLOBAL(vmInvoke_returnAddress)@GOT(%esi),%esi
# endif
#endif
2009-05-24 17:18:17 +00:00
movl %esi,(%ecx)
// copy arguments into place
2009-05-24 17:18:17 +00:00
movl $0,%esi
movl 20(%esp),%edx
movl 24(%esp),%eax
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
LOCAL(vmJumpAndInvoke_argumentTest):
2009-05-24 17:18:17 +00:00
cmpl %edx,%esi
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
jmp *%esi
#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
#else
2009-06-11 15:48:27 +00:00
#error unsupported architecture
#endif //def __x86_64__