对编译器和虚拟机进行重构,以支持闭包和垃圾回收功能

- 去除了不再使用的结构,并更新了编译器以处理新的闭包语义。
- 改进了 Compiler,使其能够生成带有源位置跟踪的指令。
- 在 FunctionObject 和 VM 中引入了作用域变量管理,以支持动态闭包。
- 实现了使用标记-扫描(Mark-And-Sweep) (Tri-Color tracing) 算法的垃圾回收机制,包括对作用域变量的处理。
- 在 VM 中增加了函数加载和作用域变量检索的支持。
- 更新了对象模型,包括引入 InstanceObject 并改进内存管理。
- 添加了用于调试的全局变量打印功能。
This commit is contained in:
2026-03-11 16:53:10 +08:00
parent 0f635ccf2b
commit 51a939ac45
20 changed files with 712 additions and 126 deletions

View 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")

View File

@@ -6,6 +6,7 @@
#pragma once
#include <Ast/Base.hpp>
#include <Sema/Environment.hpp>
#include <Bytecode/Bytecode.hpp>
namespace Fig
{
@@ -33,6 +34,9 @@ namespace Fig
Type resolvedReturnType;
Symbol *resolvedSymbol = nullptr; // 连接物理符号
int protoIndex = -1; // 在CompiledModule扁平化protos的下标
DynArray<UpvalueInfo> upvalues;
FnDefStmt() { type = AstType::FnDefStmt; }
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)

View File

@@ -5,8 +5,13 @@
#pragma once
#include <Deps/Deps.hpp>
#include <Object/ObjectBase.hpp>
#include <Core/SourceLocations.hpp>
#include <cstdint>
namespace Fig
{
using Instruction = std::uint32_t;
@@ -80,4 +85,27 @@ namespace Fig
| (static_cast<std::uint32_t>(static_cast<std::uint16_t>(sbx)) << 16);
}
} // 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

View File

@@ -3,16 +3,20 @@
@brief 编译器主逻辑实现:物理 Bootstrapper 与双步扫描
*/
#include <Compiler/Compiler.hpp>
#include <Ast/Stmt/FnDefStmt.hpp>
#include <Compiler/Compiler.hpp>
namespace Fig
{
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();
bootProto->name = "[bootstrapper]";
module->protos.push_back(bootProto);
@@ -20,17 +24,22 @@ namespace Fig
int initIdx = -1;
int mainIdx = -1;
// 2. 第一步:预扫描顶层函数,锁定物理索引
SourceLocation *mainFnLoc = nullptr;
SourceLocation *initFnLoc = nullptr;
// 预扫描顶层函数
for (auto *stmt : program->nodes)
{
if (stmt->type == AstType::FnDefStmt)
{
auto *f = static_cast<FnDefStmt *>(stmt);
int idx = (int) module->protos.size();
Proto *p = new Proto();
p->name = f->name;
p->numParams = (uint8_t) f->params.size();
p->maxRegisters = p->numParams;
f->protoIndex = idx;
module->protos.push_back(p);
@@ -41,13 +50,19 @@ namespace Fig
}
if (f->name == "init")
initIdx = idx;
{
initIdx = idx;
initFnLoc = &stmt->location;
}
if (f->name == "main")
mainIdx = idx;
{
mainIdx = idx;
mainFnLoc = &stmt->location;
}
}
}
// 3. 第二步:在 Bootstrapper 环境中编译所有语句
// Bootstrapper 中编译所有语句
FuncState bootState(bootProto, nullptr);
current = &bootState;
@@ -60,18 +75,18 @@ namespace Fig
}
}
// 4. 发射 Bootstrapper 引导指令
// 发射 Bootstrapper 引导指令
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)
{
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;
}
@@ -89,7 +104,8 @@ namespace Fig
{
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++;
@@ -112,14 +128,15 @@ namespace Fig
{
if (current->constantMap.contains(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->constantMap[val] = 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

View File

@@ -14,23 +14,6 @@ namespace Fig
{
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
{
private:
@@ -60,7 +43,7 @@ namespace Fig
void freeReg(Register count = 1);
int addConstant(Value val);
void emit(Instruction instr);
void emit(Instruction inst, SourceLocation *loc);
Result<void, Error> compileStmt(Stmt *stmt);
Result<Register, Error> compileExpr(Expr *expr, Register target = NO_REG);

View File

@@ -94,24 +94,24 @@ namespace Fig
parsePhysicalNumber(manager.GetSub(tok.index, tok.length), l->location);
if (!vRes)
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)
{
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)
{
emit(Op::iABC(OpCode::LoadNull, r, 0, 0));
emit(Op::iABC(OpCode::LoadNull, r, 0, 0), &l->location);
}
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)
{
emit(Op::iABC(OpCode::LoadFalse, r, 0, 0));
emit(Op::iABC(OpCode::LoadFalse, r, 0, 0), &l->location);
}
return r;
}
@@ -129,7 +129,7 @@ namespace Fig
// 仅在被强制指定目标(如参数装填)时发射搬运指令
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;
}
@@ -137,12 +137,12 @@ namespace Fig
Register r = (target == NO_REG) ? *allocateReg(i->location) : target;
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)
{
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;
}
@@ -167,30 +167,43 @@ namespace Fig
return std::unexpected(res.error());
}
bool isGlobalFastCall = false;
if (c->callee->type == AstType::IdentiExpr)
{
// 静态去虚化:编译期直接跳板
auto *id = static_cast<IdentiExpr *>(c->callee);
int protoIdx = id->resolvedSymbol->index;
emit(Op::iABC(OpCode::FastCall,
static_cast<uint8_t>(protoIdx),
baseReg,
static_cast<uint8_t>(c->args.args.size())));
auto *id = static_cast<IdentiExpr *>(c->callee);
// 只有在全局区的函数,才能使用 FastCall
if (id->resolvedSymbol->location == SymbolLocation::Global)
{
isGlobalFastCall = true;
int protoIdx = id->resolvedSymbol->index;
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);
if (!r_fn)
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;
// 目标对齐:若 target 未指定allocateReg 将自然复用 baseReg实现零开销回写
// 目若 target 未指定allocateReg 将复用 baseReg实现零开销回写
Register r_dest;
if (target == NO_REG)
@@ -207,7 +220,7 @@ namespace Fig
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;
@@ -227,18 +240,18 @@ namespace Fig
Symbol *sym = lid->resolvedSymbol;
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)
{
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
{
emit(Op::iABx(OpCode::SetGlobal,
*r_val,
static_cast<uint16_t>(getGlobalID(lid->name))));
static_cast<uint16_t>(getGlobalID(lid->name))), &lid->location);
}
}
return r_val;
@@ -300,7 +313,7 @@ namespace Fig
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;
}

