/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * This file is part of SableVM. * * See the file "LICENSE" for Copyright information and the * * terms and conditions for copying, distribution and * * modification of SableVM. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* ---------------------------------------------------------------------- _svmf_interpreter ---------------------------------------------------------------------- */ static jint _svmf_interpreter (_svmt_JNIEnv *_env) { _svmt_JNIEnv *volatile env = _env; register _svmt_stack_value *stack = NULL; register _svmt_stack_value *locals = NULL; register _svmt_code *pc = NULL; register jint stack_size; #ifdef _SABLEVM_INLINED_THREADED_INTERPRETER /* exception addresses * * The idea is that normal gotos might be compiled to relative * jumps, preventing their usage in inlined-threaded code. Using a * goto is an elegant way to avoid using method calls in ATHROW * (necessary to create a new null pointer exception). * * A last note:We must guard against a too clever compiler that * would detect a unique value in a variable; we do this by * initializing goto address variable to NULL, and changing its * value to the correct one when initializing the instruction array. * Ahh! So many little details to get right for things to work... */ static void *athrow = NULL; #endif #ifdef _SABLEVM_SIGNALS_FOR_EXCEPTIONS sigjmp_buf *volatile previous_signal_handler = env->signal_handler; sigjmp_buf signal_handler; #endif assert (*(env->throwable) == NULL); #ifdef _SABLEVM_SIGNALS_FOR_EXCEPTIONS /* set signal handler */ if (sigsetjmp (signal_handler, 1)) { jint signal_code = env->signal_code; #ifndef NDEBUG env->signal_code = SVM_SIGNAL_NONE; #endif switch (signal_code) { case SVM_SIGNAL_NULL_POINTER_EXCEPTION: { /* if initializing this vm, we store into _svmv_codes the address of the initialized static local array */ if (env->stack.current_frame == NULL) { goto initialize_instructions; } else { goto nullpointerexception_handler; } } break; case SVM_SIGNAL_ARITHMETIC_EXCEPTION: { goto arithmeticexception_handler; } break; default: { _svmm_fatal_error ("impossible control flow"); } break; } } env->signal_handler = &signal_handler; #else /* _SABLEVM_SIGNALS_FOR_EXCEPTIONS */ if (env->stack.current_frame == NULL) { goto initialize_instructions; } #endif /* _SABLEVM_SIGNALS_FOR_EXCEPTIONS */ { /* When _SABLEVM_SIGNALS_FOR_EXCEPTIONS is defined, the following code causes a sigfault at the time of initialization of vm->instructions, as env->stack.current_frame is NULL at that point. The advantage of using this weird control flow on initialization is to eliminate "initialization test" overhead from normal _svmf_interpreter execution path. Not a thing you should teach cs-101 students ;-) */ _svmt_stack_frame *frame = env->stack.current_frame; _svmt_method_info *method = frame->method; locals = (_svmt_stack_value *) (((char *) frame) - method->frame_info->start_offset); stack = (_svmt_stack_value *) (((char *) frame) + _svmv_stack_offset); assert (env->stack.current_frame->this != NULL); assert (env->stack.current_frame->stack_size == 0); /* check */ _svmf_periodic_check (env); } #if !defined(NDEBUG) if (env->vm->verbose_methods) { _svmt_method_info *method = env->stack.current_frame->method; _svmf_printf (env, stdout, "[verbose methods: entering method %s.%s%s]\n", method->class_info->name, DREF (method->name, value), DREF (method->descriptor, value)); } #endif pc = env->stack.current_frame->pc; stack_size = 0; #if defined(_SABLEVM_INLINED_THREADED_INTERPRETER) || defined(_SABLEVM_DIRECT_THREADED_INTERPRETER) goto *((pc++)->implementation); #else dispatch: assert (stack_size >= 0); assert (stack_size == 0 || env->stack.current_frame->method == &env->vm->internal_call_method || env->stack.current_frame->method == &env->vm->vm_initiated_call_method || stack_size <= env->stack.current_frame->method->data.code_attribute->max_stack); switch ((pc++)->jint) { #include "instructions_switch.c" default: { _svmm_fatal_error ("impossible control flow"); } break; } #endif /* defined(_SABLEVM_INLINED_THREADED_INTERPRETER) || defined(_SABLEVM_DIRECT_THREADED_INTERPRETER) */ _svmm_fatal_error ("impossible control flow"); athrow_handler: if (*(env->throwable) == NULL) { goto nullpointerexception_handler; } goto exception_handler; arithmeticexception_handler: _svmf_error_ArithmeticException (env); goto exception_handler; classcastexception_handler: _svmf_error_ClassCastException (env); goto exception_handler; nullpointerexception_handler: _svmf_error_NullPointerException (env); goto exception_handler; arrayindexoutofboundsexception_handler: _svmf_error_ArrayIndexOutOfBoundsException (env); goto exception_handler; arraystoreexception_handler: _svmf_error_ArrayStoreException (env); goto exception_handler; abstractmethoderror_handler: _svmf_error_AbstractMethodError (env); goto exception_handler; exception_handler: assert (*(env->throwable) != NULL); #ifdef COMMENT if (strcmp ((*(env->throwable))->vtable->type->name, "java/lang/ClassNotFoundException") != 0 && strcmp ((*(env->throwable))->vtable->type->name, "java/lang/NoClassDefFoundError") != 0) { _svmf_printf (env, stderr, "** (on thread %d) exception: %s\n", env->thread.id, (*(env->throwable))->vtable->type->name); _svmf_dump_stack_trace (env); } #endif { jint i; jint table_length; _svmt_exception_table *table; _svmt_stack_frame *frame = env->stack.current_frame; _svmt_method_info *method = frame->method; exception_loop: pc = frame->pc; frame->stack_size = 0; if (_svmf_is_set_flag (method->access_flags, SVM_ACC_INTERNAL)) { assert (method == &env->vm->internal_call_method || method == &env->vm->vm_initiated_call_method); #ifdef _SABLEVM_SIGNALS_FOR_EXCEPTIONS env->signal_handler = previous_signal_handler; #endif return JNI_ERR; } assert (!_svmf_is_set_flag (method->access_flags, SVM_ACC_NATIVE)); table_length = method->data.code_attribute->exception_table_length; table = method->data.code_attribute->exception_table; for (i = 0; i < table_length; i++) { if ((pc >= table[i].normal_start && pc <= table[i].normal_end) || (pc >= table[i].prepare_start && pc <= table[i].prepare_end)) { /* resolve and link type, if necessary */ if (CAN_DREF (table[i].catch_type)) { jobject pending_throwable; if (_svmm_new_native_local (env, pending_throwable) != JNI_OK) { /* to avoid infinite loops! */ goto pop_stack_frame; } /* save throwable aside, so that we can run Java code (i.e. java/lang/Class.) if necessary */ *pending_throwable = *(env->throwable); *(env->throwable) = NULL; if (_svmf_resolve_CONSTANT_Class (env, env->stack.current_frame->method->class_info, *(table[i].catch_type)) != JNI_OK) { _svmm_free_native_local (env, pending_throwable); goto pop_stack_frame; } if (_svmf_link_type (env, DREF (table[i].catch_type, type)) != JNI_OK) { _svmm_free_native_local (env, pending_throwable); goto pop_stack_frame; } /* restore pending throwable */ *(env->throwable) = *pending_throwable; _svmm_free_native_local (env, pending_throwable); frame = env->stack.current_frame; assert (method == frame->method); } /* if "any" (null) or matching type */ if (CANNOT_DREF (table[i].catch_type) || _svmf_is_assignable_from (env, (*(env->throwable))->vtable->type, DREF (table[i].catch_type, type))) { locals = (_svmt_stack_value *) (((char *) frame) - method->frame_info->start_offset); stack = (_svmt_stack_value *) (((char *) frame) + _svmv_stack_offset); pc = table[i].handler; stack_size = 1; stack[0].reference = *(env->throwable); *(env->throwable) = NULL; #if defined(_SABLEVM_INLINED_THREADED_INTERPRETER) || defined(_SABLEVM_DIRECT_THREADED_INTERPRETER) goto *((pc++)->implementation); #else goto dispatch; #endif } } } /* structured locking */ if (env->stack.current_frame->lock_count != 0) { /* pop stack frame */ frame = env->stack.current_frame; env->stack.current_frame = (_svmt_stack_frame *) (((char *) frame) - frame->previous_offset); _svmf_error_IllegalMonitorStateException (env); goto exception_handler; } #if !defined(NDEBUG) if (env->vm->verbose_methods) { _svmf_printf (env, stdout, "[verbose methods: exiting method %s.%s%s]\n", method->class_info->name, DREF (method->name, value), DREF (method->descriptor, value)); { _svmt_method_info *caller_method; _svmt_stack_frame *caller_frame = env->stack.current_frame; caller_frame = (_svmt_stack_frame *) (((char *) caller_frame) - caller_frame->previous_offset); caller_method = caller_frame->method; while (_svmf_is_set_flag (caller_method->access_flags, SVM_ACC_INTERNAL) && caller_method != &env->vm->stack_bottom_method) { caller_frame = (_svmt_stack_frame *) (((char *) caller_frame) - caller_frame->previous_offset); caller_method = caller_frame->method; } if (!_svmf_is_set_flag (caller_method->access_flags, SVM_ACC_INTERNAL)) { _svmf_printf (env, stdout, "[ returning to %s.%s%s]\n", caller_method->class_info->name, DREF (caller_method->name, value), DREF (caller_method->descriptor, value)); } } } #endif pop_stack_frame: /* pop stack frame */ frame = env->stack.current_frame; env->stack.current_frame = (_svmt_stack_frame *) (((char *) frame) - frame->previous_offset); /* is method synchronized? */ if (method->synchronized) { /* release monitor */ if (_svmf_exit_object_monitor (env, frame->this) != JNI_OK) { goto exception_handler; } } frame = env->stack.current_frame; method = frame->method; goto exception_loop; } _svmm_fatal_error ("impossible control flow"); #ifdef _SABLEVM_INLINED_THREADED_INTERPRETER fatal_error_handler: _svmm_fatal_error ("impossible control flow"); return JNI_ERR; #endif initialize_instructions: { jint instr; for (instr = 0; instr < SVM_INSTRUCTION_COUNT; instr++) { switch (instr) { #ifdef _SABLEVM_INLINED_THREADED_INTERPRETER #include "instructions_preparation_inlined_threaded.c" #endif #ifdef _SABLEVM_DIRECT_THREADED_INTERPRETER #include "instructions_preparation_direct_threaded.c" #endif #ifdef _SABLEVM_SWITCH_THREADED_INTERPRETER #include "instructions_preparation_switch_threaded.c" #endif case SVM_INSTRUCTION_UNDEFINED_186: { _svmm_zero_memory (env->vm->instructions[instr]); } break; default: { _svmm_fatal_error ("impossible control flow"); } break; } } #ifdef _SABLEVM_INLINED_THREADED_INTERPRETER /* initialize goto address */ athrow = &&athrow_handler; #endif #ifdef _SABLEVM_SIGNALS_FOR_EXCEPTIONS env->signal_handler = previous_signal_handler; #endif /* _SABLEVM_SIGNALS_FOR_EXCEPTIONS */ return JNI_OK; } }