refactor: 引入 Arena 内存池并优化指令分发,为类型系统重构做准备

This commit is contained in:
2026-03-08 15:59:55 +08:00
parent 91e4eb734e
commit 90448006ff
13 changed files with 301 additions and 36 deletions

View File

@@ -21,6 +21,7 @@ namespace Fig
enum class OpCode : std::uint8_t
{
Exit, // 结束运行
LoadK, // iABx 模式: R[A] = Constants[Bx]
LoadTrue, // iABC: R[A] = true
LoadFalse, // iABC: R[A] = false
@@ -35,7 +36,8 @@ namespace Fig
Jmp, // iAsBx: ip += sBx 无条件跳转
JmpIfFalse, // iAsBx: 如果 R[A] 为假, ip += sBx
Mov, // iABx: R[A] = R[Bx]
Mov, // iABx: R[A] = R[Bx]
Add, // iABC: R[A] = R[B] + R[C]
Sub, // iABC: R[A] = R[B] - R[C]
Mul, // iABC: R[A] = R[B] * R[C]
@@ -43,6 +45,11 @@ namespace Fig
Mod, // iABC: R[A] = R[B] % R[C]
BitXor, // iABC: R[A] = R[B] ^ R[C]
IntFastAdd, // iABC: R[A] (Int) = R[B] (Int) + R[C] (Int)
IntFastSub, // iABC: R[A] (Int) = R[B] (Int) - R[C] (Int)
IntFastMul, // iABC: R[A] (Int) = R[B] (Int) * R[C] (Int)
IntFastDiv, // iABC: R[A] (Double) = R[B] (Int) / R[C] (Int)
Equal, // iABC: R[A] = R[B] == R[C]
NotEqual, // iABC: R[A] = R[B] != R[C]
Greater, // iABC: R[A] = R[B] > R[C]

View File

@@ -346,7 +346,13 @@ namespace Fig
case OpCode::Sub:
case OpCode::Mul:
case OpCode::Div:
case OpCode::Mod: {
case OpCode::Mod:
case OpCode::IntFastAdd:
case OpCode::IntFastSub:
case OpCode::IntFastMul:
case OpCode::IntFastDiv:
{
// iABC 模式:解析 B (16~23 位) 和 C (24~31 位)
std::uint8_t b = (inst >> 16) & 0xFF;
std::uint8_t c = (inst >> 24) & 0xFF;

View File

@@ -139,13 +139,16 @@ namespace Fig
return compileAssignment(infix);
}
const auto &_lhsReg = compileExpr(infix->left);
Expr *left = infix->left;
Expr *right = infix->right;
const auto &_lhsReg = compileExpr(left);
if (!_lhsReg)
{
return _lhsReg;
}
std::uint8_t lhsReg = *_lhsReg;
const auto &_rhsReg = compileExpr(infix->right);
const auto &_rhsReg = compileExpr(right);
if (!_rhsReg)
{
return _rhsReg;
@@ -156,25 +159,58 @@ namespace Fig
FreeReg(lhsReg);
std::uint8_t resultReg = AllocReg();
switch (infix->op)
{
case BinaryOperator::Add: {
Emit(Op::iABC(OpCode::Add, resultReg, lhsReg, rhsReg));
if (left->resolvedType == right->resolvedType && left->resolvedType->isInt())
{
// Int + Int
Emit(Op::iABC(OpCode::IntFastAdd, resultReg, lhsReg, rhsReg));
}
else
{
Emit(Op::iABC(OpCode::Add, resultReg, lhsReg, rhsReg));
}
break;
}
case BinaryOperator::Subtract: {
Emit(Op::iABC(OpCode::Sub, resultReg, lhsReg, rhsReg));
if (left->resolvedType == right->resolvedType && left->resolvedType->isInt())
{
// Int - Int
Emit(Op::iABC(OpCode::IntFastSub, resultReg, lhsReg, rhsReg));
}
else
{
Emit(Op::iABC(OpCode::Sub, resultReg, lhsReg, rhsReg));
}
break;
}
case BinaryOperator::Multiply: {
Emit(Op::iABC(OpCode::Mul, resultReg, lhsReg, rhsReg));
if (left->resolvedType == right->resolvedType && left->resolvedType->isInt())
{
// Int * Int
Emit(Op::iABC(OpCode::IntFastMul, resultReg, lhsReg, rhsReg));
}
else
{
Emit(Op::iABC(OpCode::Mul, resultReg, lhsReg, rhsReg));
}
break;
}
case BinaryOperator::Divide: {
Emit(Op::iABC(OpCode::Div, resultReg, lhsReg, rhsReg));
if (left->resolvedType == right->resolvedType && left->resolvedType->isInt())
{
// Int / Int
Emit(Op::iABC(OpCode::IntFastDiv, resultReg, lhsReg, rhsReg));
}
else
{
Emit(Op::iABC(OpCode::Div, resultReg, lhsReg, rhsReg));
}
break;
}
@@ -267,7 +303,7 @@ namespace Fig
for (size_t i = 0; i < expr->args.size(); ++i)
{
std::uint8_t argTarget = AllocReg();
auto argRes = compileExpr(expr->args.args[i]);
auto argRes = compileExpr(expr->args.args[i]);
if (!argRes)
{
return argRes;

View File

@@ -41,7 +41,9 @@ namespace Fig::CoreIO
void InitConsoleIO()
{
#ifdef _WIN32
SetConsoleCP(CP_UTF8);
SetConsoleOutputCP(CP_UTF8);
#endif
}
};

View File

@@ -9,7 +9,6 @@
#include <Object/ObjectBase.hpp>
namespace Fig
{
// 运行时闭包对象 (24字节 Base + 8字节 Proto指针 = 32 bytes)
@@ -17,7 +16,9 @@ namespace Fig
struct Proto;
struct FunctionObject final : public Object
{
String name; // 调试使用
Proto *proto; // 指向编译器生成的只读字节码与常量池
std::uint8_t paraCount;
// TODO: 实现闭包时 加一个 Upvalue 指针数组
// Value* upvalues;

View File

@@ -14,7 +14,7 @@ namespace Fig
StateProtector p(this, {State::ParsingLiteralExpr});
const Token &literal_token = consumeToken();
LiteralExpr *node = new LiteralExpr(literal_token, makeSourceLocation(literal_token));
LiteralExpr *node = arena.Allocate<LiteralExpr>(literal_token, makeSourceLocation(literal_token));
return node;
}
Result<IdentiExpr *, Error> Parser::parseIdentiExpr() // 当前token为Identifier调用
@@ -22,7 +22,7 @@ namespace Fig
StateProtector p(this, {State::ParsingIdentiExpr});
const Token &identifier = consumeToken();
IdentiExpr *node = new IdentiExpr(
IdentiExpr *node = arena.Allocate<IdentiExpr>(
srcManager.GetSub(identifier.index, identifier.length), makeSourceLocation(identifier));
return node;
}
@@ -42,7 +42,7 @@ namespace Fig
}
Expr *rhs = *rhs_result;
InfixExpr *node = new InfixExpr(lhs, op, rhs);
InfixExpr *node = arena.Allocate<InfixExpr>(lhs, op, rhs);
return node;
}
@@ -61,7 +61,7 @@ namespace Fig
}
Expr *rhs = *rhs_result;
PrefixExpr *node = new PrefixExpr(op, rhs);
PrefixExpr *node = arena.Allocate<PrefixExpr>(op, rhs);
return node;
}
@@ -87,7 +87,7 @@ namespace Fig
}
consumeToken(); // consume `]`
IndexExpr *indexExpr = new IndexExpr(base, *index_result);
IndexExpr *indexExpr = arena.Allocate<IndexExpr>(base, *index_result);
return indexExpr;
}
@@ -104,7 +104,7 @@ namespace Fig
if (currentToken().type == TokenType::RightParen)
{
consumeToken(); // consume `)`
return new CallExpr(callee, callArgs);
return arena.Allocate<CallExpr>(callee, callArgs);
}
while (true)
@@ -140,7 +140,7 @@ namespace Fig
consumeToken(); // consume `,`
}
return new CallExpr(callee, callArgs);
return arena.Allocate<CallExpr>(callee, callArgs);
}
Result<Expr *, Error> Parser::parseExpression(BindingPower rbp)