View File

@@ -9,7 +9,6 @@
#include <Ast/Stmt/WhileStmt.hpp>
#include <Compiler/Compiler.hpp>
namespace Fig
{
Result<void, Error> Compiler::compileStmt(Stmt *stmt)
@@ -41,8 +40,10 @@ namespace Fig
if (!regRes)
return std::unexpected(regRes.error());
emit(Op::iABx(
OpCode::SetGlobal, *regRes, static_cast<uint16_t>(getGlobalID(v->name))));
emit(Op::iABx(OpCode::SetGlobal,
*regRes,
static_cast<uint16_t>(getGlobalID(v->name))),
&v->location);
current->freereg = mark; // 释放初始化表达式的临时占用
}
else
@@ -68,8 +69,21 @@ namespace Fig
case AstType::FnDefStmt: {
auto *f = static_cast<FnDefStmt *>(stmt);
// 物理连线:对接 Compile() 第一阶段预分配的 Proto
Proto *p = module->protos[f->resolvedSymbol->index];
if (f->protoIndex == -1) // 闭包环境没有被扫到
{
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 *old = current;
@@ -79,13 +93,47 @@ namespace Fig
if (!res)
return res;
// 窥孔拦截:防死代码污染
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;
// 如果是局部闭包,在当前栈帧分配寄存器并生成 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;
}
@@ -99,13 +147,13 @@ namespace Fig
return std::unexpected(r_cond.error());
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; // 回收条件表达式临时槽位
if (auto r = compileStmt(i->consequent); !r)
return r;
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());
current->proto->code[jmpToNext] = Op::iAsBx(
@@ -119,17 +167,22 @@ namespace Fig
return std::unexpected(ec.error());
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 临时槽位
if (auto r = compileStmt(elif->consequent); !r)
return r;
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(
OpCode::JmpIfFalse, *ec, static_cast<int16_t>(target - nextElif - 1));
current->proto->locations.resize(nextElif);
current->proto->locations[nextElif] = &elif->location;
}
if (i->alternate)
@@ -157,14 +210,15 @@ namespace Fig
return std::unexpected(r_cond.error());
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; // 回收循环条件临时槽位
if (auto r = compileStmt(w->body); !r)
return r;
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());
current->proto->code[exitJmpIdx] = Op::iAsBx(
@@ -189,11 +243,11 @@ namespace Fig
auto r = allocateReg(rs->location);
if (!r)
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;
}
emit(Op::iABC(OpCode::Return, retReg, 0, 0));
emit(Op::iABC(OpCode::Return, retReg, 0, 0), &rs->location);
current->freereg = mark; // 回收返回值计算的占用
break;
}

