// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ // ¥ BeginExecution /*e*/ // ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ // Moves the program into the executing state. You must then call Step whilst it returns true to run it. void CProgram::BeginExecution() { AssertThrow_(mProgramState==kReady); ECHO("Beginning execution of '" << GetProgramName() << "'"); // Introduce the top level stack frame CStackFrame *stack=new CStackFrame(CStackFrame::kRoot,0L,0L,mRootScope); ThrowIfMemFull_(stack); PushStackFrame(stack); mProgramState=kRunning; mBreakDisabled=false; CGLTextureManager::Initialise(); UFileManager::Initialise(this); UGammaManager::Initialise(); UTNTMapManager::Initialise(); UCursorManager::Initialise(); CProgMoanChannel::ResetSharedRegs(); CApplication::GetApplication()->ClearKeyboard(); // don't want any keys to look like they've been held down if using carbon events we could lose the keyup event }
// RAGE AGAINST THE VIRTUAL MACHINE =) gmThread::State gmThread::Sys_Execute(gmVariable * a_return) { register union { const gmuint8 * instruction; const gmuint32 * instruction32; }; register gmVariable * top; gmVariable * base; gmVariable * operand; const gmuint8 * code; if(m_state != RUNNING) return m_state; #if GMDEBUG_SUPPORT if(m_debugFlags && m_machine->GetDebugMode() && m_machine->m_isBroken) { if(m_machine->m_isBroken(this)) return RUNNING; } #endif // GMDEBUG_SUPPORT // make sure we have a stack frame GM_ASSERT(m_frame); GM_ASSERT(GetFunction()->m_type == GM_FUNCTION); // cache our "registers" gmFunctionObject * fn = (gmFunctionObject *) GM_MOBJECT(m_machine, GetFunction()->m_value.m_ref); code = (const gmuint8 *) fn->GetByteCode(); if(m_instruction == NULL) instruction = code; else instruction = m_instruction; top = GetTop(); base = GetBase(); // // start byte code execution // for(;;) { #ifdef GM_CHECK_USER_BREAK_CALLBACK // This may be defined in gmConfig_p.h // Check external source to break execution with exception eg. Check for CTRL-BREAK // Endless loop protection could be implemented with this, or in a similar manner. if( gmMachine::s_userBreakCallback && gmMachine::s_userBreakCallback(this) ) { GMTHREAD_LOG("User break. Execution halted."); goto LabelException; } #endif //GM_CHECK_USER_BREAK_CALLBACK switch(*(instruction32++)) { // // unary operator // #if GM_USE_INCDECOPERATORS case BC_OP_INC : case BC_OP_DEC : #endif case BC_BIT_INV : case BC_OP_NEG : case BC_OP_POS : case BC_OP_NOT : { operand = top - 1; gmOperatorFunction op = OPERATOR(operand->m_type, (gmOperator) instruction32[-1]); if(op) { op(this, operand); } else if((fn = CALLOPERATOR(operand->m_type, (gmOperator) instruction32[-1]))) { operand[2] = operand[0]; operand[0] = gmVariable(GM_NULL, 0); operand[1] = gmVariable(GM_FUNCTION, fn->GetRef()); SetTop(operand + 3); State res = PushStackFrame(1, &instruction, &code); top = GetTop(); base = GetBase(); if(res == RUNNING) break; if(res == SYS_YIELD) return RUNNING; if(res == SYS_EXCEPTION) goto LabelException; if(res == KILLED) { m_machine->Sys_SwitchState(this, KILLED); GM_ASSERT(0); } // operator should not kill a thread return res; } else { GMTHREAD_LOG("unary operator %s undefined for type %s", gmGetOperatorName((gmOperator) instruction32[-1]), m_machine->GetTypeName(operand->m_type)); goto LabelException; } break; } // // operator // case BC_OP_ADD : case BC_OP_SUB : case BC_OP_MUL : case BC_OP_DIV : case BC_OP_REM : case BC_BIT_OR : case BC_BIT_XOR : case BC_BIT_AND : case BC_BIT_SHL : case BC_BIT_SHR : case BC_OP_LT : case BC_OP_GT : case BC_OP_LTE : case BC_OP_GTE : case BC_OP_EQ : case BC_OP_NEQ : { operand = top - 2; --top; // NOTE: Classic logic for operators. Higher type processes the operation. register gmType t1 = operand[1].m_type; if(operand->m_type > t1) t1 = operand->m_type; gmOperatorFunction op = OPERATOR(t1, (gmOperator) instruction32[-1]); if(op) { op(this, operand); } else if((fn = CALLOPERATOR(t1, (gmOperator) instruction32[-1]))) { operand[2] = operand[0]; operand[3] = operand[1]; operand[0] = gmVariable(GM_NULL, 0); operand[1] = gmVariable(GM_FUNCTION, fn->GetRef()); SetTop(operand + 4); State res = PushStackFrame(2, &instruction, &code); top = GetTop(); base = GetBase(); if(res == RUNNING) break; if(res == SYS_YIELD) return RUNNING; if(res == SYS_EXCEPTION) goto LabelException; if(res == KILLED) { m_machine->Sys_SwitchState(this, KILLED); GM_ASSERT(0); } // operator should not kill a thread return res; } else { GMTHREAD_LOG("operator %s undefined for type %s and %s", gmGetOperatorName((gmOperator) instruction32[-1]), m_machine->GetTypeName(operand->m_type), m_machine->GetTypeName((operand + 1)->m_type)); goto LabelException; } break; } case BC_GETIND : { operand = top - 2; --top; gmOperatorFunction op = OPERATOR(operand->m_type, (gmOperator) instruction32[-1]); if(op) { op(this, operand); } else if((fn = CALLOPERATOR(operand->m_type, (gmOperator) instruction32[-1]))) { operand[2] = operand[0]; operand[3] = operand[1]; operand[0] = gmVariable(GM_NULL, 0); operand[1] = gmVariable(GM_FUNCTION, fn->GetRef()); SetTop(operand + 4); State res = PushStackFrame(2, &instruction, &code); top = GetTop(); base = GetBase(); if(res == RUNNING) break; if(res == SYS_YIELD) return RUNNING; if(res == SYS_EXCEPTION) goto LabelException; if(res == KILLED) { m_machine->Sys_SwitchState(this, KILLED); GM_ASSERT(0); } // operator should not kill a thread return res; } else { GMTHREAD_LOG("operator %s undefined for type %s and %s", gmGetOperatorName((gmOperator) instruction32[-1]), m_machine->GetTypeName(operand->m_type), m_machine->GetTypeName((operand + 1)->m_type)); goto LabelException; } break; } case BC_SETIND : { operand = top - 3; top -= 3; gmOperatorFunction op = OPERATOR(operand->m_type, O_SETIND); if(op) { op(this, operand); } else if((fn = CALLOPERATOR(operand->m_type, O_SETIND))) { operand[4] = operand[2]; operand[3] = operand[1]; operand[2] = operand[0]; operand[0] = gmVariable(GM_NULL, 0); operand[1] = gmVariable(GM_FUNCTION, fn->GetRef()); SetTop(operand + 5); State res = PushStackFrame(3, &instruction, &code); top = GetTop(); base = GetBase(); if(res == RUNNING) break; if(res == SYS_YIELD) return RUNNING; if(res == SYS_EXCEPTION) goto LabelException; if(res == KILLED) { m_machine->Sys_SwitchState(this, KILLED); GM_ASSERT(0); } // operator should not kill a thread return res; } else { GMTHREAD_LOG("setind failed."); goto LabelException; } break; } case BC_NOP : { break; } case BC_LINE : { #if GMDEBUG_SUPPORT if(m_machine->GetDebugMode() && m_machine->m_line) { SetTop(top); m_instruction = instruction; if(m_machine->m_line(this)) return RUNNING; } #endif // GMDEBUG_SUPPORT break; } case BC_GETDOT : { operand = top - 1; gmptr member = OPCODE_PTR(instruction); top->m_type = GM_STRING; top->m_value.m_ref = member; gmType t1 = operand->m_type; gmOperatorFunction op = OPERATOR(t1, O_GETDOT); if(op) { op(this, operand); if(operand->m_type) break; } if(t1 == GM_NULL) { GMTHREAD_LOG("getdot failed."); goto LabelException; } *operand = m_machine->GetTypeVariable(t1, gmVariable(GM_STRING, member)); break; } case BC_SETDOT : { operand = top - 2; gmptr member = OPCODE_PTR(instruction); top->m_type = GM_STRING; top->m_value.m_ref = member; top -= 2; gmOperatorFunction op = OPERATOR(operand->m_type, O_SETDOT); if(op) { op(this, operand); } else { GMTHREAD_LOG("setdot failed."); goto LabelException; } break; } case BC_BRA : { instruction = code + OPCODE_PTR_NI(instruction); break; } case BC_BRZ : { #if GM_BOOL_OP operand = top - 1; --top; if (operand->m_type > GM_USER) { // Look for overridden operator. gmOperatorFunction op = OPERATOR(operand->m_type, O_BOOL); if (op) { op(this, operand); } else if ((fn = CALLOPERATOR(operand->m_type, O_BOOL))) { operand[2] = operand[0]; operand[0] = gmVariable(GM_NULL, 0); operand[1] = gmVariable(GM_FUNCTION, fn->GetRef()); SetTop(operand + 3); // Return to the same instruction after making the call but it will be testing the results of the call. --instruction32; State res = PushStackFrame(1, &instruction, &code); top = GetTop(); base = GetBase(); if(res == RUNNING) break; if(res == SYS_YIELD) return RUNNING; if(res == SYS_EXCEPTION) goto LabelException; if(res == KILLED) { m_machine->Sys_SwitchState(this, KILLED); GM_ASSERT(0); } // operator should not kill a thread return res; } } if(operand->m_value.m_int == 0) { instruction = code + OPCODE_PTR_NI(instruction); } else instruction += sizeof(gmptr); #else // !GM_BOOL_OP --top; if(top->m_value.m_int == 0) { instruction = code + OPCODE_PTR_NI(instruction); } else instruction += sizeof(gmptr); #endif // !GM_BOOL_OP break; } case BC_BRNZ : { #if GM_BOOL_OP operand = top - 1; --top; if (operand->m_type > GM_USER) { // Look for overridden operator. gmOperatorFunction op = OPERATOR(operand->m_type, O_BOOL); if (op) { op(this, operand); } else if ((fn = CALLOPERATOR(operand->m_type, O_BOOL))) { operand[2] = operand[0]; operand[0] = gmVariable(GM_NULL, 0); operand[1] = gmVariable(GM_FUNCTION, fn->GetRef()); SetTop(operand + 3); // Return to the same instruction after making the call but it will be testing the results of the call. --instruction32; State res = PushStackFrame(1, &instruction, &code); top = GetTop(); base = GetBase(); if(res == RUNNING) break; if(res == SYS_YIELD) return RUNNING; if(res == SYS_EXCEPTION) goto LabelException; if(res == KILLED) { m_machine->Sys_SwitchState(this, KILLED); GM_ASSERT(0); } // operator should not kill a thread return res; } } if(operand->m_value.m_int != 0) { instruction = code + OPCODE_PTR_NI(instruction); } else instruction += sizeof(gmptr); #else // !GM_BOOL_OP --top; if(top->m_value.m_int != 0) { instruction = code + OPCODE_PTR_NI(instruction); } else instruction += sizeof(gmptr); #endif // !GM_BOOL_OP break; } case BC_BRZK : { #if GM_BOOL_OP operand = top - 1; if (operand->m_type > GM_USER) { // Look for overridden operator. gmOperatorFunction op = OPERATOR(operand->m_type, O_BOOL); if (op) { op(this, operand); } else if ((fn = CALLOPERATOR(operand->m_type, O_BOOL))) { operand[2] = operand[0]; operand[0] = gmVariable(GM_NULL, 0); operand[1] = gmVariable(GM_FUNCTION, fn->GetRef()); SetTop(operand + 3); // Return to the same instruction after making the call but it will be testing the results of the call. --instruction32; State res = PushStackFrame(1, &instruction, &code); top = GetTop(); base = GetBase(); if(res == RUNNING) break; if(res == SYS_YIELD) return RUNNING; if(res == SYS_EXCEPTION) goto LabelException; if(res == KILLED) { m_machine->Sys_SwitchState(this, KILLED); GM_ASSERT(0); } // operator should not kill a thread return res; } } if(operand->m_value.m_int == 0) { instruction = code + OPCODE_PTR_NI(instruction); } else instruction += sizeof(gmptr); #else // !GM_BOOL_OP if(top[-1].m_value.m_int == 0) { instruction = code + OPCODE_PTR_NI(instruction); } else instruction += sizeof(gmptr); #endif // !GM_BOOL_OP break; } case BC_BRNZK : { #if GM_BOOL_OP operand = top - 1; if (operand->m_type > GM_USER) { // Look for overridden operator. gmOperatorFunction op = OPERATOR(operand->m_type, O_BOOL); if (op) { op(this, operand); } else if ((fn = CALLOPERATOR(operand->m_type, O_BOOL))) { operand[2] = operand[0]; operand[0] = gmVariable(GM_NULL, 0); operand[1] = gmVariable(GM_FUNCTION, fn->GetRef()); SetTop(operand + 3); // Return to the same instruction after making the call but it will be testing the results of the call. --instruction32; State res = PushStackFrame(1, &instruction, &code); top = GetTop(); base = GetBase(); if(res == RUNNING) break; if(res == SYS_YIELD) return RUNNING; if(res == SYS_EXCEPTION) goto LabelException; if(res == KILLED) { m_machine->Sys_SwitchState(this, KILLED); GM_ASSERT(0); } // operator should not kill a thread return res; } } if(operand->m_value.m_int != 0) { instruction = code + OPCODE_PTR_NI(instruction); } else instruction += sizeof(gmptr); #else // !GM_BOOL_OP if(top[-1].m_value.m_int != 0) { instruction = code + OPCODE_PTR_NI(instruction); } else instruction += sizeof(gmptr); #endif // !GM_BOOL_OP break; } case BC_CALL : { SetTop(top); int numParams = (int) OPCODE_INT(instruction); State res = PushStackFrame(numParams, &instruction, &code); top = GetTop(); base = GetBase(); if(res == RUNNING) { #if GMDEBUG_SUPPORT if(m_debugFlags && m_machine->GetDebugMode() && m_machine->m_call) { m_instruction = instruction; if(m_machine->m_call(this)) return RUNNING; } #endif // GMDEBUG_SUPPORT break; } if(res == SYS_YIELD) return RUNNING; if(res == SYS_EXCEPTION) goto LabelException; if(res == KILLED) { if(a_return) *a_return = m_stack[m_top - 1]; m_machine->Sys_SwitchState(this, KILLED); } return res; } case BC_RET : { PUSHNULL; } case BC_RETV : { SetTop(top); int res = Sys_PopStackFrame(instruction, code); top = GetTop(); base = GetBase(); if(res == RUNNING) { #if GMDEBUG_SUPPORT if(m_debugFlags && m_machine->GetDebugMode() && m_machine->m_return) { m_instruction = instruction; if(m_machine->m_return(this)) return RUNNING; } #endif // GMDEBUG_SUPPORT break; } if(res == KILLED) { if(a_return) *a_return = *(top - 1); m_machine->Sys_SwitchState(this, KILLED); return KILLED; } if(res == SYS_EXCEPTION) goto LabelException; break; } #if GM_USE_FORK // duplicates the current thread and just the local stack frame // and branches around the forked section of code case BC_FORK : { int id; gmThread* newthr = GetMachine()->CreateThread(&id); GM_ASSERT( newthr ); // make sure there is enough room newthr->Touch( m_size - m_base + 2 - GMTHREAD_SLACKSPACE); // copy stack and vars memcpy( newthr->m_stack, &m_stack[ m_base - 2 ], sizeof( gmVariable ) * (m_top - m_base + 2 ) ); newthr->m_top = m_top - m_base + 2; newthr->m_frame = m_machine->Sys_AllocStackFrame(); newthr->m_frame->m_prev = 0; newthr->m_frame->m_returnAddress = 0; newthr->m_frame->m_returnBase = 0; newthr->m_base = 2; newthr->m_instruction = instruction + sizeof(gmptr); // skip branch on other thread newthr->PushInt( GetId() ); instruction = code + OPCODE_PTR_NI( instruction ); // branch top->m_type = GM_INT; top->m_value.m_int = newthr->GetId(); ++top; break; } #endif //GM_USE_FORK case BC_FOREACH : { gmuint32 localvalue = OPCODE_INT(instruction); gmuint32 localkey = localvalue >> 16; localvalue &= 0xffff; // iterator is at tos-1, table is at tos -2, push int 1 if continuing loop. write key and value into localkey and localvalue if(top[-2].m_type != GM_TABLE) { #if GM_USER_FOREACH gmTypeIteratorCallback itrfunc = m_machine->GetUserTypeIteratorCallback(top[-2].m_type); if (!itrfunc) { GMTHREAD_LOG("foreach expression has no iterator function"); goto LabelException; } gmTypeIterator it = (gmTypeIterator) top[-1].m_value.m_int; gmUserObject *obj = (gmUserObject*)GM_MOBJECT(m_machine, top[-2].m_value.m_ref); // Do callback for getnext gmVariable localvar; gmVariable localkeyvar; itrfunc(this, obj, it, &localkeyvar, &localvar); if (it != GM_TYPE_ITR_NULL) { base[localkey] = localkeyvar; base[localvalue] = localvar; top->m_type = GM_INT; top->m_value.m_int = 1; } else { top->m_type = GM_INT; top->m_value.m_int = 0; } top[-1].m_value.m_int = it; ++top; #else //GM_USER_FOREACH (original) GMTHREAD_LOG("foreach expression is not table type"); goto LabelException; #endif //GM_USER_FOREACH } else { GM_ASSERT(top[-1].m_type == GM_INT); gmTableIterator it = (gmTableIterator) top[-1].m_value.m_int; gmTableObject * table = (gmTableObject *) GM_MOBJECT(m_machine, top[-2].m_value.m_ref); gmTableNode * node = table->GetNext(it); top[-1].m_value.m_int = it; if(node) { base[localkey] = node->m_key; base[localvalue] = node->m_value; top->m_type = GM_INT; top->m_value.m_int = 1; } else { top->m_type = GM_INT; top->m_value.m_int = 0; } ++top; } break; } case BC_POP : { --top; break; } case BC_POP2 : { top -= 2; break; } case BC_DUP : { top[0] = top[-1]; ++top; break; } case BC_DUP2 : { top[0] = top[-2]; top[1] = top[-1]; top += 2; break; } case BC_SWAP : { top[0] = top[-1]; top[-1] = top[-2]; top[-2] = top[0]; break; } case BC_PUSHNULL : { PUSHNULL; break; } case BC_PUSHINT : { top->m_type = GM_INT; top->m_value.m_int = OPCODE_INT(instruction); ++top; break; } case BC_PUSHINT0 : { top->m_type = GM_INT; top->m_value.m_int = 0; ++top; break; } case BC_PUSHINT1 : { top->m_type = GM_INT; top->m_value.m_int = 1; ++top; break; } case BC_PUSHFP : { top->m_type = GM_FLOAT; top->m_value.m_float = OPCODE_FLOAT(instruction); ++top; break; } case BC_PUSHSTR : { top->m_type = GM_STRING; top->m_value.m_ref = OPCODE_PTR(instruction); ++top; break; } case BC_PUSHTBL : { SetTop(top); top->m_type = GM_TABLE; top->m_value.m_ref = m_machine->AllocTableObject()->GetRef(); ++top; break; } case BC_PUSHFN : { top->m_type = GM_FUNCTION; top->m_value.m_ref = OPCODE_PTR(instruction); ++top; break; } case BC_PUSHTHIS : { *top = *GetThis(); ++top; break; } case BC_GETLOCAL : { gmuint32 offset = OPCODE_INT(instruction); *(top++) = base[offset]; break; } case BC_SETLOCAL : { gmuint32 offset = OPCODE_INT(instruction); // Write barrier old local objects { gmGarbageCollector* gc = m_machine->GetGC(); if( !gc->IsOff() && base[offset].IsReference() ) { gmObject * object = GM_MOBJECT(m_machine, base[offset].m_value.m_ref); gc->WriteBarrier(object); } } base[offset] = *(--top); break; } case BC_GETGLOBAL : { top->m_type = GM_STRING; top->m_value.m_ref = OPCODE_PTR(instruction); *top = m_machine->GetGlobals()->Get(*top); ++top; break; } case BC_SETGLOBAL : { top->m_type = GM_STRING; top->m_value.m_ref = OPCODE_PTR(instruction); m_machine->GetGlobals()->Set(m_machine, *top, *(top-1)); --top; break; } case BC_GETTHIS : { gmptr member = OPCODE_PTR(instruction); const gmVariable * thisVar = GetThis(); *top = *thisVar; top[1].m_type = GM_STRING; top[1].m_value.m_ref = member; gmOperatorFunction op = OPERATOR(thisVar->m_type, O_GETDOT); if(op) { op(this, top); if(top->m_type) { ++top; break; } } if(thisVar->m_type == GM_NULL) { GMTHREAD_LOG("getthis failed. this is null"); goto LabelException; } *top = m_machine->GetTypeVariable(thisVar->m_type, top[1]); ++top; break; } case BC_SETTHIS : { gmptr member = OPCODE_PTR(instruction); const gmVariable * thisVar = GetThis(); operand = top - 1; *top = *operand; *operand = *thisVar; top[1].m_type = GM_STRING; top[1].m_value.m_ref = member; --top; gmOperatorFunction op = OPERATOR(thisVar->m_type, O_SETDOT); if(op) { op(this, operand); } else { GMTHREAD_LOG("setthis failed."); goto LabelException; } break; } default : { break; } } } LabelException: // // exception handler // m_instruction = instruction; // spit out error info LogLineFile(); LogCallStack(); // call machine exception handler if(gmMachine::s_machineCallback) { if(gmMachine::s_machineCallback(m_machine, MC_THREAD_EXCEPTION, this)) { #if GMDEBUG_SUPPORT // if we are being debugged, put this thread into a limbo state, waiting for delete. if(m_machine->GetDebugMode() && m_machine->m_debugUser) { m_machine->Sys_SwitchState(this, EXCEPTION); return EXCEPTION; } #endif } } // kill the thread m_machine->Sys_SwitchState(this, KILLED); return KILLED; }
gmThread::State gmThread::PushStackFrame(int a_numParameters, const gmuint8 ** a_ip, const gmuint8 ** a_cp) { // calculate new stack base int base = m_top - a_numParameters; if( base == 2 ) // When initial thread function is ready, signal thread creation { // This may not be the best place to signal, but we at least want a valid 'this' m_base = base; // Init so some thread queries work m_machine->Sys_SignalCreateThread(this); } gmVariable * fnVar = &m_stack[base - 1]; if(fnVar->m_type != GM_FUNCTION) { m_machine->GetLog().LogEntry("attempt to call non function type"); return SYS_EXCEPTION; } gmFunctionObject * fn = (gmFunctionObject *) GM_MOBJECT(m_machine, fnVar->m_value.m_ref); if(fn->m_cFunction) { // // Its a native function call, call it now as we cannot stack wind natives. this avoids // pushing a gmStackFrame. // m_numParameters = (short) a_numParameters; int lastBase = m_base; int lastTop = m_top; m_base = base; int result = fn->m_cFunction(this); // Write barrier old local objects at native pop time { gmGarbageCollector* gc = m_machine->GetGC(); if( !gc->IsOff() ) { for(int index = m_base; index < m_top; ++index) { if(m_stack[index].IsReference()) { gmObject * object = GM_MOBJECT(m_machine, m_stack[index].m_value.m_ref); gc->WriteBarrier(object); } } } } // handle state if(result == GM_SYS_STATE) { // this is special case, a bit messy. return PushStackFrame(a_numParameters - GM_STATE_NUM_PARAMS, a_ip, a_cp); } // NOTE: It is not currently safe for a C binding to kill this thread. // Since we cant unwind mixed script and native functions anyway, // perhaps the safest thing would be for ALWAYS delay killed threads // from deletion. // push a null if the function did not return anything if(lastTop == m_top) { m_stack[m_base - 2] = gmVariable(GM_NULL, 0); } else { m_stack[m_base - 2] = m_stack[m_top - 1]; } // Restore the stack m_top = m_base - 1; m_base = lastBase; // check the call result if(result != GM_OK) { const gmuint8 * returnAddress = (a_ip) ? *a_ip : NULL; if(result == GM_SYS_YIELD) { m_machine->Sys_RemoveSignals(this); m_instruction = returnAddress; return SYS_YIELD; } else if(result == GM_SYS_BLOCK) { m_instruction = returnAddress; m_machine->Sys_SwitchState(this, BLOCKED); return BLOCKED; } else if(result == GM_SYS_SLEEP) { m_instruction = returnAddress; m_machine->Sys_SwitchState(this, SLEEPING); return SLEEPING; } else if(result == GM_SYS_KILL) { return KILLED; } return SYS_EXCEPTION; } if(!m_frame) // C called C function, no stack frame, so signal killed. { return KILLED; } // return result return RUNNING; } // // Its a script function call, push a stack frame // int clearSize = fn->GetNumParamsLocals() - a_numParameters; if(!Touch(clearSize + fn->GetMaxStackSize())) { m_machine->GetLog().LogEntry("stack overflow"); return SYS_EXCEPTION; } // zero missing params and locals. if(a_numParameters <= fn->GetNumParams()) { memset(GetTop(), 0, sizeof(gmVariable) * clearSize); } else { memset(&m_stack[base + fn->GetNumParams()], 0, sizeof(gmVariable) * fn->GetNumLocals()); } // push a new stack frame gmStackFrame * frame = m_machine->Sys_AllocStackFrame(); frame->m_prev = m_frame; m_frame = frame; // cache new frame variables m_frame->m_returnBase = m_base; if(a_ip) { m_frame->m_returnAddress = *a_ip; *a_ip = (const gmuint8 *) fn->GetByteCode(); *a_cp = *a_ip; } else { m_frame->m_returnAddress = NULL; } m_base = base; m_top = base + fn->GetNumParamsLocals(); return RUNNING; }
WfRuntimeExecutionAction WfRuntimeThreadContext::ExecuteInternal(WfInstruction& ins, WfRuntimeStackFrame& stackFrame, IWfDebuggerCallback* callback) { switch (ins.code) { case WfInsCode::LoadValue: PushValue(ins.valueParameter); return WfRuntimeExecutionAction::ExecuteInstruction; case WfInsCode::LoadClosure: { Ptr<WfRuntimeVariableContext> capturedVariables; if (ins.countParameter > 0) { capturedVariables = new WfRuntimeVariableContext; capturedVariables->variables.Resize(ins.countParameter); Value operand; for (vint i = 0; i < ins.countParameter; i++) { CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack."); capturedVariables->variables[ins.countParameter - 1 - i] = operand; } } auto lambda = MakePtr<WfRuntimeLambda>(globalContext, capturedVariables, ins.indexParameter); PushValue(Value::From(lambda)); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::LoadException: { PushValue(BoxValue(exceptionInfo)); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::LoadLocalVar: { Value operand; CONTEXT_ACTION(LoadLocalVariable(ins.indexParameter, operand), L"illegal local variable index."); PushValue(operand); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::LoadCapturedVar: { Value operand; CONTEXT_ACTION(LoadCapturedVariable(ins.indexParameter, operand), L"illegal captured variable index."); PushValue(operand); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::LoadGlobalVar: { CALL_DEBUGGER(callback->BreakRead(globalContext->assembly.Obj(), ins.indexParameter)); Value operand; CONTEXT_ACTION(LoadGlobalVariable(ins.indexParameter, operand), L"illegal global variable index."); PushValue(operand); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::StoreLocalVar: { Value operand; CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack."); CONTEXT_ACTION(StoreLocalVariable(ins.indexParameter, operand), L"illegal local variable index."); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::StoreGlobalVar: { CALL_DEBUGGER(callback->BreakWrite(globalContext->assembly.Obj(), ins.indexParameter)); Value operand; CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack."); CONTEXT_ACTION(StoreGlobalVariable(ins.indexParameter, operand), L"illegal global variable index."); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::Duplicate: { vint index = stack.Count() - 1 - ins.countParameter; Value operand; CONTEXT_ACTION(LoadStackValue(index, operand), L"failed to duplicate a value from the stack."); PushValue(operand); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::Pop: { Value operand; CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack."); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::Return: { Value operand; CONTEXT_ACTION(PopValue(operand), L"failed to pop the function result."); CONTEXT_ACTION(PopStackFrame(), L"failed to pop the stack frame."); PushValue(operand); if (stackFrames.Count() == 0) { status = WfRuntimeExecutionStatus::Finished; } return WfRuntimeExecutionAction::ExitStackFrame; } case WfInsCode::CreateArray: { auto list = IValueList::Create(); Value operand; for (vint i = 0; i < ins.countParameter; i++) { CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack."); list->Add(operand); } PushValue(Value::From(list)); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::CreateMap: { auto map = IValueDictionary::Create(); Value key, value; for (vint i = 0; i < ins.countParameter; i+=2) { CONTEXT_ACTION(PopValue(value), L"failed to pop a value from the stack."); CONTEXT_ACTION(PopValue(key), L"failed to pop a value from the stack."); map->Set(key, value); } PushValue(Value::From(map)); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::CreateInterface: { auto proxy = MakePtr<WfRuntimeInterfaceInstance>(); Value key, value; for (vint i = 0; i < ins.countParameter; i+=2) { CONTEXT_ACTION(PopValue(value), L"failed to pop a value from the stack."); CONTEXT_ACTION(PopValue(key), L"failed to pop a value from the stack."); auto name = UnboxValue<WString>(key); auto func = UnboxValue<Ptr<IValueFunctionProxy>>(value); proxy->functions.Add(name, func); } PushValue(Value::From(proxy)); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::CreateRange: BEGIN_TYPE EXECUTE(OpCreateRange, I1) EXECUTE(OpCreateRange, I2) EXECUTE(OpCreateRange, I4) EXECUTE(OpCreateRange, I8) EXECUTE(OpCreateRange, U1) EXECUTE(OpCreateRange, U2) EXECUTE(OpCreateRange, U4) EXECUTE(OpCreateRange, U8) END_TYPE case WfInsCode::ReverseEnumerable: { Value operand; CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack."); Value reversedEnumerable = OPERATOR_OpReverseEnumerable(operand); PushValue(reversedEnumerable); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::DeleteRawPtr: { Value operand; CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack."); operand.DeleteRawPtr(); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::ConvertToType: { Value result, converted; CONTEXT_ACTION(PopValue(result), L"failed to pop a value from the stack."); if (OPERATOR_OpConvertToType(result, converted, ins)) { PushValue(converted); return WfRuntimeExecutionAction::ExecuteInstruction; } else { WString from = result.IsNull() ? L"<null>" : L"<" + result.GetText() + L"> of " + result.GetTypeDescriptor()->GetTypeName(); WString to = ins.typeDescriptorParameter->GetTypeName(); RaiseException(L"Failed to convert from \"" + from + L"\" to \"" + to + L"\".", false); return WfRuntimeExecutionAction::Nop; } } case WfInsCode::TryConvertToType: { Value result, converted; CONTEXT_ACTION(PopValue(result), L"failed to pop a value from the stack."); if (OPERATOR_OpConvertToType(result, converted, ins)) { PushValue(converted); } else { PushValue(Value()); } return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::TestType: { Value operand; CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack."); if (operand.GetTypeDescriptor() && operand.GetValueType() == ins.flagParameter && operand.GetTypeDescriptor()->CanConvertTo(ins.typeDescriptorParameter)) { PushValue(BoxValue(true)); } else { PushValue(BoxValue(false)); } return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::GetType: { Value operand; CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack."); PushValue(Value::From(operand.GetTypeDescriptor())); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::Jump: { stackFrame.nextInstructionIndex = ins.indexParameter; return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::JumpIf: { Value operand; CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack."); if (UnboxValue<bool>(operand)) { stackFrame.nextInstructionIndex = ins.indexParameter; } return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::Invoke: { CONTEXT_ACTION(PushStackFrame(ins.indexParameter, ins.countParameter), L"failed to invoke a function."); return WfRuntimeExecutionAction::EnterStackFrame; } case WfInsCode::GetProperty: { Value operand; CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack."); CALL_DEBUGGER(callback->BreakGet(operand.GetRawPtr(), ins.propertyParameter)); Value result = ins.propertyParameter->GetValue(operand); PushValue(result); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::SetProperty: { Value operand, value; CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack."); CONTEXT_ACTION(PopValue(value), L"failed to pop a value from the stack."); CALL_DEBUGGER(callback->BreakSet(operand.GetRawPtr(), ins.propertyParameter)); ins.propertyParameter->SetValue(operand, value); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::InvokeProxy: { Value thisValue; CONTEXT_ACTION(PopValue(thisValue), L"failed to pop a value from the stack."); auto proxy = UnboxValue<Ptr<IValueFunctionProxy>>(thisValue); if (!proxy) { INTERNAL_ERROR(L"failed to invoke a null function proxy."); return WfRuntimeExecutionAction::Nop; } if (auto lambda = proxy.Cast<WfRuntimeLambda>()) { if (lambda->globalContext == globalContext) { CONTEXT_ACTION(PushStackFrame(lambda->functionIndex, ins.countParameter, lambda->capturedVariables), L"failed to invoke a function."); return WfRuntimeExecutionAction::EnterStackFrame; } } List<Value> arguments; for (vint i = 0; i < ins.countParameter; i++) { Value argument; CONTEXT_ACTION(PopValue(argument), L"failed to pop a value from the stack."); arguments.Insert(0, argument); } Ptr<IValueList> list = new ValueListWrapper<List<Value>*>(&arguments); Value result = proxy->Invoke(list); PushValue(result); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::InvokeMethod: { Value thisValue; CONTEXT_ACTION(PopValue(thisValue), L"failed to pop a value from the stack."); CALL_DEBUGGER(callback->BreakInvoke(thisValue.GetRawPtr(), ins.methodParameter)); if (auto staticMethod = dynamic_cast<WfStaticMethod*>(ins.methodParameter)) { if (staticMethod->GetGlobalContext() == globalContext.Obj()) { CONTEXT_ACTION(PushStackFrame(staticMethod->functionIndex, ins.countParameter, nullptr), L"failed to invoke a function."); return WfRuntimeExecutionAction::EnterStackFrame; } } Array<Value> arguments(ins.countParameter); for (vint i = 0; i < ins.countParameter; i++) { Value argument; CONTEXT_ACTION(PopValue(argument), L"failed to pop a value from the stack."); arguments[ins.countParameter - i - 1] = argument; } Value result = ins.methodParameter->Invoke(thisValue, arguments); PushValue(result); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::AttachEvent: { Value thisValue, function; CONTEXT_ACTION(PopValue(function), L"failed to pop a value from the stack."); CONTEXT_ACTION(PopValue(thisValue), L"failed to pop a value from the stack."); CALL_DEBUGGER(callback->BreakAttach(thisValue.GetRawPtr(), ins.eventParameter)); auto proxy = UnboxValue<Ptr<IValueFunctionProxy>>(function); auto handler = ins.eventParameter->Attach(thisValue, proxy); PushValue(Value::From(handler)); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::DetachEvent: { Value operand; CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack."); auto handler = UnboxValue<Ptr<IEventHandler>>(operand); CALL_DEBUGGER(callback->BreakDetach(handler->GetOwnerObject().GetRawPtr(), handler->GetOwnerEvent())); auto result = handler->Detach(); PushValue(BoxValue(result)); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::InstallTry: CONTEXT_ACTION(PushTrapFrame(ins.indexParameter), L"failed to push a trap frame"); return WfRuntimeExecutionAction::ExecuteInstruction; case WfInsCode::UninstallTry: { if (trapFrames.Count() == 0) { INTERNAL_ERROR(L"failed to pop the trap frame."); } auto frame = GetCurrentTrapFrame(); CONTEXT_ACTION(PopTrapFrame(ins.countParameter), L"failed to pop the trap frame."); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::RaiseException: { Value operand; CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack."); if (operand.GetValueType() == Value::Text) { RaiseException(operand.GetText(), false); } else if (auto info = operand.GetSharedPtr().Cast<WfRuntimeExceptionInfo>()) { RaiseException(info); } else { INTERNAL_ERROR(L"failed to raise an exception which is neither a string nor a WfRuntimeExceptionInfo."); } return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::TestElementInSet: { Value element, set; CONTEXT_ACTION(PopValue(set), L"failed to pop a value from the stack."); CONTEXT_ACTION(PopValue(element), L"failed to pop a value from the stack."); auto enumerable = UnboxValue<Ptr<IValueEnumerable>>(set); auto enumerator = enumerable->CreateEnumerator(); while (enumerator->Next()) { if (enumerator->GetCurrent() == element) { PushValue(BoxValue(true)); return WfRuntimeExecutionAction::ExecuteInstruction; } } PushValue(BoxValue(false)); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::CompareLiteral: BEGIN_TYPE EXECUTE(OpCompare, Bool) EXECUTE(OpCompare, I1) EXECUTE(OpCompare, I2) EXECUTE(OpCompare, I4) EXECUTE(OpCompare, I8) EXECUTE(OpCompare, U1) EXECUTE(OpCompare, U2) EXECUTE(OpCompare, U4) EXECUTE(OpCompare, U8) EXECUTE(OpCompare, F4) EXECUTE(OpCompare, F8) EXECUTE(OpCompare, String) END_TYPE case WfInsCode::CompareStruct: { Value first, second; CONTEXT_ACTION(PopValue(second), L"failed to pop a value from the stack."); CONTEXT_ACTION(PopValue(first), L"failed to pop a value from the stack."); if (!first.IsNull() && !first.GetTypeDescriptor()->GetValueSerializer()) { INTERNAL_ERROR(L"type" + first.GetTypeDescriptor()->GetTypeName() + L" is not a struct."); } if (!second.IsNull() && !second.GetTypeDescriptor()->GetValueSerializer()) { INTERNAL_ERROR(L"type" + second.GetTypeDescriptor()->GetTypeName() + L" is not a struct."); } if (first.GetValueType() != second.GetValueType()) { PushValue(BoxValue(false)); } else if (first.IsNull()) { PushValue(BoxValue(true)); } else { PushValue(BoxValue(first.GetText() == second.GetText())); } return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::CompareReference: { Value first, second; CONTEXT_ACTION(PopValue(second), L"failed to pop a value from the stack."); CONTEXT_ACTION(PopValue(first), L"failed to pop a value from the stack."); bool result = first.GetValueType() != Value::Text && second.GetValueType() != Value::Text && first.GetRawPtr() == second.GetRawPtr(); PushValue(BoxValue(result)); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::CompareValue: { Value first, second; CONTEXT_ACTION(PopValue(second), L"failed to pop a value from the stack."); CONTEXT_ACTION(PopValue(first), L"failed to pop a value from the stack."); switch (first.GetValueType()) { case Value::RawPtr: case Value::SharedPtr: switch (first.GetValueType()) { case Value::RawPtr: case Value::SharedPtr: PushValue(BoxValue(first.GetRawPtr() == second.GetRawPtr())); break; default: PushValue(BoxValue(false)); } break; case Value::Text: switch (first.GetValueType()) { case Value::Text: PushValue(BoxValue(first.GetText() == second.GetText())); default: PushValue(BoxValue(false)); } break; default: PushValue(BoxValue(second.IsNull())); } return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::OpNot: BEGIN_TYPE EXECUTE(OpNot_Bool, Bool) EXECUTE(OpNot, I1) EXECUTE(OpNot, I2) EXECUTE(OpNot, I4) EXECUTE(OpNot, I8) EXECUTE(OpNot, U1) EXECUTE(OpNot, U2) EXECUTE(OpNot, U4) EXECUTE(OpNot, U8) END_TYPE case WfInsCode::OpPositive: BEGIN_TYPE EXECUTE(OpPositive, I1) EXECUTE(OpPositive, I2) EXECUTE(OpPositive, I4) EXECUTE(OpPositive, I8) EXECUTE(OpPositive, U1) EXECUTE(OpPositive, U2) EXECUTE(OpPositive, U4) EXECUTE(OpPositive, U8) EXECUTE(OpPositive, F4) EXECUTE(OpPositive, F8) END_TYPE case WfInsCode::OpNegative: BEGIN_TYPE EXECUTE(OpNegative, I1) EXECUTE(OpNegative, I2) EXECUTE(OpNegative, I4) EXECUTE(OpNegative, I8) EXECUTE(OpNegative, F4) EXECUTE(OpNegative, F8) END_TYPE case WfInsCode::OpConcat: { Value first, second; CONTEXT_ACTION(PopValue(second), L"failed to pop a value from the stack."); CONTEXT_ACTION(PopValue(first), L"failed to pop a value from the stack."); PushValue(BoxValue(first.GetText() + second.GetText())); return WfRuntimeExecutionAction::ExecuteInstruction; } case WfInsCode::OpExp: BEGIN_TYPE EXECUTE(OpExp, F4) EXECUTE(OpExp, F8) END_TYPE case WfInsCode::OpAdd: BEGIN_TYPE EXECUTE(OpAdd, I1) EXECUTE(OpAdd, I2) EXECUTE(OpAdd, I4) EXECUTE(OpAdd, I8) EXECUTE(OpAdd, U1) EXECUTE(OpAdd, U2) EXECUTE(OpAdd, U4) EXECUTE(OpAdd, U8) EXECUTE(OpAdd, F4) EXECUTE(OpAdd, F8) END_TYPE case WfInsCode::OpSub: BEGIN_TYPE EXECUTE(OpSub, I1) EXECUTE(OpSub, I2) EXECUTE(OpSub, I4) EXECUTE(OpSub, I8) EXECUTE(OpSub, U1) EXECUTE(OpSub, U2) EXECUTE(OpSub, U4) EXECUTE(OpSub, U8) EXECUTE(OpSub, F4) EXECUTE(OpSub, F8) END_TYPE case WfInsCode::OpMul: BEGIN_TYPE EXECUTE(OpMul, I1) EXECUTE(OpMul, I2) EXECUTE(OpMul, I4) EXECUTE(OpMul, I8) EXECUTE(OpMul, U1) EXECUTE(OpMul, U2) EXECUTE(OpMul, U4) EXECUTE(OpMul, U8) EXECUTE(OpMul, F4) EXECUTE(OpMul, F8) END_TYPE case WfInsCode::OpDiv: BEGIN_TYPE EXECUTE(OpDiv, I1) EXECUTE(OpDiv, I2) EXECUTE(OpDiv, I4) EXECUTE(OpDiv, I8) EXECUTE(OpDiv, U1) EXECUTE(OpDiv, U2) EXECUTE(OpDiv, U4) EXECUTE(OpDiv, U8) EXECUTE(OpDiv, F4) EXECUTE(OpDiv, F8) END_TYPE case WfInsCode::OpMod: BEGIN_TYPE EXECUTE(OpMod, I1) EXECUTE(OpMod, I2) EXECUTE(OpMod, I4) EXECUTE(OpMod, I8) EXECUTE(OpMod, U1) EXECUTE(OpMod, U2) EXECUTE(OpMod, U4) EXECUTE(OpMod, U8) END_TYPE case WfInsCode::OpShl: BEGIN_TYPE EXECUTE(OpShl, I1) EXECUTE(OpShl, I2) EXECUTE(OpShl, I4) EXECUTE(OpShl, I8) EXECUTE(OpShl, U1) EXECUTE(OpShl, U2) EXECUTE(OpShl, U4) EXECUTE(OpShl, U8) END_TYPE case WfInsCode::OpShr: BEGIN_TYPE EXECUTE(OpShr, I1) EXECUTE(OpShr, I2) EXECUTE(OpShr, I4) EXECUTE(OpShr, I8) EXECUTE(OpShr, U1) EXECUTE(OpShr, U2) EXECUTE(OpShr, U4) EXECUTE(OpShr, U8) END_TYPE case WfInsCode::OpXor: BEGIN_TYPE EXECUTE(OpXor, Bool) EXECUTE(OpXor, I1) EXECUTE(OpXor, I2) EXECUTE(OpXor, I4) EXECUTE(OpXor, I8) EXECUTE(OpXor, U1) EXECUTE(OpXor, U2) EXECUTE(OpXor, U4) EXECUTE(OpXor, U8) END_TYPE case WfInsCode::OpAnd: BEGIN_TYPE EXECUTE(OpAnd_Bool, Bool) EXECUTE(OpAnd, I1) EXECUTE(OpAnd, I2) EXECUTE(OpAnd, I4) EXECUTE(OpAnd, I8) EXECUTE(OpAnd, U1) EXECUTE(OpAnd, U2) EXECUTE(OpAnd, U4) EXECUTE(OpAnd, U8) END_TYPE case WfInsCode::OpOr: BEGIN_TYPE EXECUTE(OpOr_Bool, Bool) EXECUTE(OpOr, I1) EXECUTE(OpOr, I2) EXECUTE(OpOr, I4) EXECUTE(OpOr, I8) EXECUTE(OpOr, U1) EXECUTE(OpOr, U2) EXECUTE(OpOr, U4) EXECUTE(OpOr, U8) END_TYPE case WfInsCode::OpLT: { Value operand; CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack."); vint value = UnboxValue<vint>(operand); PushValue(BoxValue(value < 0)); return WfRuntimeExecutionAction::ExecuteInstruction; } break; case WfInsCode::OpGT: { Value operand; CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack."); vint value = UnboxValue<vint>(operand); PushValue(BoxValue(value > 0)); return WfRuntimeExecutionAction::ExecuteInstruction; } break; case WfInsCode::OpLE: { Value operand; CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack."); vint value = UnboxValue<vint>(operand); PushValue(BoxValue(value <= 0)); return WfRuntimeExecutionAction::ExecuteInstruction; } break; case WfInsCode::OpGE: { Value operand; CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack."); vint value = UnboxValue<vint>(operand); PushValue(BoxValue(value >= 0)); return WfRuntimeExecutionAction::ExecuteInstruction; } break; case WfInsCode::OpEQ: { Value operand; CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack."); vint value = UnboxValue<vint>(operand); PushValue(BoxValue(value == 0)); return WfRuntimeExecutionAction::ExecuteInstruction; } break; case WfInsCode::OpNE: { Value operand; CONTEXT_ACTION(PopValue(operand), L"failed to pop a value from the stack."); vint value = UnboxValue<vint>(operand); PushValue(BoxValue(value != 0)); return WfRuntimeExecutionAction::ExecuteInstruction; } break; default: return WfRuntimeExecutionAction::Nop; } }