View File

@@ -11,7 +11,7 @@ namespace Fig
{
Result<Program *, Error> Parser::Parse()
{
Program *program = new Program;
Program *program = arena.Allocate<Program>();
while (!isEOF)
{
auto result = parseStatement();
@@ -27,5 +27,6 @@ namespace Fig
program->nodes.push_back(stmt);
}
return program;
}
}; // namespace Fig

View File

@@ -12,6 +12,7 @@
#include <Error/Error.hpp>
#include <Lexer/Lexer.hpp>
#include <Token/Token.hpp>
#include <Utils/Arena.hpp>
#include <cstddef>
#include <cstdlib>
@@ -24,6 +25,7 @@ namespace Fig
class Parser
{
private:
Arena arena;
Lexer &lexer;
SourceManager &srcManager;

View File

@@ -12,7 +12,7 @@ namespace Fig
Result<BlockStmt *, Error> Parser::parseBlockStmt() // 当前token为 {
{
SourceLocation location = makeSourceLocation(consumeToken()); // consume `{`
BlockStmt *stmt = new BlockStmt();
BlockStmt *stmt = arena.Allocate<BlockStmt>();
while (true)
{
if (isEOF)
@@ -94,7 +94,7 @@ namespace Fig
{
return std::unexpected(makeExpectSemicolonError());
}
VarDecl *varDecl = new VarDecl(isPublic, name, typeSpeicifer, isInfer, initExpr, location);
VarDecl *varDecl = arena.Allocate<VarDecl>(isPublic, name, typeSpeicifer, isInfer, initExpr, location);
return varDecl;
}
@@ -207,7 +207,7 @@ namespace Fig
return std::unexpected(result.error());
}
BlockStmt *consequent = *result;
ElseIfStmt *elif = new ElseIfStmt(cond, consequent, elseLocation);
ElseIfStmt *elif = arena.Allocate<ElseIfStmt>(cond, consequent, elseLocation);
elifs.push_back(elif);
}
else
@@ -233,7 +233,7 @@ namespace Fig
alternate = *result;
}
}
IfStmt *ifStmt = new IfStmt(cond, consequent, elifs, alternate, location);
IfStmt *ifStmt = arena.Allocate<IfStmt>(cond, consequent, elifs, alternate, location);
return ifStmt;
}
@@ -291,7 +291,7 @@ namespace Fig
}
BlockStmt *body = *result;
WhileStmt *whileStmt = new WhileStmt(cond, body, location);
WhileStmt *whileStmt = arena.Allocate<WhileStmt>(cond, body, location);
return whileStmt;
}
@@ -350,7 +350,7 @@ namespace Fig
defaultValue = *result;
}
PosParam *posParam = new PosParam(name, type, defaultValue, location);
PosParam *posParam = arena.Allocate<PosParam>(name, type, defaultValue, location);
params.push_back(posParam);
if (match(TokenType::Comma))
@@ -423,7 +423,7 @@ namespace Fig
}
body = *bodyResult;
FnDefStmt *fnDef = new FnDefStmt(isPublic, name, params, returnType, body, location);
FnDefStmt *fnDef = arena.Allocate<FnDefStmt>(isPublic, name, params, returnType, body, location);
return fnDef;
}
@@ -440,7 +440,7 @@ namespace Fig
}
Expr *value = *result;
ReturnStmt *returnStmt = new ReturnStmt(value, location);
ReturnStmt *returnStmt = arena.Allocate<ReturnStmt>(value, location);
if (!match(TokenType::Semicolon))
{
@@ -507,7 +507,7 @@ namespace Fig
{
return std::unexpected(makeExpectSemicolonError());
}
BreakStmt *breakStmt = new BreakStmt(location);
BreakStmt *breakStmt = arena.Allocate<BreakStmt>(location);
return breakStmt;
}
@@ -518,7 +518,7 @@ namespace Fig
{
return std::unexpected(makeExpectSemicolonError());
}
ContinueStmt *continueStmt = new ContinueStmt(location);
ContinueStmt *continueStmt = arena.Allocate<ContinueStmt>(location);
return continueStmt;
}
@@ -532,7 +532,7 @@ namespace Fig
{
return std::unexpected(expr_result.error());
}
ExprStmt *exprStmt = new ExprStmt(*expr_result);
ExprStmt *exprStmt = arena.Allocate<ExprStmt>(*expr_result);
if (!match(TokenType::Semicolon))
{
return std::unexpected(makeExpectSemicolonError());

View File

@@ -5,8 +5,6 @@
@date 2026-02-25
*/
#pragma once
#include <Parser/Parser.hpp>
namespace Fig
@@ -37,7 +35,7 @@ namespace Fig
break;
}
}
NamedTypeExpr *namedTypeExpr = new NamedTypeExpr(path, location);
NamedTypeExpr *namedTypeExpr = arena.Allocate<NamedTypeExpr>(path, location);
return namedTypeExpr;
}