View File

@@ -1,26 +1,40 @@
/*!
@file src/Object/FunctionObject.hpp
@brief 函数对象定义
@author PuqiAR (im@puqiar.top)
@date 2026-02-28
*/
#pragma once
#include <Object/ObjectBase.hpp>
#include <Bytecode/Bytecode.hpp>
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
{
String name; // 调试使用
Proto *proto; // 指向编译器生成的只读字节码与常量池
std::uint8_t paraCount;
String name;
Proto *proto; // 静态只读字节码
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

View 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[];
};
}

View File

@@ -5,7 +5,7 @@
@date 2026-02-19
*/
#include <Object/ObjectBase.hpp>
#include <Object/Object.hpp>
namespace Fig
{
@@ -29,7 +29,35 @@ namespace Fig
}
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
{

View File

@@ -7,7 +7,8 @@
#pragma once
#include <Object/FunctionObject.hpp>
#include <Object/InstanceObject.hpp>
#include <Object/ObjectBase.hpp>
#include <Object/StringObject.hpp>
#include <Object/StructObject.hpp>
#include <Object/FunctionObject.hpp>

View File

@@ -125,7 +125,7 @@ namespace Fig
{
return (v_ & (SIGN_BIT | QNAN_MASK)) == (SIGN_BIT | QNAN_MASK);
}
// 提取数据 (Unbox / As)
[[nodiscard]] constexpr double AsDouble() const
{
@@ -165,7 +165,8 @@ namespace Fig
// 让 VM 的 OP_EQ 指令极简:`if (RA == RB)`
[[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())
{
return AsDouble() == other.AsDouble();
@@ -199,13 +200,20 @@ namespace Fig
struct StructObject /* : public Object */; // 结构体基类的定义,前向声明
enum class GCColor : std::uint8_t
{
White = 0, // 垃圾(或新对象)!
Gray = 1, // 已发现,子节点待扫描
Black = 2, // 存活
};
// Total 24 bytes size
struct Object
{
Object *next; // 8 bytes: gc链表
StructObject *klass; // 8 bytes: 一切皆对象,父类指针
ObjectType type; // 1 byte : 类型
bool isMarked = false; // 1 byte : gc标记
Object *next; // 8 bytes: gc链表
StructObject *klass; // 8 bytes: 一切皆对象,父类指针
ObjectType type; // 1 byte : 类型
GCColor color = GCColor::White; // 1 byte : gc标记
// + 6 bytes padding
constexpr bool isString() const
@@ -227,12 +235,6 @@ namespace Fig
{
return type == ObjectType::Instance;
}
// 调试输出
virtual String toString() const
{
return "Object";
}
};
} // namespace Fig

View File

@@ -25,10 +25,5 @@ namespace Fig
struct StringObject final : public Object
{
String data; // 40 bytes
virtual String toString() const override
{
return data;
}
};
};

View File

@@ -39,9 +39,6 @@ namespace Fig
0 - UnaryOperators::Count BinaryOperators::Count
*/
Value fields[];
Object *GetUnaryOperator(UnaryOperator _op)
{

View File

@@ -206,8 +206,39 @@ namespace Fig
v->localId = idx;
break;
}
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);
ScopeGuard scopeGuard(env, true);
for (auto *p : f->params)
@@ -220,8 +251,15 @@ namespace Fig
}
if (auto r = analyzeStmt(f->body); !r)
return r;
for (const auto &upval : env.current->upvalues)
{
f->upvalues.push_back({static_cast<std::uint8_t>(upval.index), upval.isLocal});
}
break;
}
case AstType::IfStmt: {
auto *i = static_cast<IfStmt *>(stmt);
@@ -394,7 +432,7 @@ namespace Fig
auto r = analyzeExpr(arg.value);
if (!r)
return std::unexpected(r.error());
// 顺手做字段赋值类型检查
// 字段赋值类型检查
if (!arg.name.empty()
&& !r->isAssignableTo(st->fields[st->fieldMap[arg.name]].type))
{
@@ -436,7 +474,7 @@ namespace Fig
if (l.is(TypeTag::Any) || r.is(TypeTag::Any))
return expr->resolvedType = typeCtx.GetBasic(TypeTag::Any);
// 🔥 算术操作强检查
// 算术操作强检查
if (in->op == BinaryOperator::Add && l.is(TypeTag::String) && r.is(TypeTag::String))
return expr->resolvedType = typeCtx.GetBasic(TypeTag::String);
if (l.is(TypeTag::Int) && r.is(TypeTag::Int))
@@ -467,7 +505,7 @@ namespace Fig
if (calleeType.is(TypeTag::Any))
return expr->resolvedType = typeCtx.GetBasic(TypeTag::Any);
// 🔥 终极函数签名校验
// 函数签名校验
if (!calleeType.is(TypeTag::Function))
return std::unexpected(
Error(ErrorType::TypeError, "callee is not a function", "", c->location));

View File

@@ -42,7 +42,7 @@ namespace Fig
return true; // Any 逃逸通道
if (this->is(TypeTag::Null) && target.isNullable)
return true; // Null 安全赋值
return this->base == target.base && (!this->isNullable || target.isNullable); // 严格匹配
return this->base == target.base && (!this->isNullable || target.isNullable);
}
TypeContext::TypeContext()

View File

@@ -76,7 +76,7 @@ namespace Fig
};
DynArray<Field> fields;
HashMap<String, size_t> fieldMap;
HashMap<String, class FnDefStmt *> methods;
HashMap<String, struct FnDefStmt *> methods;
StructType(String n) : BaseType(TypeTag::Struct, std::move(n)) {}
void AddField(String name, Type type, bool isPublic)

