#include <string.h>
#include "j9.h"
#include "jitprotos.h"
#include "rommeth.h"
#include "stackwalk.h"
#include "ut_j9codertvm.h"
#if defined(J9VM_JIT_DYNAMIC_LOOP_TRANSFER)
static UDATA
dltIterator(J9VMThread * currentThread, J9StackWalkState * walkState)
{
if (walkState->framesWalked == 2) {
walkState->userData1 = walkState->unwindSP;
walkState->userData2 = walkState->arg0EA;
walkState->userData3 = walkState->method;
}
return J9_STACKWALK_KEEP_ITERATING;
}
void *
setUpForDLT(J9VMThread * currentThread, J9StackWalkState * walkState)
{
J9JavaVM * vm = currentThread->javaVM;
J9DLTInformationBlock * dltBlock = &(currentThread->dltBlock);
UDATA * onStackTemps;
UDATA * copiedTemps;
void * dltEntry;
void * currentFrame;
UDATA * currentA0;
J9Method * currentMethod;
J9ROMMethod * romMethod;
UDATA argTempCount;
UDATA argCount;
J9JITExceptionTable * metaData;
UDATA * checkSP;
J9MonitorEnterRecord * enterRecord;
UDATA * relativeA0;
Trc_DLT_setUpForDLT_Entry(currentThread);
dltEntry = dltBlock->dltEntry;
dltBlock->dltEntry = NULL;
retry:
walkState->skipCount = 0;
walkState->maxFrames = 3;
walkState->walkThread = currentThread;
walkState->frameWalkFunction = dltIterator;
walkState->flags = J9_STACKWALK_ITERATE_FRAMES | J9_STACKWALK_COUNT_SPECIFIED | J9_STACKWALK_MAINTAIN_REGISTER_MAP;
vm->walkStackFrames(currentThread, walkState);
if (walkState->framesWalked != 3) {
Trc_DLT_setUpForDLT_Exit_MalformedStack(currentThread);
return NULL;
}
currentFrame = walkState->userData1;
currentA0 = walkState->userData2;
currentMethod = walkState->userData3;
metaData = jitGetExceptionTableFromPC(currentThread, (UDATA) dltEntry);
checkSP = walkState->sp - (metaData->totalFrameSize + J9SW_JIT_STACK_SLOTS_USED_BY_CALL);
if (checkSP < currentThread->stackOverflowMark2) {
#if defined(J9VM_INTERP_GROWABLE_STACKS)
if ((currentThread->privateFlags & J9_PRIVATE_FLAGS_STACK_OVERFLOW) == 0) {
J9JavaStack * stack = currentThread->stackObject;
UDATA bytesRequired = (UDATA)stack->end - (UDATA)checkSP;
UDATA maxSize = vm->stackSize;
if (bytesRequired <= maxSize) {
bytesRequired += vm->stackSizeIncrement;
if (bytesRequired > maxSize) {
bytesRequired = maxSize;
}
if (vm->internalVMFunctions->growJavaStack(currentThread, bytesRequired) == 0) {
goto retry;
}
}
}
#endif
Trc_DLT_setUpForDLT_Exit_StackOverflow(currentThread);
return NULL;
}
romMethod = J9_ROM_METHOD_FROM_RAM_METHOD(currentMethod);
argTempCount = romMethod->tempCount;
if (romMethod->modifiers & J9AccSynchronized) {
++argTempCount;
} else if (J9ROMMETHOD_IS_NON_EMPTY_OBJECT_CONSTRUCTOR(romMethod)) {
++argTempCount;
}
argCount = romMethod->argCount;
argTempCount += argCount;
copiedTemps = dltBlock->inlineTempsBuffer;
if (argTempCount > (sizeof(dltBlock->inlineTempsBuffer) / sizeof(UDATA))) {
PORT_ACCESS_FROM_JAVAVM(vm);
copiedTemps = j9mem_allocate_memory(argTempCount * sizeof(UDATA), OMRMEM_CATEGORY_JIT);
if (copiedTemps == NULL) {
Trc_DLT_setUpForDLT_Exit_FailedTempAllocate(currentThread);
return NULL;
}
}
onStackTemps = currentA0 + 1 - argTempCount;
memcpy(copiedTemps, onStackTemps, argTempCount * sizeof(UDATA));
dltBlock->temps = copiedTemps;
if (walkState->jitInfo != NULL) {
J9I2JState * currentState;
Trc_DLT_setUpForDLT_Jitted_Caller(currentThread);
walkState->userData1 = ((J9SFJ2IFrame *) currentFrame)->returnAddress;
currentState = walkState->i2jState;
if (currentState != NULL) {
J9I2JState * elsState = &(currentThread->entryLocalStorage->i2jState);
elsState->pc = currentState->pc;
elsState->literals = currentState->literals;
elsState->a0 = currentState->a0;
elsState->returnSP = currentState->returnSP;
}
currentThread->j2iFrame = walkState->j2iFrame;
} else {
J9I2JState * elsState = &(currentThread->entryLocalStorage->i2jState);
UDATA * returnSP;
UDATA * sp;
U_32 infoWord = ((U_32 *) dltEntry)[-1];
Trc_DLT_setUpForDLT_Bytecode_Caller(currentThread);
if ((*(UDATA *) currentFrame) & J9_STACK_FLAGS_J2_IFRAME) {
Trc_DLT_setUpForDLT_Exit_MalformedStack(currentThread);
return NULL;
}
walkState->userData1 = ((void **) vm->jitConfig->i2jReturnTable)[infoWord & 0x000F];
elsState->a0 = walkState->arg0EA;
elsState->pc = walkState->pc;
elsState->literals = walkState->method;
sp = walkState->sp;
returnSP = sp + argCount;
returnSP = (UDATA *) ((UDATA) returnSP | J9_STACK_FLAGS_J2_IFRAME);
if (J9_ARE_ANY_BITS_SET((UDATA)sp, sizeof(UDATA))) {
Trc_DLT_setUpForDLT_Aligning_Arguments(currentThread);
memmove((walkState->sp = sp - 1), sp, argCount * sizeof(UDATA));
}
elsState->returnSP = returnSP;
}
currentThread->jitStackFrameFlags = 0;
enterRecord = currentThread->monitorEnterRecords;
relativeA0 = CONVERT_TO_RELATIVE_STACK_OFFSET(currentThread, currentA0);
while ((enterRecord != NULL) && (enterRecord->arg0EA == relativeA0)) {
J9MonitorEnterRecord * next = enterRecord->next;
Trc_DLT_setUpForDLT_Discard_Enter_Record(currentThread, enterRecord, enterRecord->object);
pool_removeElement(currentThread->monitorEnterRecordPool, enterRecord);
enterRecord = next;
}
currentThread->monitorEnterRecords = enterRecord;
Trc_DLT_setUpForDLT_Exit_Success(currentThread, dltEntry);
return dltEntry;
}
#endif