View File

@@ -33,6 +33,41 @@ namespace Fig
{
return tag == TypeTag::Any;
}
bool isNull() const
{
return tag == TypeTag::Null;
}
bool isInt() const
{
return tag == TypeTag::Int;
}
bool isDouble() const
{
return tag == TypeTag::Double;
}
bool isBool() const
{
return tag == TypeTag::Bool;
}
bool isString() const
{
return tag == TypeTag::String;
}
bool isFunction() const
{
return tag == TypeTag::Function;
}
bool isStruct() const
{
return tag == TypeTag::Struct;
}
};
// 全局唯一类型驻留池

115
src/Utils/Arena.hpp Normal file
View File

@@ -0,0 +1,115 @@
/*!
@file src/Utils/Arena.hpp
@brief 线性分配内存池,支持非平凡析构对象的自动清理
@author PuqiAR (im@puqiar.top)
@date 2026-03-08
*/
#pragma once
#include <cstddef>
#include <vector>
#include <memory>
#include <type_traits>
namespace Fig
{
class Arena
{
private:
struct DestructorNode
{
void (*destructor)(void *);
void *object;
DestructorNode *next;
};
static constexpr std::size_t CHUNK_SIZE = 64 * 1024; // 64KB 块大小
std::vector<char *> chunks;
char *currentPtr = nullptr;
std::size_t remaining = 0;
DestructorNode *destructorHead = nullptr;
public:
Arena() = default;
~Arena()
{
// 1. 逆序调用析构函数
DestructorNode *node = destructorHead;
while (node)
{
node->destructor(node->object);
node = node->next;
}
// 2. 释放所有分配的内存块
for (char *chunk : chunks)
{
delete[] chunk;
}
}
// 禁止拷贝和移动,防止内存所有权混乱
Arena(const Arena &) = delete;
Arena &operator=(const Arena &) = delete;
template <typename T, typename... Args>
T *Allocate(Args &&...args)
{
std::size_t size = sizeof(T);
std::size_t alignment = alignof(T);
// 在当前块中尝试对齐并分配
void *ptr = allocateRaw(size, alignment);
// 在分配的内存上构造对象
T *obj = new (ptr) T(std::forward<Args>(args)...);
// 如果 T 需要析构(如包含 String注册到销毁链表
if constexpr (!std::is_trivially_destructible_v<T>)
{
// 注意: DestructorNode 本身是 POD直接在 Arena 里分配,不需要注册析构
void *nodeRaw = allocateRaw(sizeof(DestructorNode), alignof(DestructorNode));
DestructorNode *node = new (nodeRaw) DestructorNode();
node->object = obj;
node->destructor = [](void *p) { static_cast<T *>(p)->~T(); };
node->next = destructorHead;
destructorHead = node;
}
return obj;
}
private:
void *allocateRaw(std::size_t size, std::size_t alignment)
{
// 对齐计算
std::size_t adjustment = 0;
std::size_t currentAddr = reinterpret_cast<std::size_t>(currentPtr);
if (alignment > 0 && (currentAddr % alignment) != 0)
{
adjustment = alignment - (currentAddr % alignment);
}
if (remaining < (size + adjustment))
{
// 当前块空间不足,分配新块
std::size_t nextChunkSize = (size > CHUNK_SIZE) ? size : CHUNK_SIZE;
currentPtr = new char[nextChunkSize];
chunks.push_back(currentPtr);
remaining = nextChunkSize;
adjustment = 0; // 新分配的块通常是最大对齐的
}
currentPtr += adjustment;
void *res = currentPtr;
currentPtr += size;
remaining -= (size + adjustment);
return res;
}
};
} // namespace Fig

View File

@@ -86,24 +86,37 @@ namespace Fig
pushFrame(entry, registers);
// 🔥 必须与 Bytecode.hpp 中的 OpCode 枚举严格一一对应!
static const void *dispatchTable[] = {&&do_Exit,
static const void *dispatchTable[] = {
&&do_Exit,
&&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,
@@ -114,7 +127,7 @@ namespace Fig
Instruction inst;
// 🔥 核心分发引擎:取指 -> 直接查表并 Jump
// 取指 -> 直接查表并 Jump
#define DISPATCH() \
do \
{ \
@@ -122,7 +135,7 @@ namespace Fig
goto *dispatchTable[inst & 0xFF]; \
} while (0)
// 引擎点火
// 引擎点火!! :3
DISPATCH();
do_Exit: {
@@ -215,6 +228,54 @@ namespace Fig
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(l.AsInt() + r.AsInt());
DISPATCH();
}
BINARY_COMPARE_OP(Equal, ==);
BINARY_COMPARE_OP(NotEqual, !=);
BINARY_COMPARE_OP(Greater, >);
@@ -226,5 +287,6 @@ namespace Fig
assert(false && "Hit Count sentinel!");
return Value::GetNullInstance();
}
}
}; // namespace Fig