/** * Empty the call and value stacks, ready to call java from the firmware */ void empty_stacks() { // smash the stacks back to the initial state currentThread->stackFrameIndex = 0; init_sp_pv(); update_stack_frame(current_stackframe()); }
void do_return (byte numWords) { StackFrame *stackFrame; STACKWORD *fromStackPtr; stackFrame = current_stackframe(); #if DEBUG_BYTECODE printf ("\n------ return ----- %d ------------------\n\n", stackFrame->methodRecord->signatureId); #endif #if DEBUG_METHODS printf ("do_return: method: %d # num. words: %d\n", stackFrame->methodRecord->signatureId, numWords); #endif #ifdef VERIFY assert (stackFrame != null, LANGUAGE3); #endif if (stackFrame->monitor != null) exit_monitor (currentThread, stackFrame->monitor); #if DEBUG_THREADS || DEBUG_METHODS printf ("do_return: stack frame array size: %d\n", currentThread->stackFrameArraySize); #endif if (currentThread->stackFrameArraySize == 1) { #if DEBUG_METHODS printf ("do_return: thread is done: %d\n", (int) currentThread); #endif currentThread->state = DEAD; schedule_request (REQUEST_SWITCH_THREAD); return; } // Place source ptr below data to be copied up the stack fromStackPtr = get_stack_ptr_at (numWords); // Pop stack frame currentThread->stackFrameArraySize--; stackFrame--; // Assign registers update_registers (stackFrame); #if DEBUG_METHODS printf ("do_return: stack reset to:\n"); printf ("-- stack ptr = %d\n", (int) get_stack_ptr()); #endif while (numWords--) { push_word (*(++fromStackPtr)); } }
/** * Calls static initializer if necessary before * dispatching with dispatch_special(). * @param retAddr Return bytecode address. * @param btAddr Backtrack bytecode address (in case * static initializer is executed). */ void dispatch_special_checked (byte classIndex, byte methodIndex, byte *retAddr, byte *btAddr) { ClassRecord *classRecord; MethodRecord *methodRecord; #if DEBUG_METHODS printf ("dispatch_special_checked: %d, %d, %d, %d\n", classIndex, methodIndex, (int) retAddr, (int) btAddr); #endif // If we need to run the initializer then the real method will get called // later, when we re-run the current instruction. classRecord = get_class_record (classIndex); if (!is_initialized_idx (classIndex)) if (dispatch_static_initializer (classRecord, btAddr) != EXEC_CONTINUE) return; methodRecord = get_method_record (classRecord, methodIndex); if(dispatch_special (methodRecord, retAddr)) { if (is_synchronized(methodRecord)) { if (!is_static(methodRecord)) { Object *ref = (Object *)curLocalsBase[0]; current_stackframe()->monitor = ref; enter_monitor (currentThread, ref); } else { Object *ref = (Object *)classRecord; current_stackframe()->monitor = ref; enter_monitor (currentThread, ref); } } } }
/** * Perform a return from a method call. Clean up the stack, setup * the return of any results, release any monitor and finally set the * PC for the return address. */ void do_return (int numWords) { StackFrame *stackFrame; STACKWORD *fromStackPtr; stackFrame = current_stackframe(); #if DEBUG_BYTECODE printf ("\n------ return ----- %d ------------------\n\n", stackFrame->methodRecord->signatureId); #endif #if DEBUG_METHODS printf ("do_return: method: %d # num. words: %d\n", stackFrame->methodRecord->signatureId, numWords); #endif #ifdef VERIFY assert (stackFrame != null, LANGUAGE3); #endif if (stackFrame->monitor != null) { // if this was a class init then mark the class as now complete if (stackFrame->methodRecord->signatureId == _6clinit_7_4_5V) set_init_state((ClassRecord *)(stackFrame->monitor), C_INITIALIZED); exit_monitor (currentThread, stackFrame->monitor); } #if DEBUG_THREADS || DEBUG_METHODS printf ("do_return: stack frame array size: %d\n", currentThread->stackFrameIndex); #endif // Place source ptr below data to be copied up the stack fromStackPtr = get_stack_ptr_at_cur(numWords); // Pop stack frame currentThread->stackFrameIndex--; stackFrame--; // Assign registers update_registers (stackFrame); #if DEBUG_METHODS printf ("do_return: stack reset to:\n"); //printf ("-- stack ptr = %d\n", (int) get_stack_ptr()); #endif while (numWords--) { push_word_cur (*(++fromStackPtr)); } }
void dispatch_virtual (Object *ref, int signature, byte *retAddr) { ClassRecord *classRecord; MethodRecord *methodRecord; int classIndex; #if DEBUG_METHODS printf("dispatch_virtual %d\n", signature); #endif if (ref == JNULL) { throw_new_exception (JAVA_LANG_NULLPOINTEREXCEPTION); return; } // When calling methods on arrays, we use the methods for the Object class... classIndex = get_class_index(ref); LABEL_METHODLOOKUP: classRecord = get_class_record (classIndex); methodRecord = find_method (classRecord, signature); if (methodRecord == null) { #if SAFE if (classIndex == JAVA_LANG_OBJECT) { throw_new_exception (JAVA_LANG_NOSUCHMETHODERROR); return; } #endif classIndex = classRecord->parentClass; goto LABEL_METHODLOOKUP; } if (dispatch_special (methodRecord, retAddr)) { if (is_synchronized(methodRecord)) { current_stackframe()->monitor = ref; enter_monitor (currentThread, ref); } } }
void dispatch_virtual (Object *ref, TWOBYTES signature, byte *retAddr) { MethodRecord *auxMethodRecord; byte auxByte; #if DEBUG_METHODS printf("dispatch_virtual %d\n", signature); #endif if (ref == JNULL) { throw_exception (nullPointerException); return; } auxByte = get_class_index(ref); LABEL_METHODLOOKUP: tempClassRecord = get_class_record (auxByte); auxMethodRecord = find_method (tempClassRecord, signature); if (auxMethodRecord == null) { #if SAFE if (auxByte == JAVA_LANG_OBJECT) { throw_exception (noSuchMethodError); return; } #endif auxByte = tempClassRecord->parentClass; goto LABEL_METHODLOOKUP; } if (dispatch_special (auxMethodRecord, retAddr)) { if (is_synchronized(auxMethodRecord)) { current_stackframe()->monitor = ref; enter_monitor (currentThread, ref); } } }
/** * @return false iff all threads are dead. */ void throw_exception (Object *exception) { Thread *auxThread; #ifdef VERIFY assert (exception != null, EXCEPTIONS0); #endif // VERIFY #if DEBUG_EXCEPTIONS printf("Throw exception\n"); #endif if (currentThread == null) { // No threads have started probably return; } else if (exception == interruptedException) { // Throwing an interrupted exception clears the flag currentThread->interruptState = INTERRUPT_CLEARED; } #ifdef VERIFY assert (currentThread->state > DEAD, EXCEPTIONS1); #endif // VERIFY gExceptionPc = pc; gExcepMethodRec = null; #if 0 trace (-1, get_class_index(exception), 3); #endif LABEL_PROPAGATE: tempStackFrame = current_stackframe(); tempMethodRecord = tempStackFrame->methodRecord; if (gExcepMethodRec == null) gExcepMethodRec = tempMethodRecord; gExceptionRecord = (ExceptionRecord *) (get_binary_base() + tempMethodRecord->exceptionTable); tempCurrentOffset = ptr2word(pc) - ptr2word(get_binary_base() + tempMethodRecord->codeOffset); #if 0 trace (-1, tempCurrentOffset, 5); #endif gNumExceptionHandlers = tempMethodRecord->numExceptionHandlers; #if DEBUG_EXCEPTIONS printf("Num exception handlers=%d\n",gNumExceptionHandlers); #endif while (gNumExceptionHandlers--) { if (gExceptionRecord->start <= tempCurrentOffset /* off by one? < ? */ && tempCurrentOffset <= gExceptionRecord->end) { // Check if exception class applies if (instance_of (exception, gExceptionRecord->classIndex)) { // Clear operand stack init_sp (tempStackFrame, tempMethodRecord); // Push the exception object push_ref (ptr2word (exception)); // Jump to handler: pc = get_binary_base() + tempMethodRecord->codeOffset + gExceptionRecord->handler; #if DEBUG_EXCEPTIONS printf("Found exception handler\n"); #endif return; } } gExceptionRecord++; } // No good handlers in current stack frame - go up. auxThread = currentThread; do_return (0); // Note: return takes care of synchronized methods. if (auxThread->state == DEAD) { #if DEBUG_EXCEPTIONS printf("Thread is dead\n"); #endif if (get_class_index(exception) != JAVA_LANG_THREADDEATH) { #if DEBUG_EXCEPTIONS printf("Handle uncaught exception\n"); #endif handle_uncaught_exception (exception, auxThread, gExcepMethodRec, tempMethodRecord, gExceptionPc); } return; } goto LABEL_PROPAGATE; }
/** * Exceute the static initializer if required. Note that the ret address used * here is set such that the current instruction will be re-started when the * initialization completes. * @return An indication of how the VM should proceed */ int dispatch_static_initializer (ClassRecord *aRec, byte *retAddr) { int state = get_init_state(aRec); ClassRecord *init = aRec; ClassRecord *super = get_class_record(init->parentClass); MethodRecord *method; // Are we needed? if (state & C_INITIALIZED) return EXEC_CONTINUE; // We need to initialize all of the super classes first. So we find the // highest one that has not been initialized and deal with that. This code // will then be called again and we will init the next highest and so on // until all of the classes in the chain are done. for(;;) { // find first super class that has not been initialized while (init != super && (get_init_state(super) & C_INITIALIZED) == 0) { init = super; super = get_class_record(init->parentClass); } // Do we have an initilizer if so we have found our class if (has_clinit (init)) break; // no initializer so mark as now initialized set_init_state (init, C_INITIALIZED); // If we are at the start of the list we are done if (init == aRec) return EXEC_CONTINUE; // Otherwise go do it all again init = aRec; } state = get_init_state(init); // are we already initializing ? if (state & C_INITIALIZING) { // Is it this thread that is doing the init? if (get_sync(init)->threadId == currentThread->threadId) return EXEC_CONTINUE; // No so we must retry the current instruction curPc = retAddr; sleep_thread(1); schedule_request(REQUEST_SWITCH_THREAD); return EXEC_RETRY; } #if DEBUG_METHODS printf ("dispatch_static_initializer: has clinit: %d, %d\n", (int) aRec, (int) retAddr); #endif // Static initializer is always the first method method = get_method_table(init); if ((byte *)method == get_binary_base() || method->signatureId != _6clinit_7_4_5V) { throw_new_exception (JAVA_LANG_NOSUCHMETHODERROR); return EXEC_EXCEPTION; } // Can we run it? if (!dispatch_special (method, retAddr)) return EXEC_RETRY; // Mark for next time set_init_state(init, C_INITIALIZING); // and claim the monitor current_stackframe()->monitor = (Object *)init; enter_monitor (currentThread, (Object *)init); return EXEC_RUN; }