boolean debug_event(int event, Object *exception, const Thread *thread, const MethodRecord *method, byte *pc, int frame) { // Inform the debug thread (if any) that there has been a debug event. // return false if no debug thread is waiting. switch(debugEventOptions[event]) { case DBG_EVENT_DISABLE: return false; case DBG_EVENT_IGNORE: return true; default: break; } // Check that we have a debugger attached and that it is ready to go... if (!debug || get_monitor_count((&(debug->_super.sync))) != 0 || debugThread->state != CONDVAR_WAITING || (Debug *)debugThread->waitingOn != debug) return false; // Setup the state debug->typ = event; debug->exception = ptr2ref(exception); debug->thread = ptr2ref(thread); debug->pc = (pc ? pc - get_binary_base() : 0); debug->method = (method ? method - get_method_table(get_class_record(0)) : 0); debug->frame = frame; // Suspend all threads (except current) suspend_thread(null); // Make sure current thread is also suspended suspend_thread(currentThread); // Allow the debug thread to run resume_thread(debugThread); monitor_notify_unchecked(&debug->_super, 1); return true; }
/** * Create a compact form of the specified call stack. * One int per frame containing * the method number and current offset. If the ignore parameter is non null * then frames that have a matching this field will not be included in the * trace. This allow the frames for the creation of an exception object to * be ignored. */ Object * create_stack_trace(Thread *thread, Object *ignore) { int frameCnt = thread->stackFrameIndex; Object *stackArray; JINT *data; int i; StackFrame *topFrame = ((StackFrame *)array_start(thread->stackFrameArray)) + frameCnt; StackFrame *stackFrame = topFrame; MethodRecord *methodBase = get_method_table(get_class_record(0)); byte *pcBase = get_binary_base() + 2; // Ignore frames if required. if (ignore) { while ((STACKWORD)ignore == *(stackFrame->localsBase)) { stackFrame--; frameCnt--; } } // Try and allocate the space for the trace. stackArray = new_single_array(AI, frameCnt); if (stackArray == JNULL) return JNULL; if (thread == currentThread) topFrame->pc = getPc(); // adjust top most pc to allow for return address hack topFrame->pc += 2; // Fill in the trace. data = jint_array(stackArray); for(i = 0; i < frameCnt; i++) { data[i] = ((stackFrame->methodRecord - methodBase) << 16) | (stackFrame->pc - pcBase - stackFrame->methodRecord->codeOffset); stackFrame--; } // restore correct pc topFrame->pc -= 2; return stackArray; }
/** * @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; }