📄 interpreter.c
字号:
#include "trace.h"#include "types.h"#include "constants.h"#include "classes.h"#include "interpreter.h"#include "platform_hooks.h"#include "threads.h"#include "opcodes.h"#include "configure.h"#include "memory.h"#include "language.h"#include "exceptions.h"#include "specialclasses.h"#include "fields.h"#include "stack.h"#include "poll.h"#define F_OFFSET_MASK 0x0F#if DEBUG_BYTECODEextern char *OPCODE_NAME[];#endif// Interpreter globals:volatile boolean gMakeRequest;byte gRequestCode;byte *pc;STACKWORD *localsBase;STACKWORD *stackTop;// Temporary globals:byte tempByte;byte *tempBytePtr;JFLOAT tempFloat;ConstantRecord *tempConstRec;STACKWORD tempStackWord;STACKWORD *tempWordPtr;JSHORT tempInt; /** * Assumes pc points to 2-byte offset, and jumps. */void do_goto (boolean aCond){ if (aCond) { pc += (JSHORT) (((TWOBYTES) *pc << 8) | *(pc+1)); pc--; } else { pc += 2; }}void do_isub (void){ STACKWORD poppedWord; poppedWord = pop_word(); set_top_word (word2jint(get_top_word()) - word2jint(poppedWord));}#if FP_ARITHMETICvoid do_fcmp (JFLOAT f1, JFLOAT f2, STACKWORD def){ if (f1 > f2) push_word (1); else if (f1 == f2) push_word (0); else if (f1 < f2) push_word (-1); else push_word (def);}#endif/** * @return A String instance, or JNULL if an exception was thrown * or the static initializer of String had to be executed. */static inline Object *create_string (ConstantRecord *constantRecord, byte *btAddr){ Object *ref; Object *arr; TWOBYTES i; ref = new_object_checked (JAVA_LANG_STRING, btAddr); if (ref == JNULL) return JNULL; arr = new_primitive_array (T_CHAR, constantRecord->constantSize); if (arr == JNULL) { deallocate (obj2ptr(ref), class_size (JAVA_LANG_STRING)); return JNULL; } // printf ("char array at %d\n", (int) arr); store_word ((byte *) &(((String *) ref)->characters), 4, obj2word(arr)); for (i = 0; i < constantRecord->constantSize; i++) { jchar_array(arr)[i] = (JCHAR) get_constant_ptr(constantRecord)[i]; //printf ("char %d: %c\n", i, (char) (jchar_array(arr)[i])); } return ref;}/** * Pops the array index off the stack, assigns * both tempInt and tempBytePtr, and checks * bounds and null reference. The array reference * is the top word on the stack after this operation. * @return True if successful, false if an exception has been scheduled. */boolean array_load_helper(){ tempInt = word2jshort(pop_word()); tempBytePtr = word2ptr(get_top_ref()); if (tempBytePtr == JNULL) throw_exception (nullPointerException); else if (tempInt < 0 || tempInt >= get_array_length ((Object *) tempBytePtr)) throw_exception (arrayIndexOutOfBoundsException); else return true; return false;}/** * Same as array_load_helper, except that it pops * the reference from the stack. */boolean array_store_helper(){ if (array_load_helper()) { pop_ref(); return true; } return false;}/** * Everything runs inside here, essentially. * * To be able use only a single fast test on each instruction * several assumptions are made: * - currentThread is initialized and non-null and * it is not set to null by any bytecode instruction. * - Thus it is not allowed to call schedule_thread() in instructions, * use schedule_request( REQUEST_SWITCH_THREAD) instead. * - Whenever gMakeRequest is false, gRequestCode is REQUEST_TICK. * - Thus anybody who sets gRequestCode must also set gMakeRequest to true * (using schedule_request assures this). * - Only the request handler may set gMakeRequest to false. * - The millisecond timer interrupt must set gMakeRequest to true * for time slices to work. * */void engine(){ byte ticks_until_switch = TICKS_PER_TIME_SLICE; int lgginst = 0; assert( currentThread != null, INTERPRETER0); schedule_request( REQUEST_SWITCH_THREAD); LABEL_ENGINELOOP: instruction_hook(); assert( currentThread != null, INTERPRETER1); while( gMakeRequest) { byte requestCode = gRequestCode; gMakeRequest = false; gRequestCode = REQUEST_TICK; tick_hook(); if( requestCode == REQUEST_EXIT) { return; } if( requestCode == REQUEST_TICK) ticks_until_switch--; if( requestCode == REQUEST_SWITCH_THREAD || ticks_until_switch == 0){ ticks_until_switch = TICKS_PER_TIME_SLICE;#if DEBUG_THREADS printf ("switching thread: %d\n", (int)ticks_until_switch);#endif switch_thread();#if DEBUG_THREADS printf ("done switching thread\n");#endif switch_thread_hook(); } if( currentThread == null /* no runnable thread */ && gRequestCode == REQUEST_TICK){ /* no important request */ idle_hook(); schedule_request( REQUEST_SWITCH_THREAD); } } assert( gRequestCode == REQUEST_TICK, INTERPRETER2); assert( currentThread != null, INTERPRETER3); //----------------------------------------------- // SWITCH BEGINS HERE //----------------------------------------------- #if DEBUG_BYTECODE printf ("0x%X: \n", (int) pc); printf ("OPCODE (0x%X) %s\n", (int) *pc, OPCODE_NAME[*pc]); #endif switch (*pc++) { case OP_NOP: goto LABEL_ENGINELOOP; #include "op_stack.hc" #include "op_locals.hc" #include "op_arrays.hc" #include "op_objects.hc" #include "op_control.hc" #include "op_other.hc" #include "op_conversions.hc" #include "op_logical.hc" #include "op_arithmetic.hc" #include "op_methods.hc"/*#ifdef VERIFY default: assert(false, (TWOBYTES)(pc-1) % 10000); break;#endif*/ } //----------------------------------------------- // SWITCH ENDS HERE //----------------------------------------------- #if !FP_ARITHMETIC throw_exception (noSuchMethodError); #else // This point should never be reached #ifdef VERIFY assert (false, 1000 + *pc); #endif // VERIFY #endif // FP_ARITHMETIC}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -