void VM::ExecuteFrame() { CallInfo *call = &state_->calls_.back(); Closure *cl = call->func_ ? call->func_->closure_ : nullptr; Function *proto = cl ? cl->GetPrototype() : nullptr; Value *a = nullptr; Value *b = nullptr; while (call->instruction_ < call->end_) { Instruction i = *call->instruction_++; switch (Instruction::GetOpCode(i)) { case OpType_LoadConst: a = GET_REGISTER_A(i); b = GET_CONST_VALUE(i); *a = *b; SET_NEW_TOP(a); break; case OpType_Move: a = GET_REGISTER_A(i); b = GET_REGISTER_B(i); *a = *b; SET_NEW_TOP(a); break; case OpType_Call: a = GET_REGISTER_A(i); if (Call(a, i)) return ; break; case OpType_SetTop: a = GET_REGISTER_A(i); state_->stack_.SetNewTop(a); break; case OpType_GetUpTable: GetUpTable(GET_REGISTER_A(i), GET_UPVALUE_B(i), GET_REGISTER_C(i)); break; } } // For bootstrap CallInfo, we use call->register_ as new top Value *new_top = call->func_ ? call->func_ : call->register_; // Reset top value state_->stack_.SetNewTop(new_top); // Set expect result if (call->expect_result != EXP_VALUE_COUNT_ANY) state_->stack_.SetNewTop(new_top + call->expect_result); // Pop current CallInfo, and return to last CallInfo state_->calls_.pop_back(); }
void VM::ExecuteFrame() { CallInfo *call = &state_->calls_.back(); Closure *cl = call->func_->closure_; Function *proto = cl->GetPrototype(); Value *a = nullptr; Value *b = nullptr; Value *c = nullptr; while (call->instruction_ < call->end_) { state_->CheckRunGC(); Instruction i = *call->instruction_++; switch (Instruction::GetOpCode(i)) { case OpType_LoadNil: a = GET_REGISTER_A(i); GET_REAL_VALUE(a)->SetNil(); break; case OpType_LoadBool: a = GET_REGISTER_A(i); GET_REAL_VALUE(a)->SetBool(Instruction::GetParamB(i) ? true : false); break; case OpType_LoadInt: a = GET_REGISTER_A(i); assert(call->instruction_ < call->end_); a->num_ = (*call->instruction_++).opcode_; a->type_ = ValueT_Number; break; case OpType_LoadConst: a = GET_REGISTER_A(i); b = GET_CONST_VALUE(i); *GET_REAL_VALUE(a) = *b; break; case OpType_Move: a = GET_REGISTER_A(i); b = GET_REGISTER_B(i); *GET_REAL_VALUE(a) = *GET_REAL_VALUE(b); break; case OpType_Call: a = GET_REGISTER_A(i); if (Call(a, i)) return ; break; case OpType_GetUpvalue: a = GET_REGISTER_A(i); b = GET_UPVALUE_B(i)->GetValue(); *GET_REAL_VALUE(a) = *b; break; case OpType_SetUpvalue: a = GET_REGISTER_A(i); b = GET_UPVALUE_B(i)->GetValue(); *b = *a; break; case OpType_GetGlobal: a = GET_REGISTER_A(i); b = GET_CONST_VALUE(i); *GET_REAL_VALUE(a) = state_->global_.table_->GetValue(*b); break; case OpType_SetGlobal: a = GET_REGISTER_A(i); b = GET_CONST_VALUE(i); state_->global_.table_->SetValue(*b, *a); break; case OpType_Closure: a = GET_REGISTER_A(i); GenerateClosure(a, i); break; case OpType_VarArg: a = GET_REGISTER_A(i); CopyVarArg(a, i); break; case OpType_Ret: a = GET_REGISTER_A(i); return Return(a, i); case OpType_JmpFalse: a = GET_REGISTER_A(i); if (GET_REAL_VALUE(a)->IsFalse()) call->instruction_ += -1 + Instruction::GetParamsBx(i); break; case OpType_JmpTrue: a = GET_REGISTER_A(i); if (!GET_REAL_VALUE(a)->IsFalse()) call->instruction_ += -1 + Instruction::GetParamsBx(i); break; case OpType_JmpNil: a = GET_REGISTER_A(i); if (a->type_ == ValueT_Nil) call->instruction_ += -1 + Instruction::GetParamsBx(i); break; case OpType_Jmp: call->instruction_ += -1 + Instruction::GetParamsBx(i); break; case OpType_Neg: a = GET_REGISTER_A(i); CheckType(a, ValueT_Number, "neg"); a->num_ = -a->num_; break; case OpType_Not: a = GET_REGISTER_A(i); a->SetBool(a->IsFalse() ? true : false); break; case OpType_Len: a = GET_REGISTER_A(i); if (a->type_ == ValueT_Table) a->num_ = a->table_->ArraySize(); else if (a->type_ == ValueT_String) a->num_ = a->str_->GetLength(); else ReportTypeError(a, "length of"); a->type_ = ValueT_Number; break; case OpType_Add: GET_REGISTER_ABC(i); CheckArithType(b, c, "add"); a->num_ = b->num_ + c->num_; a->type_ = ValueT_Number; break; case OpType_Sub: GET_REGISTER_ABC(i); CheckArithType(b, c, "sub"); a->num_ = b->num_ - c->num_; a->type_ = ValueT_Number; break; case OpType_Mul: GET_REGISTER_ABC(i); CheckArithType(b, c, "multiply"); a->num_ = b->num_ * c->num_; a->type_ = ValueT_Number; break; case OpType_Div: GET_REGISTER_ABC(i); CheckArithType(b, c, "div"); a->num_ = b->num_ / c->num_; a->type_ = ValueT_Number; break; case OpType_Pow: GET_REGISTER_ABC(i); CheckArithType(b, c, "power"); a->num_ = pow(b->num_, c->num_); a->type_ = ValueT_Number; break; case OpType_Mod: GET_REGISTER_ABC(i); CheckArithType(b, c, "mod"); a->num_ = fmod(b->num_, c->num_); a->type_ = ValueT_Number; break; case OpType_Concat: GET_REGISTER_ABC(i); Concat(a, b, c); break; case OpType_Less: GET_REGISTER_ABC(i); CheckInequalityType(b, c, "compare(<)"); if (b->type_ == ValueT_Number) a->SetBool(b->num_ < c->num_); else a->SetBool(*b->str_ < *c->str_); break; case OpType_Greater: GET_REGISTER_ABC(i); CheckInequalityType(b, c, "compare(>)"); if (b->type_ == ValueT_Number) a->SetBool(b->num_ > c->num_); else a->SetBool(*b->str_ > *c->str_); break; case OpType_Equal: GET_REGISTER_ABC(i); a->SetBool(*b == *c); break; case OpType_UnEqual: GET_REGISTER_ABC(i); a->SetBool(*b != *c); break; case OpType_LessEqual: GET_REGISTER_ABC(i); CheckInequalityType(b, c, "compare(<=)"); if (b->type_ == ValueT_Number) a->SetBool(b->num_ <= c->num_); else a->SetBool(*b->str_ <= *c->str_); break; case OpType_GreaterEqual: GET_REGISTER_ABC(i); CheckInequalityType(b, c, "compare(>=)"); if (b->type_ == ValueT_Number) a->SetBool(b->num_ >= c->num_); else a->SetBool(*b->str_ >= *c->str_); break; case OpType_NewTable: a = GET_REGISTER_A(i); a->table_ = state_->NewTable(); a->type_ = ValueT_Table; break; case OpType_SetTable: GET_REGISTER_ABC(i); CheckTableType(a, b, "set", "to"); if (a->type_ == ValueT_Table) a->table_->SetValue(*b, *c); else if (a->type_ == ValueT_UserData) a->user_data_->GetMetatable()->SetValue(*b, *c); else assert(0); break; case OpType_GetTable: GET_REGISTER_ABC(i); CheckTableType(a, b, "get", "from"); if (a->type_ == ValueT_Table) *c = a->table_->GetValue(*b); else if (a->type_ == ValueT_UserData) *c = a->user_data_->GetMetatable()->GetValue(*b); else assert(0); break; case OpType_ForInit: GET_REGISTER_ABC(i); ForInit(a, b, c); break; case OpType_ForStep: GET_REGISTER_ABC(i); i = *call->instruction_++; if ((c->num_ > 0.0 && a->num_ > b->num_) || (c->num_ <= 0.0 && a->num_ < b->num_)) call->instruction_ += -1 + Instruction::GetParamsBx(i); break; default: break; } } Value *new_top = call->func_; // Reset top value state_->stack_.SetNewTop(new_top); // Set expect results if (call->expect_result_ != EXP_VALUE_COUNT_ANY) state_->stack_.SetNewTop(new_top + call->expect_result_); // Pop current CallInfo, and return to last CallInfo state_->calls_.pop_back(); }