View File

@@ -150,7 +150,8 @@ namespace Fig
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
(currentFrame - 1)->proto->name); // pushFrame失败了但currentFrame仍然移动所以
// (currentFrame - 1)是 lastFrame
std::exit(static_cast<int>(MAX_RECURSION_DEPTH));
}
@@ -191,6 +192,40 @@ namespace Fig
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
{
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();
}
@@ -198,8 +233,9 @@ namespace Fig
std::uint8_t a = decodeA(inst);
Value retVal = currentFrame->registerBase[a];
// 此时 registerBase[0] 指向的是 Caller 的 baseReg 槽位
closeUpvalues(currentFrame->registerBase);
// 此时 registerBase[0] 指向的是 Caller 的 baseReg 槽位
currentFrame->registerBase[0] = retVal;
popFrame();
@@ -207,6 +243,67 @@ namespace Fig
}
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 = &currentFrame->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();
}
@@ -315,12 +412,17 @@ namespace Fig
}
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();
}
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();
}

View File

@@ -9,8 +9,9 @@
#include <Compiler/Compiler.hpp>
#include <Object/Object.hpp>
#include <cassert>
#include <Core/Core.hpp>
#include <cassert>
#include <iostream> // debug
#include <print>
@@ -18,9 +19,10 @@ namespace Fig
{
struct CallFrame
{
Proto *proto; // 当前执行的原型
Instruction *ip; // 当前指令指针
Value *registerBase; // 寄存器起点
FunctionObject *closure; // 动态闭包Context (FastCall时 null)
Proto *proto; // 当前执行的原型
Instruction *ip; // 当前指令指针
Value *registerBase; // 寄存器起点
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
{
private:
@@ -45,6 +55,251 @@ namespace Fig
CallFrame *currentFrame;
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:
VM()
{
@@ -66,7 +321,7 @@ namespace Fig
private:
[[nodiscard]]
inline Instruction *pushFrame(Proto *proto, Value *base)
inline Instruction *pushFrame(Proto *proto, Value *base) // fastcall
{
if (++currentFrame >= frameLimit) [[unlikely]] // 达到最大递归层数
{
@@ -75,7 +330,21 @@ namespace Fig
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;
}
@@ -113,15 +382,28 @@ namespace Fig
// 执行入口:接收 Proto
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)
{
Value &v = registers[i];
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());
}
}
}

View File

@@ -81,6 +81,7 @@ int main()
std::cout << "Result: " << (*result_).ToString() << "\n";
std::cout << "Execution Cost: " << duration.count() << "ms\n";
vm.PrintRegisters();
vm.PrintRegisters();
vm.PrintGlobals();
return 0;
}