443 lines
17 KiB
C++
443 lines
17 KiB
C++
/*!
|
||
@file src/VM/VM.cpp
|
||
@brief 虚拟机核心执行引擎实现
|
||
*/
|
||
|
||
#include <Core/Core.hpp>
|
||
#include <VM/VM.hpp>
|
||
|
||
#define BINARY_ARITHMETIC_OP(opName, op) \
|
||
do_##opName: \
|
||
{ \
|
||
std::uint8_t a = decodeA(inst); \
|
||
std::uint8_t b = decodeB(inst); \
|
||
std::uint8_t c = decodeC(inst); \
|
||
Value lhs = currentFrame->registerBase[b]; \
|
||
Value rhs = currentFrame->registerBase[c]; \
|
||
if (lhs.IsInt() && rhs.IsInt()) [[likely]] \
|
||
{ \
|
||
currentFrame->registerBase[a] = Value::FromInt(lhs.AsInt() op rhs.AsInt()); \
|
||
} \
|
||
else if (lhs.IsDouble() && rhs.IsDouble()) [[likely]] \
|
||
{ \
|
||
currentFrame->registerBase[a] = Value::FromDouble(lhs.AsDouble() op rhs.AsDouble()); \
|
||
} \
|
||
else if (lhs.IsInt() && rhs.IsDouble()) [[likely]] \
|
||
{ \
|
||
currentFrame->registerBase[a] = Value::FromDouble(lhs.AsInt() op rhs.AsDouble()); \
|
||
} \
|
||
else if (lhs.IsDouble() && rhs.IsInt()) [[likely]] \
|
||
{ \
|
||
currentFrame->registerBase[a] = Value::FromDouble(lhs.AsDouble() op rhs.AsInt()); \
|
||
} \
|
||
else \
|
||
{ \
|
||
assert(false && "VM Runtime Error: Unsupported types for arithmetic operation"); \
|
||
} \
|
||
DISPATCH(); \
|
||
}
|
||
|
||
#define BINARY_COMPARE_OP(opName, op) \
|
||
do_##opName: \
|
||
{ \
|
||
std::uint8_t a = decodeA(inst); \
|
||
std::uint8_t b = decodeB(inst); \
|
||
std::uint8_t c = decodeC(inst); \
|
||
Value lhs = currentFrame->registerBase[b]; \
|
||
Value rhs = currentFrame->registerBase[c]; \
|
||
if (lhs.IsInt() && rhs.IsInt()) [[likely]] \
|
||
{ \
|
||
currentFrame->registerBase[a] = (lhs.AsInt() op rhs.AsInt()) ? \
|
||
Value::GetTrueInstance() : \
|
||
Value::GetFalseInstance(); \
|
||
} \
|
||
else if (lhs.IsDouble() && rhs.IsDouble()) [[likely]] \
|
||
{ \
|
||
currentFrame->registerBase[a] = (lhs.AsDouble() op rhs.AsDouble()) ? \
|
||
Value::GetTrueInstance() : \
|
||
Value::GetFalseInstance(); \
|
||
} \
|
||
else if (lhs.IsInt() && rhs.IsDouble()) [[likely]] \
|
||
{ \
|
||
currentFrame->registerBase[a] = (lhs.AsInt() op rhs.AsDouble()) ? \
|
||
Value::GetTrueInstance() : \
|
||
Value::GetFalseInstance(); \
|
||
} \
|
||
else if (lhs.IsDouble() && rhs.IsInt()) [[likely]] \
|
||
{ \
|
||
currentFrame->registerBase[a] = (lhs.AsDouble() op rhs.AsInt()) ? \
|
||
Value::GetTrueInstance() : \
|
||
Value::GetFalseInstance(); \
|
||
} \
|
||
else \
|
||
{ \
|
||
assert(false && "VM Runtime Error: Unsupported types for comparison"); \
|
||
} \
|
||
DISPATCH(); \
|
||
}
|
||
|
||
namespace Fig
|
||
{
|
||
Result<Value, Error> VM::Execute(CompiledModule *compiledModule)
|
||
{
|
||
Proto *entry = compiledModule->protos[0];
|
||
(void) pushFrame(entry, registers); // 刚开始执行寄存器不会溢出
|
||
|
||
// 对齐 Bytecode.hpp 中的 OpCode 顺序
|
||
static const void *dispatchTable[] = {&&do_Exit,
|
||
&&do_Exit_MaxRecursionDepthExceeded,
|
||
|
||
&&do_LoadK,
|
||
&&do_LoadTrue,
|
||
&&do_LoadFalse,
|
||
&&do_LoadNull,
|
||
|
||
&&do_FastCall,
|
||
&&do_Call,
|
||
&&do_Return,
|
||
|
||
&&do_LoadFn,
|
||
|
||
&&do_Jmp,
|
||
&&do_JmpIfFalse,
|
||
|
||
&&do_Mov,
|
||
|
||
&&do_Add,
|
||
&&do_Sub,
|
||
&&do_Mul,
|
||
&&do_Div,
|
||
&&do_Mod,
|
||
&&do_BitXor,
|
||
|
||
&&do_IntFastAdd,
|
||
&&do_IntFastSub,
|
||
&&do_IntFastMul,
|
||
&&do_IntFastDiv,
|
||
|
||
&&do_Equal,
|
||
&&do_NotEqual,
|
||
&&do_Greater,
|
||
&&do_Less,
|
||
&&do_GreaterEqual,
|
||
&&do_LessEqual,
|
||
|
||
&&do_GetGlobal,
|
||
&&do_SetGlobal,
|
||
&&do_GetUpval,
|
||
&&do_SetUpval,
|
||
&&do_Copy,
|
||
|
||
&&do_Count};
|
||
|
||
Instruction inst;
|
||
|
||
#define DISPATCH() \
|
||
do \
|
||
{ \
|
||
inst = *(currentFrame->ip++); \
|
||
goto *dispatchTable[inst & 0xFF]; \
|
||
} while (0)
|
||
|
||
// 引擎点火!! :3
|
||
DISPATCH();
|
||
|
||
do_Exit: {
|
||
return Value::FromInt(decodeSBx(inst));
|
||
}
|
||
|
||
do_Exit_MaxRecursionDepthExceeded: {
|
||
CoreIO::GetStdErr() << std::format(
|
||
"Oops! max recursion depth limit {} exceeded in Fn `{}` , exiting...\n",
|
||
MAX_RECURSION_DEPTH,
|
||
(currentFrame - 1)->proto->name); // pushFrame失败了,但currentFrame仍然移动,所以
|
||
// (currentFrame - 1)是 lastFrame
|
||
std::exit(static_cast<int>(MAX_RECURSION_DEPTH));
|
||
}
|
||
|
||
do_LoadK: {
|
||
std::uint8_t a = decodeA(inst);
|
||
std::uint16_t bx = decodeBx(inst);
|
||
currentFrame->registerBase[a] = currentFrame->getConstant(bx);
|
||
DISPATCH();
|
||
}
|
||
|
||
do_LoadTrue: {
|
||
std::uint8_t a = decodeA(inst);
|
||
currentFrame->registerBase[a] = Value::GetTrueInstance();
|
||
DISPATCH();
|
||
}
|
||
|
||
do_LoadFalse: {
|
||
std::uint8_t a = decodeA(inst);
|
||
currentFrame->registerBase[a] = Value::GetFalseInstance();
|
||
DISPATCH();
|
||
}
|
||
|
||
do_LoadNull: {
|
||
std::uint8_t a = decodeA(inst);
|
||
currentFrame->registerBase[a] = Value::GetNullInstance();
|
||
DISPATCH();
|
||
}
|
||
|
||
do_FastCall: {
|
||
std::uint8_t a = decodeA(inst);
|
||
Proto *proto = compiledModule->protos[a];
|
||
std::uint8_t baseReg = decodeB(inst);
|
||
|
||
currentFrame->ip = pushFrame(proto, currentFrame->registerBase + baseReg);
|
||
|
||
DISPATCH();
|
||
}
|
||
|
||
do_Call: {
|
||
// TODO: FunctionObject 动态解包
|
||
|
||
std::uint8_t a = decodeA(inst);
|
||
std::uint8_t baseReg = decodeB(inst);
|
||
|
||
Value callee = currentFrame->registerBase[a];
|
||
|
||
FunctionObject *closure = nullptr;
|
||
|
||
if (!callee.IsObject())
|
||
{
|
||
size_t ipIdx = currentFrame->ip - currentFrame->proto->code.data();
|
||
|
||
return std::unexpected(Error(ErrorType::TypeError,
|
||
std::format("Object `{}` is not callable", callee.ToString()),
|
||
"none",
|
||
*currentFrame->proto->locations[ipIdx]));
|
||
}
|
||
else [[likely]]
|
||
{
|
||
|
||
Object *obj = callee.AsObject();
|
||
if (!obj->isFunction())
|
||
{
|
||
size_t ipIdx = currentFrame->ip - currentFrame->proto->code.data();
|
||
|
||
return std::unexpected(Error(ErrorType::TypeError,
|
||
std::format("Object `{}` is not callable", callee.ToString()),
|
||
"none",
|
||
*currentFrame->proto->locations[ipIdx]));
|
||
}
|
||
closure = static_cast<FunctionObject *>(obj);
|
||
}
|
||
|
||
currentFrame->ip = pushFrame(closure, currentFrame->registerBase + baseReg);
|
||
|
||
DISPATCH();
|
||
}
|
||
|
||
do_Return: {
|
||
std::uint8_t a = decodeA(inst);
|
||
Value retVal = currentFrame->registerBase[a];
|
||
|
||
closeUpvalues(currentFrame->registerBase);
|
||
|
||
// 此时 registerBase[0] 指向的是 Caller 的 baseReg 槽位
|
||
currentFrame->registerBase[0] = retVal;
|
||
popFrame();
|
||
|
||
DISPATCH();
|
||
}
|
||
|
||
do_LoadFn: {
|
||
std::uint8_t a = decodeA(inst);
|
||
std::uint16_t bx = decodeBx(inst);
|
||
|
||
Proto *p = compiledModule->protos[bx];
|
||
|
||
size_t upValSize = p->upvalues.size();
|
||
size_t extraSize = upValSize * sizeof(Upvalue *);
|
||
|
||
FunctionObject *closure =
|
||
(FunctionObject *) allocateObject<FunctionObject>(ObjectType::Function, extraSize);
|
||
|
||
// CoreIO::GetStdErr() << "DEBUG: p->name = " << p->name << '\n';
|
||
new (&closure->name) String(p->name); // String非平凡类型,有自己的构造函数
|
||
closure->proto = p;
|
||
closure->paraCount = p->numParams;
|
||
closure->upvalueCount = static_cast<std::uint32_t>(upValSize);
|
||
|
||
for (size_t i = 0; i < closure->upvalueCount; ++i)
|
||
{
|
||
auto &info = p->upvalues[i];
|
||
if (info.isLocal)
|
||
{
|
||
Value *targetSlot = ¤tFrame->registerBase[info.index];
|
||
Upvalue *prev = nullptr;
|
||
Upvalue *curr = openUpvalues;
|
||
|
||
while (curr != nullptr && curr->location > targetSlot)
|
||
{
|
||
prev = curr;
|
||
curr = curr->next;
|
||
}
|
||
|
||
if (curr != nullptr && curr->location == targetSlot)
|
||
{
|
||
// 如果别的闭包已经捕获了这个槽位,共享物理指针
|
||
closure->upvalues[i] = curr;
|
||
++curr->refCount;
|
||
}
|
||
else
|
||
{
|
||
// 首次捕获
|
||
Upvalue *uv = new Upvalue;
|
||
|
||
uv->location = targetSlot;
|
||
uv->next = curr;
|
||
++uv->refCount;
|
||
|
||
if (prev == nullptr)
|
||
openUpvalues = uv;
|
||
else
|
||
prev->next = uv;
|
||
closure->upvalues[i] = uv;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
closure->upvalues[i] = currentFrame->closure->upvalues[info.index];
|
||
}
|
||
}
|
||
|
||
currentFrame->registerBase[a] = Value::FromObject(closure);
|
||
DISPATCH();
|
||
}
|
||
|
||
do_Jmp: {
|
||
std::int16_t sbx = decodeSBx(inst);
|
||
currentFrame->ip += sbx;
|
||
DISPATCH();
|
||
}
|
||
|
||
do_JmpIfFalse: {
|
||
std::uint8_t a = decodeA(inst);
|
||
Value &v = currentFrame->registerBase[a];
|
||
if (!v.AsBool())
|
||
{
|
||
std::int16_t sbx = decodeSBx(inst);
|
||
currentFrame->ip += sbx;
|
||
}
|
||
DISPATCH();
|
||
}
|
||
|
||
do_Mov: {
|
||
std::uint8_t a = decodeA(inst);
|
||
std::uint16_t bx = decodeBx(inst);
|
||
currentFrame->registerBase[a] = currentFrame->registerBase[bx];
|
||
DISPATCH();
|
||
}
|
||
|
||
BINARY_ARITHMETIC_OP(Add, +);
|
||
BINARY_ARITHMETIC_OP(Sub, -);
|
||
BINARY_ARITHMETIC_OP(Mul, *);
|
||
BINARY_ARITHMETIC_OP(Div, /);
|
||
|
||
do_Mod:
|
||
do_BitXor:
|
||
assert(false && "VM: Mod and BitXor not fully implemented yet!");
|
||
DISPATCH();
|
||
|
||
do_IntFastAdd: {
|
||
std::uint8_t a = decodeA(inst);
|
||
std::uint8_t b = decodeB(inst);
|
||
std::uint8_t c = decodeC(inst);
|
||
|
||
Value l = currentFrame->registerBase[b];
|
||
Value r = currentFrame->registerBase[c];
|
||
|
||
currentFrame->registerBase[a] = Value::FromInt(l.AsInt() + r.AsInt());
|
||
DISPATCH();
|
||
}
|
||
|
||
do_IntFastSub: {
|
||
std::uint8_t a = decodeA(inst);
|
||
std::uint8_t b = decodeB(inst);
|
||
std::uint8_t c = decodeC(inst);
|
||
|
||
Value l = currentFrame->registerBase[b];
|
||
Value r = currentFrame->registerBase[c];
|
||
|
||
currentFrame->registerBase[a] = Value::FromInt(l.AsInt() - r.AsInt());
|
||
DISPATCH();
|
||
}
|
||
|
||
do_IntFastMul: {
|
||
std::uint8_t a = decodeA(inst);
|
||
std::uint8_t b = decodeB(inst);
|
||
std::uint8_t c = decodeC(inst);
|
||
|
||
Value l = currentFrame->registerBase[b];
|
||
Value r = currentFrame->registerBase[c];
|
||
|
||
currentFrame->registerBase[a] = Value::FromInt(l.AsInt() * r.AsInt());
|
||
DISPATCH();
|
||
}
|
||
|
||
do_IntFastDiv: {
|
||
std::uint8_t a = decodeA(inst);
|
||
std::uint8_t b = decodeB(inst);
|
||
std::uint8_t c = decodeC(inst);
|
||
|
||
Value l = currentFrame->registerBase[b];
|
||
Value r = currentFrame->registerBase[c];
|
||
|
||
currentFrame->registerBase[a] =
|
||
Value::FromDouble(static_cast<double>(l.AsInt()) / r.AsInt());
|
||
DISPATCH();
|
||
}
|
||
|
||
BINARY_COMPARE_OP(Equal, ==);
|
||
BINARY_COMPARE_OP(NotEqual, !=);
|
||
BINARY_COMPARE_OP(Greater, >);
|
||
BINARY_COMPARE_OP(Less, <);
|
||
BINARY_COMPARE_OP(GreaterEqual, >=);
|
||
BINARY_COMPARE_OP(LessEqual, <=);
|
||
|
||
do_GetGlobal: {
|
||
std::uint8_t a = decodeA(inst);
|
||
std::uint16_t bx = decodeBx(inst);
|
||
currentFrame->registerBase[a] = globals[bx];
|
||
DISPATCH();
|
||
}
|
||
|
||
do_SetGlobal: {
|
||
std::uint8_t a = decodeA(inst);
|
||
std::uint16_t bx = decodeBx(inst);
|
||
globals[bx] = currentFrame->registerBase[a];
|
||
DISPATCH();
|
||
}
|
||
|
||
do_GetUpval: {
|
||
std::uint8_t a = decodeA(inst);
|
||
std::uint8_t b = decodeB(inst);
|
||
|
||
currentFrame->registerBase[a] = *(currentFrame->closure->upvalues[b]->location);
|
||
DISPATCH();
|
||
}
|
||
|
||
do_SetUpval: {
|
||
std::uint8_t a = decodeA(inst);
|
||
std::uint8_t b = decodeB(inst);
|
||
*(currentFrame->closure->upvalues[b]->location) = currentFrame->registerBase[a]; // copy
|
||
DISPATCH();
|
||
}
|
||
|
||
do_Copy: {
|
||
std::uint8_t a = decodeA(inst);
|
||
std::uint8_t b = decodeB(inst);
|
||
currentFrame->registerBase[a] = currentFrame->registerBase[b];
|
||
DISPATCH();
|
||
}
|
||
|
||
do_Count: {
|
||
assert(false && "Hit Count sentinel!");
|
||
return Value::GetNullInstance();
|
||
}
|
||
}
|
||
}; // namespace Fig
|