/* * Execute the ANEWARRAY instruction */ void op_anewarray() { Ref type = resolve(u16(1), ID_TYPE); if (type == NULL) { return; } // rollback, gc done Ref arrayType = getRef(type, TYPE_ARRAY_TYPE); // resolve array type if (arrayType == NULL) { Ref target = getRef(core, OBJECT_TYPE); Ref method = getRef(core, CORE_RESOLVE_METHOD); executeMethod(target, method, 0); return; // rollback } // allocate space int length = peekInt(); // don't pop yet in case gc runs int numWords = ARRAY_DATA + length; Ref array = allocate(numWords, HEADER_OBJECT_ARRAY); if (array == NULL) { return; } // rollback, gc done popInt(); // pop length // initialise array object and push on stack int hash = (char*) array - (char*) core; setInt(array, OBJECT_HASHCODE, hash); setRef(array, OBJECT_TYPE, arrayType); setInt(array, ARRAY_LENGTH, length); pushRef(array); pc += 3; }
/* * Search for an appropriate handler in the current method * and return true if one is found, false otherwise. */ static int searchForHandler(Ref exception, Ref exceptionType) { // make sure exception table exists Ref exceptionTable = getRef(method, METHOD_EXCEPTIONS); if (exceptionTable == NULL) { return FALSE; } // loop through exception table entries int length = getInt(exceptionTable, ARRAY_LENGTH); unsigned short* ps = (unsigned short*) (exceptionTable + ARRAY_DATA); int i = 0; for (; i < length; i += 4) { // read table entry int start_pc = ps[i]; int end_pc = ps[i + 1]; int handler_pc = ps[i + 2]; int catch_type = ps[i + 3]; // check range Ref catchTypeEntry = getPoolEntry(catch_type); int inRange = (pc >= start_pc) && (pc < end_pc); int handled = (catch_type == 0) || isSubClassOf(exceptionType, catchTypeEntry); if (inRange && handled) { pc = handler_pc; int frameSize = frame[OBJECT_SIZE].i; // clear stack Var* max = (Var*) (frame + frameSize); for (; stack < max; stack++) { stack->flag = FALSE; } pushRef(exception); return TRUE; } } return FALSE; }
//dup int op_dup( unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p ) { StackEntry *entry = popEntry(stack); int value = 0; value = EntryToInt(entry); if ( entry->type == STACK_ENTRY_INT ) { pushInt(stack, value); pushInt(stack, value); } else { pushRef(stack, value); pushRef(stack, value); } #if SIMPLE_JVM_DEBUG printf("dup\n"); #endif *opCode = *opCode + 1; return 0; }
//ldc int op_ldc( unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p ) { int value = opCode[0][1]; pushRef(stack, value); #if SIMPLE_JVM_DEBUG printf("ldc: push a constant index %d onto the stack \n", value); #endif *opCode = *opCode + 2; return 0; }
//0x14 ldc2_w int op_ldc2_w( unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p ) { unsigned char index1 = opCode[0][1]; unsigned char index2 = opCode[0][2]; int index = ( index1 << 8 ) | index2; pushRef(stack, index); #if SIMPLE_JVM_DEBUG printf("ldc2_w: push a constant index %d onto the stack \n", index); #endif *opCode = *opCode + 3; return 0; }
//getstatic int op_getstatic( unsigned char **opCode, StackFrame *stack, SimpleConstantPool *p ) { u2 field_index ; unsigned char tmp[2]; tmp[0] = opCode[0][1]; tmp[1] = opCode[0][2]; field_index = tmp[0] << 8 | tmp[1]; #if SIMPLE_JVM_DEBUG printf("getstatic %d\n", field_index ); #endif pushRef(stack, field_index); *opCode = *opCode + 3; return 0; }
/* * Execute the NEW instruction */ void op_new() { // resolve the type Ref type = resolve(u16(1), ID_TYPE); if (type == NULL) { return; } // rollback, gc done // allocate space int numFields = getInt(type, TYPE_INSTANCE_FIELD_COUNT); int numWords = OBJECT_FIELDS + numFields; Ref object = allocate(numWords, HEADER_INSTANCE); if (object == NULL) { return; } // rollback, gc done // set headers and push on stack int hash = (char*) object - (char*) core; setInt(object, OBJECT_HASHCODE, hash); setRef(object, OBJECT_TYPE, type); pushRef(object); pc += 3; }
/* * Execute the GETSTATIC instruction */ void op_getstatic() { Ref field = resolve(u16(1), ID_FIELD); if (field == NULL) { return; } // rollback // read field values Ref type = getRef(field, ENTRY_OWNER); Ref statics = getRef(type, TYPE_STATICS); Int index = getInt(field, FIELD_INDEX); Int flag = getInt(field, FIELD_REFERENCE_FLAG); Int size = getInt(field, FIELD_SIZE); int offset = STATICS_FIELDS + index; // read values and push on stack if (flag) { pushRef(getRef(statics, offset)); } else { pushInt(getInt(statics, offset)); } if (size == 2) { pushInt(getInt(statics, offset + 1)); } pc += 3; }
/* * Execute the GETFIELD instruction */ void op_getfield() { Ref field = resolve(u16(1), ID_FIELD); if (field == NULL) { return; } // rollback // check for null pointer Ref object = popRef(); if (object == NULL) { throwException(CORE_THROW_NULL_POINTER); return; } // push value Int index = getInt(field, FIELD_INDEX) + OBJECT_FIELDS; Int flag = getInt(field, FIELD_REFERENCE_FLAG); Int size = getInt(field, FIELD_SIZE); if (flag) { pushRef(getRef(object, index)); } else { pushInt(getInt(object, index)); } if (size == 2) { pushInt(getInt(object, index + 1)); } pc += 3; }
/* * Execute the NEWARRAY instruction */ void op_newarray() { // figure out the required size int atype = u8(1); int width = getWidth(atype); int length = peekInt(); // don't pop in case rolled back later int numBytes = length * width; int extra = ((numBytes % 4) == 0) ? 0 : 1; int numDataWords = (numBytes / 4) + extra; int numWords = numDataWords + ARRAY_DATA; // allocate space Ref array = allocate(numWords, HEADER_DATA_ARRAY); if (array == NULL) { return; } // rollback, gc done popInt(); // can pop the length now // initialise new array and push address on stack int hash = (char*) array - (char*) core; Ref type = getRef(core, CORE_ARRAYS + atype); setInt(array, OBJECT_HASHCODE, hash); setRef(array, OBJECT_TYPE, type); setInt(array, ARRAY_LENGTH, length); pushRef(array); pc += 2; }
/* * Execute the specified native method. Return true if the method * is executed, false if it is rolled back for garbage collection. */ int executeNativeMethod(Ref target, Ref method, int offset) { int magic = getInt(method, METHOD_MAGIC); if (magic == 0) { printf("Native method not supported\n"); debugTrace(); exit(1); } switch (magic) { // print a debug message case MAGIC_RUNTIME_CORE_DEBUG: debugLine(popRef()); pc += offset; break; // execute the given static method case MAGIC_RUNTIME_CORE_EXECUTE_STATIC: { Ref staticMethod = popRef(); if (staticMethod == NULL) { throwException(CORE_THROW_NULL_POINTER); return; } Ref owner = getRef(staticMethod, ENTRY_OWNER); if (!executeMethod(owner, staticMethod, offset)) { // restore stack if rolled back for gc pushRef(staticMethod); } } break; // return the current frame case MAGIC_RUNTIME_FRAME_CURRENT: pushRef(frame); pc += offset; break; // return the core object case MAGIC_RUNTIME_CORE_GET: pushRef(core); pc += offset; break; // create a statics object case MAGIC_RUNTIME_STATICS_CREATE: { // allocate space for statics object Ref type = popRef(); Int numStaticFields = getInt(type, TYPE_STATIC_FIELD_COUNT); Int numWords = STATICS_FIELDS + numStaticFields; Ref statics = allocate(numWords, HEADER_STATIC_FIELDS); if (statics == NULL) { pushRef(type); // restore stack return; // rollback, gc done } // initialise statics object and set in type object int hash = (char*) statics - (char*) core; setInt(statics, OBJECT_HASHCODE, hash); Ref staticsType = getRef(core, CORE_STATICS_TYPE); setRef(statics, OBJECT_TYPE, staticsType); Ref map = getRef(type, TYPE_STATIC_MAP); setRef(statics, STATICS_MAP, map); setRef(type, TYPE_STATICS, statics); } pc += offset; break; // read the type from a class case MAGIC_RUNTIME_CORE_GET_TYPE: { Ref class = popRef(); // type is first field in class... Ref type = getRef(class, OBJECT_FIELDS); pushRef(type); } pc += offset; break; // put system to sleep to avoid wasting processor time while idle case MAGIC_RUNTIME_IDLE_SLEEP: idleSleep(); pc += offset; break; // return the currently executing thread case MAGIC_RUNTIME_THREAD_CURRENT: pushRef(thread); pc += offset; break; // start a new thread case MAGIC_RUNTIME_THREAD_START_HOOK: startNewThread(offset); break; // return an object's class case MAGIC_JAVA_OBJECT_GET_CLASS: { Ref obj = popRef(); Ref type = getRef(obj, OBJECT_TYPE); Ref peer = getRef(type, TYPE_PEER); pushRef(peer); } pc += offset; break; // set system output stream case MAGIC_JAVA_SYSTEM_SET_OUT: { Ref arg = popRef(); Ref type = getRef(method, ENTRY_OWNER); Ref statics = getRef(type, TYPE_STATICS); setRef(statics, STATICS_FIELDS + SYSTEM_OUT, arg); } pc += offset; break; // set system error stream case MAGIC_JAVA_SYSTEM_SET_ERR: { Ref arg = popRef(); Ref type = getRef(method, ENTRY_OWNER); Ref statics = getRef(type, TYPE_STATICS); setRef(statics, STATICS_FIELDS + SYSTEM_ERR, arg); } pc += offset; break; // set system input stream case MAGIC_JAVA_SYSTEM_SET_IN: { Ref arg = popRef(); Ref type = getRef(method, ENTRY_OWNER); Ref statics = getRef(type, TYPE_STATICS); setRef(statics, STATICS_FIELDS + SYSTEM_IN, arg); } pc += offset; break; // read an ascii character from the console case MAGIC_TEST_READ_FROM_CONSOLE: { char c = readFromConsole(); pushInt(c); } pc += offset; break; // write an ascii character to the console case MAGIC_TEST_WRITE_TO_CONSOLE: { char c = popInt() & 0xFF; printf("%c", c); } pc += offset; break; // read a byte from the floppy drive case MAGIC_TEST_READ_FROM_FLOPPY: { Int pos = popInt(); pushInt(readFromFloppy(pos)); } pc += offset; break; // magic id not recognised default: printf("Invalid magic method id: %d\n", magic); exit(1); break; } }
void VirtualMachine::execute(const InstructionList& script) { ScriptValue emptyVar; emptyVar.Flags = ScriptValue::VariableRef; emptyVar.Type = -2; emptyVar.Pointer = 0x0; std::map<std::string, ScriptValue>::iterator it; for(int i = 0; i < script.size(); ++i) { const Instruction& cmd = script[i]; bool jump = true; switch(cmd.Type) { case PUSH: push(cmd.Value); break; case GETVAR: it = Variables.find(cmd.Name); if(it == Variables.end()) it = Variables.emplace(cmd.Name, emptyVar).first; pushRef(&((*it).second)); break; case EOL: //clearStack(); break; case FUNCALL: { std::vector<int> arguments; arguments.reserve(cmd.NumArguments); for(int i = 0; i < cmd.NumArguments; ++i) arguments.push_back(peek(i).Type); FunctionDeclaration* fn = Environment->resolveFunctionCall(cmd.Name, arguments); if(fn) (*(fn->FnPtr))(this); else { std::cout << "RUNTIME ERROR: No function matching " << cmd.Name << "("; for(int i = 0; i < cmd.NumArguments; ++i) { if(i != 0) std::cout << ", "; std::cout << Config->NativeTypes[peek(i).Type].Name; } std::cout << ")" << std::endl; } break; } case OBJCALL: { std::vector<int> arguments; arguments.reserve(cmd.NumArguments); for(int i = 0; i < cmd.NumArguments; ++i) arguments.push_back(peek(i+1).Type); FunctionDeclaration* fn = Environment->resolveMethodCall(peek(0).Type, cmd.Name, arguments); if(fn) (*(fn->FnPtr))(this); else { std::cout << "RUNTIME ERROR: No function matching " << cmd.Name << "("; for(int i = 0; i < cmd.NumArguments; ++i) { if(i != 0) std::cout << ", "; std::cout << Config->NativeTypes[peek(1+i).Type].Name; } std::cout << ") in " << Config->NativeTypes[peek(0).Type].Name << std::endl; } break; } case SUBCALL: { int targetPos = -1; for(int j = 0; j < script.size(); ++j) { if(script[j].Type == LABEL) if(script[j].LabelID == cmd.LabelID) { targetPos = j; break; } } if(targetPos != -1) { CallStack[CallStackPosition].ReturnAddress = i; CallStack[CallStackPosition].StackPosition = StackPosition; CallStackPosition++; i = targetPos; } break; } case SUBENTER: { int targetPos = -1; for(int j = i; j < script.size(); ++j) { if(script[j].Type == LABEL) if(script[j].LabelID == cmd.LabelID) { targetPos = j; break; } } if(targetPos != -1) { CallStack[CallStackPosition].ReturnAddress = targetPos; CallStack[CallStackPosition].StackPosition = StackPosition; CallStackPosition++; } break; } case RETURN: if(CallStackPosition > 0) { ScriptValue retValue = pop(); CallStackPosition--; i = CallStack[CallStackPosition].ReturnAddress; StackPosition = CallStack[CallStackPosition].StackPosition; push(retValue); } break; case JUMPTO: case JUMPIF: case JUMPIFN: if(cmd.Type == JUMPTO ) jump = true; else if(cmd.Type == JUMPIF ) jump = pop().as<int>(); else if(cmd.Type == JUMPIFN) jump = !pop().as<int>(); if(jump) { int targetPos = -1; for(int j = 0; j < script.size(); ++j) { if(script[j].Type == LABEL) if(script[j].LabelID == cmd.LabelID) { targetPos = j; break; } } if(targetPos != -1) i = targetPos; } break; case LABEL: // Ignore. break; default: std::cout << "Unimplemented Instruction " << cmd.Type << std::endl; break; } } }