对编译器和虚拟机进行重构,以支持闭包和垃圾回收功能
- 去除了不再使用的结构,并更新了编译器以处理新的闭包语义。 - 改进了 Compiler,使其能够生成带有源位置跟踪的指令。 - 在 FunctionObject 和 VM 中引入了作用域变量管理,以支持动态闭包。 - 实现了使用标记-扫描(Mark-And-Sweep) (Tri-Color tracing) 算法的垃圾回收机制,包括对作用域变量的处理。 - 在 VM 中增加了函数加载和作用域变量检索的支持。 - 更新了对象模型,包括引入 InstanceObject 并改进内存管理。 - 添加了用于调试的全局变量打印功能。
This commit is contained in:
11
ExampleCodes/SpeedTest/fib.lua
Normal file
11
ExampleCodes/SpeedTest/fib.lua
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
function fib(n)
|
||||||
|
if (n <= 1) then
|
||||||
|
return n
|
||||||
|
else
|
||||||
|
return fib(n - 1) + fib(n - 2) end
|
||||||
|
end
|
||||||
|
|
||||||
|
local start = os.clock()
|
||||||
|
local result = fib(30)
|
||||||
|
local endt = os.clock()
|
||||||
|
print(result, " cost: ", (endt - start) * 1000, "ms")
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <Ast/Base.hpp>
|
#include <Ast/Base.hpp>
|
||||||
#include <Sema/Environment.hpp>
|
#include <Sema/Environment.hpp>
|
||||||
|
#include <Bytecode/Bytecode.hpp>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
@@ -33,6 +34,9 @@ namespace Fig
|
|||||||
Type resolvedReturnType;
|
Type resolvedReturnType;
|
||||||
Symbol *resolvedSymbol = nullptr; // 连接物理符号
|
Symbol *resolvedSymbol = nullptr; // 连接物理符号
|
||||||
|
|
||||||
|
int protoIndex = -1; // 在CompiledModule扁平化protos的下标
|
||||||
|
DynArray<UpvalueInfo> upvalues;
|
||||||
|
|
||||||
FnDefStmt() { type = AstType::FnDefStmt; }
|
FnDefStmt() { type = AstType::FnDefStmt; }
|
||||||
FnDefStmt(bool _p, String _n, DynArray<Param *> _pa, TypeExpr *_rt, BlockStmt *_b, SourceLocation _loc)
|
FnDefStmt(bool _p, String _n, DynArray<Param *> _pa, TypeExpr *_rt, BlockStmt *_b, SourceLocation _loc)
|
||||||
: name(std::move(_n)), params(std::move(_pa)), returnTypeSpecifier(_rt), body(_b)
|
: name(std::move(_n)), params(std::move(_pa)), returnTypeSpecifier(_rt), body(_b)
|
||||||
|
|||||||
@@ -5,8 +5,13 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <Deps/Deps.hpp>
|
||||||
|
#include <Object/ObjectBase.hpp>
|
||||||
|
#include <Core/SourceLocations.hpp>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
using Instruction = std::uint32_t;
|
using Instruction = std::uint32_t;
|
||||||
@@ -80,4 +85,27 @@ namespace Fig
|
|||||||
| (static_cast<std::uint32_t>(static_cast<std::uint16_t>(sbx)) << 16);
|
| (static_cast<std::uint32_t>(static_cast<std::uint16_t>(sbx)) << 16);
|
||||||
}
|
}
|
||||||
} // namespace Op
|
} // namespace Op
|
||||||
|
|
||||||
|
struct UpvalueInfo
|
||||||
|
{
|
||||||
|
uint8_t index;
|
||||||
|
bool isLocal;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Proto
|
||||||
|
{
|
||||||
|
String name;
|
||||||
|
DynArray<Instruction> code;
|
||||||
|
DynArray<SourceLocation *> locations;
|
||||||
|
DynArray<Value> constants;
|
||||||
|
DynArray<UpvalueInfo> upvalues;
|
||||||
|
uint8_t maxRegisters = 0;
|
||||||
|
uint8_t numParams = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CompiledModule
|
||||||
|
{
|
||||||
|
DynArray<Proto *> protos;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Fig
|
} // namespace Fig
|
||||||
|
|||||||
@@ -3,16 +3,20 @@
|
|||||||
@brief 编译器主逻辑实现:物理 Bootstrapper 与双步扫描
|
@brief 编译器主逻辑实现:物理 Bootstrapper 与双步扫描
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Compiler/Compiler.hpp>
|
|
||||||
#include <Ast/Stmt/FnDefStmt.hpp>
|
#include <Ast/Stmt/FnDefStmt.hpp>
|
||||||
|
#include <Compiler/Compiler.hpp>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
Result<CompiledModule *, Error> Compiler::Compile(Program *program)
|
Result<CompiledModule *, Error> Compiler::Compile(Program *program)
|
||||||
{
|
{
|
||||||
module = new CompiledModule();
|
module = new CompiledModule();
|
||||||
|
if (program->nodes.empty())
|
||||||
|
{
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
// 1. 预留 Protos[0] 给 Bootstrapper
|
// 预留 Protos[0] 给 Bootstrapper
|
||||||
Proto *bootProto = new Proto();
|
Proto *bootProto = new Proto();
|
||||||
bootProto->name = "[bootstrapper]";
|
bootProto->name = "[bootstrapper]";
|
||||||
module->protos.push_back(bootProto);
|
module->protos.push_back(bootProto);
|
||||||
@@ -20,17 +24,22 @@ namespace Fig
|
|||||||
int initIdx = -1;
|
int initIdx = -1;
|
||||||
int mainIdx = -1;
|
int mainIdx = -1;
|
||||||
|
|
||||||
// 2. 第一步:预扫描顶层函数,锁定物理索引
|
SourceLocation *mainFnLoc = nullptr;
|
||||||
|
SourceLocation *initFnLoc = nullptr;
|
||||||
|
|
||||||
|
// 预扫描顶层函数
|
||||||
for (auto *stmt : program->nodes)
|
for (auto *stmt : program->nodes)
|
||||||
{
|
{
|
||||||
if (stmt->type == AstType::FnDefStmt)
|
if (stmt->type == AstType::FnDefStmt)
|
||||||
{
|
{
|
||||||
auto *f = static_cast<FnDefStmt *>(stmt);
|
auto *f = static_cast<FnDefStmt *>(stmt);
|
||||||
int idx = (int) module->protos.size();
|
int idx = (int) module->protos.size();
|
||||||
|
|
||||||
Proto *p = new Proto();
|
Proto *p = new Proto();
|
||||||
p->name = f->name;
|
p->name = f->name;
|
||||||
p->numParams = (uint8_t) f->params.size();
|
p->numParams = (uint8_t) f->params.size();
|
||||||
p->maxRegisters = p->numParams;
|
p->maxRegisters = p->numParams;
|
||||||
|
f->protoIndex = idx;
|
||||||
|
|
||||||
module->protos.push_back(p);
|
module->protos.push_back(p);
|
||||||
|
|
||||||
@@ -41,13 +50,19 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (f->name == "init")
|
if (f->name == "init")
|
||||||
initIdx = idx;
|
{
|
||||||
|
initIdx = idx;
|
||||||
|
initFnLoc = &stmt->location;
|
||||||
|
}
|
||||||
if (f->name == "main")
|
if (f->name == "main")
|
||||||
mainIdx = idx;
|
{
|
||||||
|
mainIdx = idx;
|
||||||
|
mainFnLoc = &stmt->location;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 第二步:在 Bootstrapper 环境中编译所有语句
|
// Bootstrapper 中编译所有语句
|
||||||
FuncState bootState(bootProto, nullptr);
|
FuncState bootState(bootProto, nullptr);
|
||||||
current = &bootState;
|
current = &bootState;
|
||||||
|
|
||||||
@@ -60,18 +75,18 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. 发射 Bootstrapper 引导指令
|
// 发射 Bootstrapper 引导指令
|
||||||
if (initIdx != -1)
|
if (initIdx != -1)
|
||||||
{
|
{
|
||||||
emit(Op::iABC(OpCode::FastCall, (uint8_t) initIdx, 0, 0));
|
emit(Op::iABC(OpCode::FastCall, (uint8_t) initIdx, 0, 0), initFnLoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mainIdx != -1)
|
if (mainIdx != -1)
|
||||||
{
|
{
|
||||||
emit(Op::iABC(OpCode::FastCall, (uint8_t) mainIdx, 0, 0));
|
emit(Op::iABC(OpCode::FastCall, (uint8_t) mainIdx, 0, 0), mainFnLoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit(Op::iAsBx(OpCode::Exit, 0, 0));
|
emit(Op::iAsBx(OpCode::Exit, 0, 0), &program->nodes.back()->location);
|
||||||
|
|
||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
@@ -89,7 +104,8 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
if (current->freereg >= MAX_REGISTERS)
|
if (current->freereg >= MAX_REGISTERS)
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::RegisterOverflow, "too many registers", "", loc));
|
return std::unexpected(
|
||||||
|
Error(ErrorType::RegisterOverflow, "too many registers", "", loc));
|
||||||
}
|
}
|
||||||
|
|
||||||
Register reg = current->freereg++;
|
Register reg = current->freereg++;
|
||||||
@@ -112,14 +128,15 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
if (current->constantMap.contains(val))
|
if (current->constantMap.contains(val))
|
||||||
return current->constantMap[val];
|
return current->constantMap[val];
|
||||||
int idx = (int) current->proto->constants.size();
|
int idx = (int) current->proto->constants.size();
|
||||||
current->proto->constants.push_back(val);
|
current->proto->constants.push_back(val);
|
||||||
current->constantMap[val] = idx;
|
current->constantMap[val] = idx;
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compiler::emit(Instruction instr)
|
void Compiler::emit(Instruction inst, SourceLocation *loc)
|
||||||
{
|
{
|
||||||
current->proto->code.push_back(instr);
|
current->proto->code.push_back(inst);
|
||||||
|
current->proto->locations.push_back(loc);
|
||||||
}
|
}
|
||||||
} // namespace Fig
|
} // namespace Fig
|
||||||
|
|||||||
@@ -14,23 +14,6 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
using Register = std::uint8_t;
|
using Register = std::uint8_t;
|
||||||
|
|
||||||
struct UpvalueInfo { uint8_t index; bool isLocal; };
|
|
||||||
|
|
||||||
struct Proto
|
|
||||||
{
|
|
||||||
String name;
|
|
||||||
DynArray<Instruction> code;
|
|
||||||
DynArray<Value> constants;
|
|
||||||
DynArray<UpvalueInfo> upvalues;
|
|
||||||
uint8_t maxRegisters = 0;
|
|
||||||
uint8_t numParams = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CompiledModule
|
|
||||||
{
|
|
||||||
DynArray<Proto *> protos;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Compiler
|
class Compiler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@@ -60,7 +43,7 @@ namespace Fig
|
|||||||
void freeReg(Register count = 1);
|
void freeReg(Register count = 1);
|
||||||
int addConstant(Value val);
|
int addConstant(Value val);
|
||||||
|
|
||||||
void emit(Instruction instr);
|
void emit(Instruction inst, SourceLocation *loc);
|
||||||
|
|
||||||
Result<void, Error> compileStmt(Stmt *stmt);
|
Result<void, Error> compileStmt(Stmt *stmt);
|
||||||
Result<Register, Error> compileExpr(Expr *expr, Register target = NO_REG);
|
Result<Register, Error> compileExpr(Expr *expr, Register target = NO_REG);
|
||||||
|
|||||||
@@ -94,24 +94,24 @@ namespace Fig
|
|||||||
parsePhysicalNumber(manager.GetSub(tok.index, tok.length), l->location);
|
parsePhysicalNumber(manager.GetSub(tok.index, tok.length), l->location);
|
||||||
if (!vRes)
|
if (!vRes)
|
||||||
return std::unexpected(vRes.error());
|
return std::unexpected(vRes.error());
|
||||||
emit(Op::iABx(OpCode::LoadK, r, static_cast<uint16_t>(addConstant(*vRes))));
|
emit(Op::iABx(OpCode::LoadK, r, static_cast<uint16_t>(addConstant(*vRes))), &l->location);
|
||||||
}
|
}
|
||||||
else if (tok.type == TokenType::LiteralString)
|
else if (tok.type == TokenType::LiteralString)
|
||||||
{
|
{
|
||||||
int kIdx = addConstant(Value::GetNullInstance()); // TODO: String 支持
|
int kIdx = addConstant(Value::GetNullInstance()); // TODO: String 支持
|
||||||
emit(Op::iABx(OpCode::LoadK, r, static_cast<uint16_t>(kIdx)));
|
emit(Op::iABx(OpCode::LoadK, r, static_cast<uint16_t>(kIdx)), &l->location);
|
||||||
}
|
}
|
||||||
else if (tok.type == TokenType::LiteralNull)
|
else if (tok.type == TokenType::LiteralNull)
|
||||||
{
|
{
|
||||||
emit(Op::iABC(OpCode::LoadNull, r, 0, 0));
|
emit(Op::iABC(OpCode::LoadNull, r, 0, 0), &l->location);
|
||||||
}
|
}
|
||||||
else if (tok.type == TokenType::LiteralTrue)
|
else if (tok.type == TokenType::LiteralTrue)
|
||||||
{
|
{
|
||||||
emit(Op::iABC(OpCode::LoadTrue, r, 0, 0));
|
emit(Op::iABC(OpCode::LoadTrue, r, 0, 0), &l->location);
|
||||||
}
|
}
|
||||||
else if (tok.type == TokenType::LiteralFalse)
|
else if (tok.type == TokenType::LiteralFalse)
|
||||||
{
|
{
|
||||||
emit(Op::iABC(OpCode::LoadFalse, r, 0, 0));
|
emit(Op::iABC(OpCode::LoadFalse, r, 0, 0), &l->location);
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@@ -129,7 +129,7 @@ namespace Fig
|
|||||||
// 仅在被强制指定目标(如参数装填)时发射搬运指令
|
// 仅在被强制指定目标(如参数装填)时发射搬运指令
|
||||||
if (target != sym->index)
|
if (target != sym->index)
|
||||||
{
|
{
|
||||||
emit(Op::iABx(OpCode::Mov, target, static_cast<uint16_t>(sym->index)));
|
emit(Op::iABx(OpCode::Mov, target, static_cast<uint16_t>(sym->index)), &i->location);
|
||||||
}
|
}
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
@@ -137,12 +137,12 @@ namespace Fig
|
|||||||
Register r = (target == NO_REG) ? *allocateReg(i->location) : target;
|
Register r = (target == NO_REG) ? *allocateReg(i->location) : target;
|
||||||
if (sym->location == SymbolLocation::Upvalue)
|
if (sym->location == SymbolLocation::Upvalue)
|
||||||
{
|
{
|
||||||
emit(Op::iABC(OpCode::GetUpval, r, static_cast<uint8_t>(sym->index), 0));
|
emit(Op::iABC(OpCode::GetUpval, r, static_cast<uint8_t>(sym->index), 0), &i->location);
|
||||||
}
|
}
|
||||||
else if (sym->location == SymbolLocation::Global)
|
else if (sym->location == SymbolLocation::Global)
|
||||||
{
|
{
|
||||||
int gId = getGlobalID(i->name);
|
int gId = getGlobalID(i->name);
|
||||||
emit(Op::iABx(OpCode::GetGlobal, r, static_cast<uint16_t>(gId)));
|
emit(Op::iABx(OpCode::GetGlobal, r, static_cast<uint16_t>(gId)), &i->location);
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@@ -167,30 +167,43 @@ namespace Fig
|
|||||||
return std::unexpected(res.error());
|
return std::unexpected(res.error());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isGlobalFastCall = false;
|
||||||
if (c->callee->type == AstType::IdentiExpr)
|
if (c->callee->type == AstType::IdentiExpr)
|
||||||
{
|
{
|
||||||
// 静态去虚化:编译期直接跳板
|
auto *id = static_cast<IdentiExpr *>(c->callee);
|
||||||
auto *id = static_cast<IdentiExpr *>(c->callee);
|
// 只有在全局区的函数,才能使用 FastCall
|
||||||
int protoIdx = id->resolvedSymbol->index;
|
if (id->resolvedSymbol->location == SymbolLocation::Global)
|
||||||
emit(Op::iABC(OpCode::FastCall,
|
{
|
||||||
static_cast<uint8_t>(protoIdx),
|
isGlobalFastCall = true;
|
||||||
baseReg,
|
int protoIdx = id->resolvedSymbol->index;
|
||||||
static_cast<uint8_t>(c->args.args.size())));
|
emit(Op::iABC(OpCode::FastCall,
|
||||||
|
static_cast<uint8_t>(protoIdx),
|
||||||
|
baseReg,
|
||||||
|
static_cast<uint8_t>(c->args.args.size())),
|
||||||
|
&c->location);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (!isGlobalFastCall)
|
||||||
{
|
{
|
||||||
// 动态闭包调用
|
// 动态闭包调用
|
||||||
|
// 先获取闭包对象所在的物理寄存器
|
||||||
auto r_fn = compileExpr(c->callee);
|
auto r_fn = compileExpr(c->callee);
|
||||||
if (!r_fn)
|
if (!r_fn)
|
||||||
return std::unexpected(r_fn.error());
|
return std::unexpected(r_fn.error());
|
||||||
emit(Op::iABC(
|
|
||||||
OpCode::Call, *r_fn, baseReg, static_cast<uint8_t>(c->args.args.size())));
|
// 使用动态 Call 指令,RA 是指向堆闭包的寄存器
|
||||||
|
emit(Op::iABC(OpCode::Call,
|
||||||
|
*r_fn,
|
||||||
|
baseReg,
|
||||||
|
static_cast<uint8_t>(c->args.args.size())),
|
||||||
|
&c->location);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 回滚水位线:彻底释放传参时的临时占用
|
// 回滚水位线, 释放传参时的临时占用
|
||||||
current->freereg = mark;
|
current->freereg = mark;
|
||||||
|
|
||||||
// 目标对齐:若 target 未指定,allocateReg 将自然复用 baseReg,实现零开销回写
|
// 目若 target 未指定,allocateReg 将复用 baseReg,实现零开销回写
|
||||||
|
|
||||||
Register r_dest;
|
Register r_dest;
|
||||||
if (target == NO_REG)
|
if (target == NO_REG)
|
||||||
@@ -207,7 +220,7 @@ namespace Fig
|
|||||||
|
|
||||||
if (r_dest != baseReg)
|
if (r_dest != baseReg)
|
||||||
{
|
{
|
||||||
emit(Op::iABx(OpCode::Mov, r_dest, baseReg));
|
emit(Op::iABx(OpCode::Mov, r_dest, baseReg), &c->location);
|
||||||
}
|
}
|
||||||
|
|
||||||
return r_dest;
|
return r_dest;
|
||||||
@@ -227,18 +240,18 @@ namespace Fig
|
|||||||
Symbol *sym = lid->resolvedSymbol;
|
Symbol *sym = lid->resolvedSymbol;
|
||||||
if (sym->location == SymbolLocation::Local)
|
if (sym->location == SymbolLocation::Local)
|
||||||
{
|
{
|
||||||
emit(Op::iABx(OpCode::Mov, static_cast<Register>(sym->index), *r_val));
|
emit(Op::iABx(OpCode::Mov, static_cast<Register>(sym->index), *r_val), &lid->location);
|
||||||
}
|
}
|
||||||
else if (sym->location == SymbolLocation::Upvalue)
|
else if (sym->location == SymbolLocation::Upvalue)
|
||||||
{
|
{
|
||||||
emit(Op::iABC(
|
emit(Op::iABC(
|
||||||
OpCode::SetUpval, *r_val, static_cast<Register>(sym->index), 0));
|
OpCode::SetUpval, *r_val, static_cast<Register>(sym->index), 0), &lid->location);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
emit(Op::iABx(OpCode::SetGlobal,
|
emit(Op::iABx(OpCode::SetGlobal,
|
||||||
*r_val,
|
*r_val,
|
||||||
static_cast<uint16_t>(getGlobalID(lid->name))));
|
static_cast<uint16_t>(getGlobalID(lid->name))), &lid->location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return r_val;
|
return r_val;
|
||||||
@@ -300,7 +313,7 @@ namespace Fig
|
|||||||
r_d = target;
|
r_d = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit(Op::iABC(op, r_d, *r_l, *r_r));
|
emit(Op::iABC(op, r_d, *r_l, *r_r), &in->location);
|
||||||
|
|
||||||
return r_d;
|
return r_d;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
#include <Ast/Stmt/WhileStmt.hpp>
|
#include <Ast/Stmt/WhileStmt.hpp>
|
||||||
#include <Compiler/Compiler.hpp>
|
#include <Compiler/Compiler.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
Result<void, Error> Compiler::compileStmt(Stmt *stmt)
|
Result<void, Error> Compiler::compileStmt(Stmt *stmt)
|
||||||
@@ -41,8 +40,10 @@ namespace Fig
|
|||||||
if (!regRes)
|
if (!regRes)
|
||||||
return std::unexpected(regRes.error());
|
return std::unexpected(regRes.error());
|
||||||
|
|
||||||
emit(Op::iABx(
|
emit(Op::iABx(OpCode::SetGlobal,
|
||||||
OpCode::SetGlobal, *regRes, static_cast<uint16_t>(getGlobalID(v->name))));
|
*regRes,
|
||||||
|
static_cast<uint16_t>(getGlobalID(v->name))),
|
||||||
|
&v->location);
|
||||||
current->freereg = mark; // 释放初始化表达式的临时占用
|
current->freereg = mark; // 释放初始化表达式的临时占用
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -68,8 +69,21 @@ namespace Fig
|
|||||||
case AstType::FnDefStmt: {
|
case AstType::FnDefStmt: {
|
||||||
auto *f = static_cast<FnDefStmt *>(stmt);
|
auto *f = static_cast<FnDefStmt *>(stmt);
|
||||||
|
|
||||||
// 物理连线:对接 Compile() 第一阶段预分配的 Proto
|
if (f->protoIndex == -1) // 闭包环境没有被扫到
|
||||||
Proto *p = module->protos[f->resolvedSymbol->index];
|
{
|
||||||
|
Proto *newProto = new Proto();
|
||||||
|
newProto->name = f->name;
|
||||||
|
newProto->numParams = static_cast<uint8_t>(f->params.size());
|
||||||
|
newProto->maxRegisters = newProto->numParams; // 同步水位线
|
||||||
|
|
||||||
|
f->protoIndex = static_cast<int>(module->protos.size());
|
||||||
|
module->protos.push_back(newProto);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取静态原型 (flat protos)
|
||||||
|
Proto *p = module->protos[f->protoIndex];
|
||||||
|
|
||||||
|
p->upvalues = f->upvalues;
|
||||||
|
|
||||||
FuncState fs(p, current);
|
FuncState fs(p, current);
|
||||||
FuncState *old = current;
|
FuncState *old = current;
|
||||||
@@ -79,13 +93,47 @@ namespace Fig
|
|||||||
if (!res)
|
if (!res)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
// 窥孔拦截:防死代码污染
|
|
||||||
if (p->code.empty() || static_cast<OpCode>(p->code.back() & 0xFF) != OpCode::Return)
|
if (p->code.empty() || static_cast<OpCode>(p->code.back() & 0xFF) != OpCode::Return)
|
||||||
{
|
{
|
||||||
emit(Op::iABC(OpCode::Return, 0, 0, 0));
|
emit(Op::iABC(OpCode::Return, 0, 0, 0), &f->location);
|
||||||
}
|
}
|
||||||
|
|
||||||
current = old;
|
current = old;
|
||||||
|
|
||||||
|
// 如果是局部闭包,在当前栈帧分配寄存器并生成 LoadFn
|
||||||
|
if (f->resolvedSymbol->location == SymbolLocation::Local)
|
||||||
|
{
|
||||||
|
Register targetReg = static_cast<Register>(f->resolvedSymbol->index);
|
||||||
|
|
||||||
|
while (current->freereg <= targetReg)
|
||||||
|
{
|
||||||
|
auto allocRes = allocateReg(f->location);
|
||||||
|
if (!allocRes)
|
||||||
|
return std::unexpected(allocRes.error());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成 LoadFn: RA = 目标寄存器, Bx = Proto 在 module->protos 中的绝对索引
|
||||||
|
emit(Op::iABx(OpCode::LoadFn, targetReg, static_cast<uint16_t>(f->protoIndex)),
|
||||||
|
&f->location);
|
||||||
|
}
|
||||||
|
else if (f->resolvedSymbol->location == SymbolLocation::Global)
|
||||||
|
{
|
||||||
|
auto result = allocateReg(f->location);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return std::unexpected(result.error());
|
||||||
|
}
|
||||||
|
|
||||||
|
Register r = *result;
|
||||||
|
emit(Op::iABx(OpCode::LoadFn, r, static_cast<uint16_t>(f->protoIndex)),
|
||||||
|
&f->location);
|
||||||
|
|
||||||
|
int gId = getGlobalID(f->name);
|
||||||
|
emit(Op::iABx(OpCode::SetGlobal, r, static_cast<std::uint16_t>(gId)),
|
||||||
|
&f->location);
|
||||||
|
|
||||||
|
freeReg();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,13 +147,13 @@ namespace Fig
|
|||||||
return std::unexpected(r_cond.error());
|
return std::unexpected(r_cond.error());
|
||||||
|
|
||||||
int jmpToNext = static_cast<int>(current->proto->code.size());
|
int jmpToNext = static_cast<int>(current->proto->code.size());
|
||||||
emit(Op::iAsBx(OpCode::JmpIfFalse, *r_cond, 0));
|
emit(Op::iAsBx(OpCode::JmpIfFalse, *r_cond, 0), &i->location);
|
||||||
current->freereg = mark; // 回收条件表达式临时槽位
|
current->freereg = mark; // 回收条件表达式临时槽位
|
||||||
|
|
||||||
if (auto r = compileStmt(i->consequent); !r)
|
if (auto r = compileStmt(i->consequent); !r)
|
||||||
return r;
|
return r;
|
||||||
exitJumps.push_back(static_cast<int>(current->proto->code.size()));
|
exitJumps.push_back(static_cast<int>(current->proto->code.size()));
|
||||||
emit(Op::iAsBx(OpCode::Jmp, 0, 0));
|
emit(Op::iAsBx(OpCode::Jmp, 0, 0), &i->location);
|
||||||
|
|
||||||
int targetIdx = static_cast<int>(current->proto->code.size());
|
int targetIdx = static_cast<int>(current->proto->code.size());
|
||||||
current->proto->code[jmpToNext] = Op::iAsBx(
|
current->proto->code[jmpToNext] = Op::iAsBx(
|
||||||
@@ -119,17 +167,22 @@ namespace Fig
|
|||||||
return std::unexpected(ec.error());
|
return std::unexpected(ec.error());
|
||||||
|
|
||||||
int nextElif = static_cast<int>(current->proto->code.size());
|
int nextElif = static_cast<int>(current->proto->code.size());
|
||||||
emit(Op::iAsBx(OpCode::JmpIfFalse, *ec, 0));
|
emit(Op::iAsBx(OpCode::JmpIfFalse, *ec, 0), &elif->location);
|
||||||
current->freereg = elifMark; // 回收 elif 临时槽位
|
current->freereg = elifMark; // 回收 elif 临时槽位
|
||||||
|
|
||||||
if (auto r = compileStmt(elif->consequent); !r)
|
if (auto r = compileStmt(elif->consequent); !r)
|
||||||
return r;
|
return r;
|
||||||
exitJumps.push_back(static_cast<int>(current->proto->code.size()));
|
exitJumps.push_back(static_cast<int>(current->proto->code.size()));
|
||||||
emit(Op::iAsBx(OpCode::Jmp, 0, 0));
|
emit(Op::iAsBx(OpCode::Jmp, 0, 0), &elif->location);
|
||||||
|
|
||||||
int target = static_cast<int>(current->proto->code.size());
|
int target = static_cast<int>(current->proto->code.size());
|
||||||
|
|
||||||
|
current->proto->code.resize(nextElif);
|
||||||
current->proto->code[nextElif] = Op::iAsBx(
|
current->proto->code[nextElif] = Op::iAsBx(
|
||||||
OpCode::JmpIfFalse, *ec, static_cast<int16_t>(target - nextElif - 1));
|
OpCode::JmpIfFalse, *ec, static_cast<int16_t>(target - nextElif - 1));
|
||||||
|
|
||||||
|
current->proto->locations.resize(nextElif);
|
||||||
|
current->proto->locations[nextElif] = &elif->location;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i->alternate)
|
if (i->alternate)
|
||||||
@@ -157,14 +210,15 @@ namespace Fig
|
|||||||
return std::unexpected(r_cond.error());
|
return std::unexpected(r_cond.error());
|
||||||
|
|
||||||
int exitJmpIdx = static_cast<int>(current->proto->code.size());
|
int exitJmpIdx = static_cast<int>(current->proto->code.size());
|
||||||
emit(Op::iAsBx(OpCode::JmpIfFalse, *r_cond, 0));
|
emit(Op::iAsBx(OpCode::JmpIfFalse, *r_cond, 0), &w->location);
|
||||||
current->freereg = mark; // 回收循环条件临时槽位
|
current->freereg = mark; // 回收循环条件临时槽位
|
||||||
|
|
||||||
if (auto r = compileStmt(w->body); !r)
|
if (auto r = compileStmt(w->body); !r)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
int backJmpIdx = static_cast<int>(current->proto->code.size());
|
int backJmpIdx = static_cast<int>(current->proto->code.size());
|
||||||
emit(Op::iAsBx(OpCode::Jmp, 0, static_cast<int16_t>(startIdx - backJmpIdx - 1)));
|
emit(Op::iAsBx(OpCode::Jmp, 0, static_cast<int16_t>(startIdx - backJmpIdx - 1)),
|
||||||
|
&w->location);
|
||||||
|
|
||||||
int endIdx = static_cast<int>(current->proto->code.size());
|
int endIdx = static_cast<int>(current->proto->code.size());
|
||||||
current->proto->code[exitJmpIdx] = Op::iAsBx(
|
current->proto->code[exitJmpIdx] = Op::iAsBx(
|
||||||
@@ -189,11 +243,11 @@ namespace Fig
|
|||||||
auto r = allocateReg(rs->location);
|
auto r = allocateReg(rs->location);
|
||||||
if (!r)
|
if (!r)
|
||||||
return std::unexpected(r.error());
|
return std::unexpected(r.error());
|
||||||
emit(Op::iABC(OpCode::LoadNull, *r, 0, 0));
|
emit(Op::iABC(OpCode::LoadNull, *r, 0, 0), &rs->location);
|
||||||
retReg = *r;
|
retReg = *r;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit(Op::iABC(OpCode::Return, retReg, 0, 0));
|
emit(Op::iABC(OpCode::Return, retReg, 0, 0), &rs->location);
|
||||||
current->freereg = mark; // 回收返回值计算的占用
|
current->freereg = mark; // 回收返回值计算的占用
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,40 @@
|
|||||||
/*!
|
/*!
|
||||||
@file src/Object/FunctionObject.hpp
|
@file src/Object/FunctionObject.hpp
|
||||||
@brief 函数对象定义
|
@brief 函数对象定义
|
||||||
@author PuqiAR (im@puqiar.top)
|
|
||||||
@date 2026-02-28
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Object/ObjectBase.hpp>
|
#include <Object/ObjectBase.hpp>
|
||||||
|
#include <Bytecode/Bytecode.hpp>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
// 运行时闭包对象 (24字节 Base + 8字节 Proto指针 = 32 bytes)
|
// Upvalue (Stack Open / Heap Closed)
|
||||||
|
struct Upvalue
|
||||||
|
{
|
||||||
|
Value *location; // Open 状态指向 VM 的 registerBase[x],Closed 状态指向下面的 closedValue
|
||||||
|
Value closedValue; // 栈帧销毁时,数据物理迁移至此
|
||||||
|
Upvalue *next; // 侵入式链表,供 VM 追踪当前 Open 的 Upvalue
|
||||||
|
std::uint32_t refCount = 0; // 多少个闭包正在使用
|
||||||
|
};
|
||||||
|
|
||||||
struct Proto;
|
|
||||||
struct FunctionObject final : public Object
|
struct FunctionObject final : public Object
|
||||||
{
|
{
|
||||||
String name; // 调试使用
|
String name;
|
||||||
Proto *proto; // 指向编译器生成的只读字节码与常量池
|
Proto *proto; // 静态只读字节码
|
||||||
std::uint8_t paraCount;
|
std::uint8_t paraCount;
|
||||||
|
std::uint32_t upvalueCount; // 捕获数量
|
||||||
|
|
||||||
// TODO: 实现闭包时 加一个 Upvalue 指针数组
|
// 柔性数组
|
||||||
// Value* upvalues;
|
Upvalue *upvalues[];
|
||||||
|
|
||||||
|
FunctionObject(const String &_name, Proto *_proto, std::uint32_t _upvalueCount) :
|
||||||
|
name(_name), proto(_proto), paraCount(_proto->numParams), upvalueCount(_upvalueCount)
|
||||||
|
{
|
||||||
|
type = ObjectType::Function;
|
||||||
|
}
|
||||||
|
|
||||||
|
~FunctionObject() = default;
|
||||||
};
|
};
|
||||||
} // namespace Fig
|
} // namespace Fig
|
||||||
16
src/Object/InstanceObject.hpp
Normal file
16
src/Object/InstanceObject.hpp
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/*!
|
||||||
|
@file src/Object/InstanceObject.hpp
|
||||||
|
@brief 实例(InstanceObject)定义
|
||||||
|
@author PuqiAR (im@puqiar.top)
|
||||||
|
@date 2026-03-10
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Object/ObjectBase.hpp>
|
||||||
|
|
||||||
|
namespace Fig
|
||||||
|
{
|
||||||
|
struct InstanceObject final : public Object
|
||||||
|
{
|
||||||
|
Value fields[];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
@date 2026-02-19
|
@date 2026-02-19
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Object/ObjectBase.hpp>
|
#include <Object/Object.hpp>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
@@ -29,7 +29,35 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
else if (IsObject())
|
else if (IsObject())
|
||||||
{
|
{
|
||||||
return "Object"; // TODO: 分派
|
Object *obj = AsObject();
|
||||||
|
if (!obj)
|
||||||
|
return "<Bad Object>";
|
||||||
|
|
||||||
|
// 物理分发, 扔掉虚函数!awa
|
||||||
|
switch (obj->type)
|
||||||
|
{
|
||||||
|
case ObjectType::String: {
|
||||||
|
auto *strObj = static_cast<StringObject *>(obj);
|
||||||
|
return strObj->data;
|
||||||
|
}
|
||||||
|
case ObjectType::Function: {
|
||||||
|
auto *fnObj = static_cast<FunctionObject *>(obj);
|
||||||
|
return std::format("<Function: {}>", fnObj->name);
|
||||||
|
}
|
||||||
|
case ObjectType::Struct: {
|
||||||
|
auto *structObj = static_cast<StructObject *>(obj);
|
||||||
|
return std::format("<Struct: {}>", structObj->name);
|
||||||
|
}
|
||||||
|
case ObjectType::Instance: {
|
||||||
|
// 利用你预留的神级指针 klass 溯源
|
||||||
|
if (obj->klass)
|
||||||
|
{
|
||||||
|
return std::format("<Instance: {}>", obj->klass->name);
|
||||||
|
}
|
||||||
|
return "<Instance: Unknown>";
|
||||||
|
}
|
||||||
|
default: return "<Corrupted Object>";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <Object/FunctionObject.hpp>
|
||||||
|
#include <Object/InstanceObject.hpp>
|
||||||
#include <Object/ObjectBase.hpp>
|
#include <Object/ObjectBase.hpp>
|
||||||
#include <Object/StringObject.hpp>
|
#include <Object/StringObject.hpp>
|
||||||
#include <Object/StructObject.hpp>
|
#include <Object/StructObject.hpp>
|
||||||
#include <Object/FunctionObject.hpp>
|
|
||||||
@@ -125,7 +125,7 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
return (v_ & (SIGN_BIT | QNAN_MASK)) == (SIGN_BIT | QNAN_MASK);
|
return (v_ & (SIGN_BIT | QNAN_MASK)) == (SIGN_BIT | QNAN_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提取数据 (Unbox / As)
|
// 提取数据 (Unbox / As)
|
||||||
[[nodiscard]] constexpr double AsDouble() const
|
[[nodiscard]] constexpr double AsDouble() const
|
||||||
{
|
{
|
||||||
@@ -165,7 +165,8 @@ namespace Fig
|
|||||||
// 让 VM 的 OP_EQ 指令极简:`if (RA == RB)`
|
// 让 VM 的 OP_EQ 指令极简:`if (RA == RB)`
|
||||||
[[nodiscard]] constexpr bool operator==(const Value &other) const
|
[[nodiscard]] constexpr bool operator==(const Value &other) const
|
||||||
{
|
{
|
||||||
// IEEE 754 规定浮点数有 +0.0 == -0.0 的特殊规则,所以不直接比对raw bits而是转换成 double进行C++比对
|
// IEEE 754 规定浮点数有 +0.0 == -0.0 的特殊规则,所以不直接比对raw bits而是转换成
|
||||||
|
// double进行C++比对
|
||||||
if (IsDouble() && other.IsDouble())
|
if (IsDouble() && other.IsDouble())
|
||||||
{
|
{
|
||||||
return AsDouble() == other.AsDouble();
|
return AsDouble() == other.AsDouble();
|
||||||
@@ -199,13 +200,20 @@ namespace Fig
|
|||||||
|
|
||||||
struct StructObject /* : public Object */; // 结构体基类的定义,前向声明
|
struct StructObject /* : public Object */; // 结构体基类的定义,前向声明
|
||||||
|
|
||||||
|
enum class GCColor : std::uint8_t
|
||||||
|
{
|
||||||
|
White = 0, // 垃圾(或新对象)!
|
||||||
|
Gray = 1, // 已发现,子节点待扫描
|
||||||
|
Black = 2, // 存活
|
||||||
|
};
|
||||||
|
|
||||||
// Total 24 bytes size
|
// Total 24 bytes size
|
||||||
struct Object
|
struct Object
|
||||||
{
|
{
|
||||||
Object *next; // 8 bytes: gc链表
|
Object *next; // 8 bytes: gc链表
|
||||||
StructObject *klass; // 8 bytes: 一切皆对象,父类指针
|
StructObject *klass; // 8 bytes: 一切皆对象,父类指针
|
||||||
ObjectType type; // 1 byte : 类型
|
ObjectType type; // 1 byte : 类型
|
||||||
bool isMarked = false; // 1 byte : gc标记
|
GCColor color = GCColor::White; // 1 byte : gc标记
|
||||||
// + 6 bytes padding
|
// + 6 bytes padding
|
||||||
|
|
||||||
constexpr bool isString() const
|
constexpr bool isString() const
|
||||||
@@ -227,12 +235,6 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
return type == ObjectType::Instance;
|
return type == ObjectType::Instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 调试输出
|
|
||||||
virtual String toString() const
|
|
||||||
{
|
|
||||||
return "Object";
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
} // namespace Fig
|
} // namespace Fig
|
||||||
|
|
||||||
|
|||||||
@@ -25,10 +25,5 @@ namespace Fig
|
|||||||
struct StringObject final : public Object
|
struct StringObject final : public Object
|
||||||
{
|
{
|
||||||
String data; // 40 bytes
|
String data; // 40 bytes
|
||||||
|
|
||||||
virtual String toString() const override
|
|
||||||
{
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -39,9 +39,6 @@ namespace Fig
|
|||||||
0 - UnaryOperators::Count BinaryOperators::Count
|
0 - UnaryOperators::Count BinaryOperators::Count
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Value fields[];
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Object *GetUnaryOperator(UnaryOperator _op)
|
Object *GetUnaryOperator(UnaryOperator _op)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -206,8 +206,39 @@ namespace Fig
|
|||||||
v->localId = idx;
|
v->localId = idx;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case AstType::FnDefStmt: {
|
case AstType::FnDefStmt: {
|
||||||
auto *f = static_cast<FnDefStmt *>(stmt);
|
auto *f = static_cast<FnDefStmt *>(stmt);
|
||||||
|
|
||||||
|
// 3.10: 局部闭包延迟类型推导
|
||||||
|
|
||||||
|
if (!f->resolvedSymbol) // 闭包?
|
||||||
|
{
|
||||||
|
SymbolLocation loc =
|
||||||
|
env.current->parent ? SymbolLocation::Local : SymbolLocation::Global;
|
||||||
|
int idx = (loc == SymbolLocation::Local) ? env.current->nextLocalId++ : 0;
|
||||||
|
|
||||||
|
Symbol *sym = arena.Allocate<Symbol>(f->name, Type{}, loc, idx, true);
|
||||||
|
f->resolvedSymbol = sym;
|
||||||
|
env.current->locals[f->name] = sym;
|
||||||
|
|
||||||
|
auto res = resolveTypeExpr(f->returnTypeSpecifier);
|
||||||
|
if (!res)
|
||||||
|
return std::unexpected(res.error());
|
||||||
|
f->resolvedReturnType = *res;
|
||||||
|
|
||||||
|
DynArray<Type> paramTypes;
|
||||||
|
for (auto *p : f->params)
|
||||||
|
{
|
||||||
|
auto pres = resolveTypeExpr(p->typeSpecifier);
|
||||||
|
if (!pres)
|
||||||
|
return std::unexpected(pres.error());
|
||||||
|
p->resolvedType = *pres;
|
||||||
|
paramTypes.push_back(*pres);
|
||||||
|
}
|
||||||
|
f->resolvedSymbol->type = typeCtx.CreateFuncType(std::move(paramTypes), *res);
|
||||||
|
}
|
||||||
|
|
||||||
FnStateGuard fnGuard(state.currentFn, f);
|
FnStateGuard fnGuard(state.currentFn, f);
|
||||||
ScopeGuard scopeGuard(env, true);
|
ScopeGuard scopeGuard(env, true);
|
||||||
for (auto *p : f->params)
|
for (auto *p : f->params)
|
||||||
@@ -220,8 +251,15 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
if (auto r = analyzeStmt(f->body); !r)
|
if (auto r = analyzeStmt(f->body); !r)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
for (const auto &upval : env.current->upvalues)
|
||||||
|
{
|
||||||
|
f->upvalues.push_back({static_cast<std::uint8_t>(upval.index), upval.isLocal});
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case AstType::IfStmt: {
|
case AstType::IfStmt: {
|
||||||
auto *i = static_cast<IfStmt *>(stmt);
|
auto *i = static_cast<IfStmt *>(stmt);
|
||||||
|
|
||||||
@@ -394,7 +432,7 @@ namespace Fig
|
|||||||
auto r = analyzeExpr(arg.value);
|
auto r = analyzeExpr(arg.value);
|
||||||
if (!r)
|
if (!r)
|
||||||
return std::unexpected(r.error());
|
return std::unexpected(r.error());
|
||||||
// 顺手做字段赋值类型检查
|
// 字段赋值类型检查
|
||||||
if (!arg.name.empty()
|
if (!arg.name.empty()
|
||||||
&& !r->isAssignableTo(st->fields[st->fieldMap[arg.name]].type))
|
&& !r->isAssignableTo(st->fields[st->fieldMap[arg.name]].type))
|
||||||
{
|
{
|
||||||
@@ -436,7 +474,7 @@ namespace Fig
|
|||||||
if (l.is(TypeTag::Any) || r.is(TypeTag::Any))
|
if (l.is(TypeTag::Any) || r.is(TypeTag::Any))
|
||||||
return expr->resolvedType = typeCtx.GetBasic(TypeTag::Any);
|
return expr->resolvedType = typeCtx.GetBasic(TypeTag::Any);
|
||||||
|
|
||||||
// 🔥 算术操作强检查
|
// 算术操作强检查
|
||||||
if (in->op == BinaryOperator::Add && l.is(TypeTag::String) && r.is(TypeTag::String))
|
if (in->op == BinaryOperator::Add && l.is(TypeTag::String) && r.is(TypeTag::String))
|
||||||
return expr->resolvedType = typeCtx.GetBasic(TypeTag::String);
|
return expr->resolvedType = typeCtx.GetBasic(TypeTag::String);
|
||||||
if (l.is(TypeTag::Int) && r.is(TypeTag::Int))
|
if (l.is(TypeTag::Int) && r.is(TypeTag::Int))
|
||||||
@@ -467,7 +505,7 @@ namespace Fig
|
|||||||
if (calleeType.is(TypeTag::Any))
|
if (calleeType.is(TypeTag::Any))
|
||||||
return expr->resolvedType = typeCtx.GetBasic(TypeTag::Any);
|
return expr->resolvedType = typeCtx.GetBasic(TypeTag::Any);
|
||||||
|
|
||||||
// 🔥 终极函数签名校验
|
// 函数签名校验
|
||||||
if (!calleeType.is(TypeTag::Function))
|
if (!calleeType.is(TypeTag::Function))
|
||||||
return std::unexpected(
|
return std::unexpected(
|
||||||
Error(ErrorType::TypeError, "callee is not a function", "", c->location));
|
Error(ErrorType::TypeError, "callee is not a function", "", c->location));
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ namespace Fig
|
|||||||
return true; // Any 逃逸通道
|
return true; // Any 逃逸通道
|
||||||
if (this->is(TypeTag::Null) && target.isNullable)
|
if (this->is(TypeTag::Null) && target.isNullable)
|
||||||
return true; // Null 安全赋值
|
return true; // Null 安全赋值
|
||||||
return this->base == target.base && (!this->isNullable || target.isNullable); // 严格匹配
|
return this->base == target.base && (!this->isNullable || target.isNullable);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeContext::TypeContext()
|
TypeContext::TypeContext()
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ namespace Fig
|
|||||||
};
|
};
|
||||||
DynArray<Field> fields;
|
DynArray<Field> fields;
|
||||||
HashMap<String, size_t> fieldMap;
|
HashMap<String, size_t> fieldMap;
|
||||||
HashMap<String, class FnDefStmt *> methods;
|
HashMap<String, struct FnDefStmt *> methods;
|
||||||
|
|
||||||
StructType(String n) : BaseType(TypeTag::Struct, std::move(n)) {}
|
StructType(String n) : BaseType(TypeTag::Struct, std::move(n)) {}
|
||||||
void AddField(String name, Type type, bool isPublic)
|
void AddField(String name, Type type, bool isPublic)
|
||||||
|
|||||||
110
src/VM/VM.cpp
110
src/VM/VM.cpp
@@ -150,7 +150,8 @@ namespace Fig
|
|||||||
CoreIO::GetStdErr() << std::format(
|
CoreIO::GetStdErr() << std::format(
|
||||||
"Oops! max recursion depth limit {} exceeded in Fn `{}` , exiting...\n",
|
"Oops! max recursion depth limit {} exceeded in Fn `{}` , exiting...\n",
|
||||||
MAX_RECURSION_DEPTH,
|
MAX_RECURSION_DEPTH,
|
||||||
(currentFrame - 1)->proto->name); // pushFrame失败了,但currentFrame仍然移动,所以 (currentFrame - 1)是 lastFrame
|
(currentFrame - 1)->proto->name); // pushFrame失败了,但currentFrame仍然移动,所以
|
||||||
|
// (currentFrame - 1)是 lastFrame
|
||||||
std::exit(static_cast<int>(MAX_RECURSION_DEPTH));
|
std::exit(static_cast<int>(MAX_RECURSION_DEPTH));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,6 +192,40 @@ namespace Fig
|
|||||||
|
|
||||||
do_Call: {
|
do_Call: {
|
||||||
// TODO: FunctionObject 动态解包
|
// 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
|
||||||
|
{
|
||||||
|
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();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,8 +233,9 @@ namespace Fig
|
|||||||
std::uint8_t a = decodeA(inst);
|
std::uint8_t a = decodeA(inst);
|
||||||
Value retVal = currentFrame->registerBase[a];
|
Value retVal = currentFrame->registerBase[a];
|
||||||
|
|
||||||
// 此时 registerBase[0] 指向的是 Caller 的 baseReg 槽位
|
closeUpvalues(currentFrame->registerBase);
|
||||||
|
|
||||||
|
// 此时 registerBase[0] 指向的是 Caller 的 baseReg 槽位
|
||||||
currentFrame->registerBase[0] = retVal;
|
currentFrame->registerBase[0] = retVal;
|
||||||
popFrame();
|
popFrame();
|
||||||
|
|
||||||
@@ -207,6 +243,67 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
|
|
||||||
do_LoadFn: {
|
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();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,12 +412,17 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
|
|
||||||
do_GetUpval: {
|
do_GetUpval: {
|
||||||
assert(false && "VM: GetUpval requires FunctionObject (Closure) implementation");
|
std::uint8_t a = decodeA(inst);
|
||||||
|
std::uint8_t b = decodeB(inst);
|
||||||
|
|
||||||
|
currentFrame->registerBase[a] = *(currentFrame->closure->upvalues[b]->location);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
do_SetUpval: {
|
do_SetUpval: {
|
||||||
assert(false && "VM: SetUpval requires FunctionObject (Closure) implementation");
|
std::uint8_t a = decodeA(inst);
|
||||||
|
std::uint8_t b = decodeB(inst);
|
||||||
|
*(currentFrame->closure->upvalues[b]->location) = currentFrame->registerBase[a]; // copy
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
300
src/VM/VM.hpp
300
src/VM/VM.hpp
@@ -9,8 +9,9 @@
|
|||||||
|
|
||||||
#include <Compiler/Compiler.hpp>
|
#include <Compiler/Compiler.hpp>
|
||||||
#include <Object/Object.hpp>
|
#include <Object/Object.hpp>
|
||||||
#include <cassert>
|
#include <Core/Core.hpp>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <iostream> // debug
|
#include <iostream> // debug
|
||||||
#include <print>
|
#include <print>
|
||||||
|
|
||||||
@@ -18,9 +19,10 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
struct CallFrame
|
struct CallFrame
|
||||||
{
|
{
|
||||||
Proto *proto; // 当前执行的原型
|
FunctionObject *closure; // 动态闭包Context (FastCall时 null)
|
||||||
Instruction *ip; // 当前指令指针
|
Proto *proto; // 当前执行的原型
|
||||||
Value *registerBase; // 寄存器起点
|
Instruction *ip; // 当前指令指针
|
||||||
|
Value *registerBase; // 寄存器起点
|
||||||
|
|
||||||
inline Value getConstant(std::uint16_t idx)
|
inline Value getConstant(std::uint16_t idx)
|
||||||
{
|
{
|
||||||
@@ -28,6 +30,14 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class GCPhase : std::uint8_t
|
||||||
|
{
|
||||||
|
Idle,
|
||||||
|
MarkRoots,
|
||||||
|
Marking,
|
||||||
|
Sweeping
|
||||||
|
};
|
||||||
|
|
||||||
class VM
|
class VM
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@@ -45,6 +55,251 @@ namespace Fig
|
|||||||
CallFrame *currentFrame;
|
CallFrame *currentFrame;
|
||||||
CallFrame *frameLimit;
|
CallFrame *frameLimit;
|
||||||
|
|
||||||
|
Upvalue *openUpvalues = nullptr;
|
||||||
|
|
||||||
|
// GC
|
||||||
|
Object *objects = nullptr; // 链表头
|
||||||
|
DynArray<Object *> grayStack;
|
||||||
|
|
||||||
|
size_t allocatedBytes = 0;
|
||||||
|
size_t nextGC = 1024 * 1024; // byte, 1MB初始阈值
|
||||||
|
GCPhase gcPhase = GCPhase::Idle;
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline void closeUpvalues(Value *level)
|
||||||
|
{
|
||||||
|
// 函数销毁时,逃逸即将销毁的变量
|
||||||
|
while (openUpvalues && openUpvalues->location >= level)
|
||||||
|
{
|
||||||
|
Upvalue *upval = openUpvalues;
|
||||||
|
upval->closedValue = *upval->location;
|
||||||
|
upval->location = &upval->closedValue;
|
||||||
|
openUpvalues = upval->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
[[nodiscard]] T *allocateObject(ObjectType type, size_t extraBytes)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (allocatedBytes > nextGC) // 超出阈值
|
||||||
|
{
|
||||||
|
switch (gcPhase)
|
||||||
|
{
|
||||||
|
case GCPhase::Idle: markRoots(); break;
|
||||||
|
case GCPhase::Marking: stepMarking(); break;
|
||||||
|
case GCPhase::Sweeping: sweep(); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t totalSize = sizeof(T) + extraBytes;
|
||||||
|
|
||||||
|
// 物理分配
|
||||||
|
T *obj = static_cast<T *>(std::malloc(totalSize));
|
||||||
|
if (!obj) [[unlikely]]
|
||||||
|
{
|
||||||
|
// 分配失败
|
||||||
|
CoreIO::GetStdErr() << "Oops! Object allocating failed! Exiting...\n";
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构造 Header
|
||||||
|
obj->type = type;
|
||||||
|
obj->color = GCColor::Black;
|
||||||
|
obj->klass = nullptr;
|
||||||
|
obj->next = objects; // 插入全局追踪链表
|
||||||
|
objects = obj;
|
||||||
|
|
||||||
|
allocatedBytes += totalSize;
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void writeBarrier(Object *parent, Value childVal)
|
||||||
|
{
|
||||||
|
if (!childVal.IsObject())
|
||||||
|
return; // 栈对象无需
|
||||||
|
|
||||||
|
Object *child = childVal.AsObject();
|
||||||
|
// 三色不变式, 黑色对象绝对不能指向白色对象
|
||||||
|
if (parent->color == GCColor::Black && child->color == GCColor::White)
|
||||||
|
{
|
||||||
|
child->color = GCColor::Gray;
|
||||||
|
grayStack.push_back(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void markValue(Value value)
|
||||||
|
{
|
||||||
|
if (!value.IsObject())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Object *obj = value.AsObject();
|
||||||
|
if (obj && obj->color == GCColor::White)
|
||||||
|
{
|
||||||
|
obj->color = GCColor::Gray;
|
||||||
|
grayStack.push_back(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void markRoots()
|
||||||
|
{
|
||||||
|
// 扫描全局变量
|
||||||
|
for (std::uint32_t i = 0; i < MAX_GLOBALS; ++i)
|
||||||
|
{
|
||||||
|
markValue(globals[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 扫描vm全部栈 [registers[0], currentFrame]
|
||||||
|
if (currentFrame && currentFrame->proto)
|
||||||
|
{
|
||||||
|
Value *stackTop = currentFrame->registerBase + currentFrame->proto->maxRegisters;
|
||||||
|
for (Value *slot = registers; slot < stackTop; ++slot)
|
||||||
|
{
|
||||||
|
markValue(*slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 扫描逃逸链表 (Open Upvalues)
|
||||||
|
for (Upvalue *uv = openUpvalues; uv != nullptr; uv = uv->next)
|
||||||
|
{
|
||||||
|
markValue(uv->closedValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
gcPhase = GCPhase::Marking;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stepMarking()
|
||||||
|
{
|
||||||
|
// 每次步进处理的对象数量
|
||||||
|
constexpr int WORK_LIMIT = 64;
|
||||||
|
int workCount = 0;
|
||||||
|
|
||||||
|
while (!grayStack.empty() && workCount++ < WORK_LIMIT)
|
||||||
|
{
|
||||||
|
Object *obj = grayStack.back();
|
||||||
|
grayStack.pop_back();
|
||||||
|
|
||||||
|
// 标记为黑色:表示该对象及其子引用已处理完毕
|
||||||
|
obj->color = GCColor::Black;
|
||||||
|
|
||||||
|
switch (obj->type)
|
||||||
|
{
|
||||||
|
case ObjectType::Function: {
|
||||||
|
auto *fn = static_cast<FunctionObject *>(obj);
|
||||||
|
for (std::uint32_t i = 0; i < fn->upvalueCount; ++i)
|
||||||
|
{
|
||||||
|
if (fn->upvalues[i])
|
||||||
|
markValue(*(fn->upvalues[i]->location));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ObjectType::Instance: {
|
||||||
|
auto *inst = static_cast<InstanceObject *>(obj);
|
||||||
|
if (inst->klass)
|
||||||
|
markValue(Value::FromObject(inst->klass));
|
||||||
|
// 扫描所有实例字段
|
||||||
|
std::uint8_t fieldCount = inst->klass ? inst->klass->fieldCount : 0;
|
||||||
|
for (std::uint8_t i = 0; i < fieldCount; ++i)
|
||||||
|
{
|
||||||
|
markValue(inst->fields[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ObjectType::Struct: {
|
||||||
|
auto *st = static_cast<StructObject *>(obj);
|
||||||
|
for (int i = 0; i < GetOperatorsSize(); ++i)
|
||||||
|
{
|
||||||
|
if (st->operators[i])
|
||||||
|
markValue(Value::FromObject(st->operators[i]));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ObjectType::String: break; // 叶子节点
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (grayStack.empty())
|
||||||
|
gcPhase = GCPhase::Sweeping;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sweep()
|
||||||
|
{
|
||||||
|
Object **curr = &objects;
|
||||||
|
size_t liveBytes = 0;
|
||||||
|
|
||||||
|
while (*curr != nullptr)
|
||||||
|
{
|
||||||
|
Object *obj = *curr;
|
||||||
|
if (obj->color == GCColor::White)
|
||||||
|
{
|
||||||
|
*curr = obj->next;
|
||||||
|
|
||||||
|
// 函数 upvalue需要手动析构
|
||||||
|
if (obj->type == ObjectType::Function)
|
||||||
|
{
|
||||||
|
auto *fn = static_cast<FunctionObject *>(obj);
|
||||||
|
fn->name.~String();
|
||||||
|
for (std::uint32_t i = 0; i < fn->upvalueCount; ++i)
|
||||||
|
{
|
||||||
|
Upvalue *uv = fn->upvalues[i];
|
||||||
|
if (uv)
|
||||||
|
{
|
||||||
|
uv->refCount--; // 减引用
|
||||||
|
if (uv->refCount == 0)
|
||||||
|
{
|
||||||
|
// 只有当所有闭包都死后,才 free 这个 Upvalue 结构体
|
||||||
|
|
||||||
|
std::free(uv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 持有 C++ 堆资源的成员手动析构!
|
||||||
|
else if (obj->type == ObjectType::String)
|
||||||
|
{
|
||||||
|
static_cast<StringObject *>(obj)->data.~String();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::free(obj);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 洗白,仍是一条好汉
|
||||||
|
// 以备下次 GC,统计存活大小
|
||||||
|
obj->color = GCColor::White;
|
||||||
|
|
||||||
|
// 计算存活对象的真实物理大小 (Header + 柔性数组/额外数据)
|
||||||
|
size_t objectSize = 0;
|
||||||
|
switch (obj->type)
|
||||||
|
{
|
||||||
|
case ObjectType::String: objectSize = sizeof(StringObject); break;
|
||||||
|
case ObjectType::Instance:
|
||||||
|
objectSize =
|
||||||
|
sizeof(InstanceObject)
|
||||||
|
+ (obj->klass ? obj->klass->fieldCount * sizeof(Value) : 0);
|
||||||
|
break;
|
||||||
|
case ObjectType::Function:
|
||||||
|
objectSize = sizeof(FunctionObject)
|
||||||
|
+ (static_cast<FunctionObject *>(obj)->upvalueCount
|
||||||
|
* sizeof(Upvalue *));
|
||||||
|
break;
|
||||||
|
case ObjectType::Struct: objectSize = sizeof(StructObject); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
liveBytes += objectSize;
|
||||||
|
|
||||||
|
curr = &obj->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allocatedBytes = liveBytes;
|
||||||
|
// 阈值调整, 当下一次分配超过存活内存的 2 倍时触发 GC
|
||||||
|
nextGC = (liveBytes < 512 * 1024) ? 1024 * 1024 : liveBytes * 2;
|
||||||
|
|
||||||
|
gcPhase = GCPhase::Idle;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VM()
|
VM()
|
||||||
{
|
{
|
||||||
@@ -66,7 +321,7 @@ namespace Fig
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
inline Instruction *pushFrame(Proto *proto, Value *base)
|
inline Instruction *pushFrame(Proto *proto, Value *base) // fastcall
|
||||||
{
|
{
|
||||||
if (++currentFrame >= frameLimit) [[unlikely]] // 达到最大递归层数
|
if (++currentFrame >= frameLimit) [[unlikely]] // 达到最大递归层数
|
||||||
{
|
{
|
||||||
@@ -75,7 +330,21 @@ namespace Fig
|
|||||||
return &POISON_MAX_RECURSION_DEPTH_EXCEED_INST;
|
return &POISON_MAX_RECURSION_DEPTH_EXCEED_INST;
|
||||||
}
|
}
|
||||||
|
|
||||||
*currentFrame = CallFrame{proto, proto->code.data(), base};
|
*currentFrame = CallFrame{nullptr, proto, proto->code.data(), base};
|
||||||
|
return currentFrame->ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
inline Instruction *pushFrame(FunctionObject *closure, Value *base) // 普通调用
|
||||||
|
{
|
||||||
|
if (++currentFrame >= frameLimit) [[unlikely]]
|
||||||
|
{
|
||||||
|
POISON_MAX_RECURSION_DEPTH_EXCEED_INST =
|
||||||
|
Op::iAsBx(OpCode::Exit_MaxRecursionDepthExceeded, 0, 0);
|
||||||
|
return &POISON_MAX_RECURSION_DEPTH_EXCEED_INST;
|
||||||
|
}
|
||||||
|
|
||||||
|
*currentFrame = CallFrame{closure, closure->proto, closure->proto->code.data(), base};
|
||||||
return currentFrame->ip;
|
return currentFrame->ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,15 +382,28 @@ namespace Fig
|
|||||||
// 执行入口:接收 Proto
|
// 执行入口:接收 Proto
|
||||||
Result<Value, Error> Execute(CompiledModule *);
|
Result<Value, Error> Execute(CompiledModule *);
|
||||||
|
|
||||||
inline void PrintRegisters()
|
void PrintRegisters(std::ostream &ostream = CoreIO::GetStdOut())
|
||||||
{
|
{
|
||||||
std::cout << "=== Registers ===" << '\n';
|
ostream << "=== Registers ===\n";
|
||||||
for (unsigned int i = 0; i < MAX_REGISTERS; ++i)
|
for (unsigned int i = 0; i < MAX_REGISTERS; ++i)
|
||||||
{
|
{
|
||||||
Value &v = registers[i];
|
Value &v = registers[i];
|
||||||
if (!v.IsNull())
|
if (!v.IsNull())
|
||||||
{
|
{
|
||||||
std::println("[{}] {}", i, v.ToString());
|
ostream << std::format("[{}] {}\n", i, v.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintGlobals(std::ostream &ostream = CoreIO::GetStdOut())
|
||||||
|
{
|
||||||
|
ostream << "== Globals ===\n";
|
||||||
|
for (unsigned int i = 0; i < MAX_GLOBALS; ++i)
|
||||||
|
{
|
||||||
|
Value &v = globals[i];
|
||||||
|
if (!v.IsNull())
|
||||||
|
{
|
||||||
|
ostream << std::format("[{}] {}\n", i, v.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ int main()
|
|||||||
std::cout << "Result: " << (*result_).ToString() << "\n";
|
std::cout << "Result: " << (*result_).ToString() << "\n";
|
||||||
std::cout << "Execution Cost: " << duration.count() << "ms\n";
|
std::cout << "Execution Cost: " << duration.count() << "ms\n";
|
||||||
|
|
||||||
vm.PrintRegisters();
|
vm.PrintRegisters();
|
||||||
|
vm.PrintGlobals();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user