From 90448006ff7803ee8320f47e0affaad130a57251 Mon Sep 17 00:00:00 2001 From: PuqiAR Date: Sun, 8 Mar 2026 15:59:55 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=BC=95=E5=85=A5=20Arena=20?= =?UTF-8?q?=E5=86=85=E5=AD=98=E6=B1=A0=E5=B9=B6=E4=BC=98=E5=8C=96=E6=8C=87?= =?UTF-8?q?=E4=BB=A4=E5=88=86=E5=8F=91=EF=BC=8C=E4=B8=BA=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E9=87=8D=E6=9E=84=E5=81=9A=E5=87=86=E5=A4=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Bytecode/Bytecode.hpp | 9 ++- src/Compiler/Compiler.hpp | 8 ++- src/Compiler/ExprCompiler.cpp | 52 ++++++++++++--- src/Core/CoreIO.cpp | 2 + src/Object/FunctionObject.hpp | 3 +- src/Parser/ExprParser.cpp | 14 ++--- src/Parser/Parser.cpp | 3 +- src/Parser/Parser.hpp | 2 + src/Parser/StmtParser.cpp | 22 +++---- src/Parser/TypeExprParser.cpp | 4 +- src/Sema/Type.hpp | 35 +++++++++++ src/Utils/Arena.hpp | 115 ++++++++++++++++++++++++++++++++++ src/VM/VM.cpp | 68 +++++++++++++++++++- 13 files changed, 301 insertions(+), 36 deletions(-) create mode 100644 src/Utils/Arena.hpp diff --git a/src/Bytecode/Bytecode.hpp b/src/Bytecode/Bytecode.hpp index 27847b7..c76aa40 100644 --- a/src/Bytecode/Bytecode.hpp +++ b/src/Bytecode/Bytecode.hpp @@ -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] diff --git a/src/Compiler/Compiler.hpp b/src/Compiler/Compiler.hpp index 651cdce..f53a7d4 100644 --- a/src/Compiler/Compiler.hpp +++ b/src/Compiler/Compiler.hpp @@ -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; diff --git a/src/Compiler/ExprCompiler.cpp b/src/Compiler/ExprCompiler.cpp index a4b54a1..3647839 100644 --- a/src/Compiler/ExprCompiler.cpp +++ b/src/Compiler/ExprCompiler.cpp @@ -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; } @@ -263,11 +299,11 @@ namespace Fig Emit(Op::iABx(OpCode::Mov, baseReg, *calleeRes)); } } - + 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; diff --git a/src/Core/CoreIO.cpp b/src/Core/CoreIO.cpp index 24505f0..363368e 100644 --- a/src/Core/CoreIO.cpp +++ b/src/Core/CoreIO.cpp @@ -41,7 +41,9 @@ namespace Fig::CoreIO void InitConsoleIO() { +#ifdef _WIN32 SetConsoleCP(CP_UTF8); SetConsoleOutputCP(CP_UTF8); +#endif } }; \ No newline at end of file diff --git a/src/Object/FunctionObject.hpp b/src/Object/FunctionObject.hpp index 416aba2..c5dd56e 100644 --- a/src/Object/FunctionObject.hpp +++ b/src/Object/FunctionObject.hpp @@ -9,7 +9,6 @@ #include - 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; diff --git a/src/Parser/ExprParser.cpp b/src/Parser/ExprParser.cpp index 522b71d..b94282e 100644 --- a/src/Parser/ExprParser.cpp +++ b/src/Parser/ExprParser.cpp @@ -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(literal_token, makeSourceLocation(literal_token)); return node; } Result 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( 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(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(op, rhs); return node; } @@ -87,7 +87,7 @@ namespace Fig } consumeToken(); // consume `]` - IndexExpr *indexExpr = new IndexExpr(base, *index_result); + IndexExpr *indexExpr = arena.Allocate(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(callee, callArgs); } while (true) @@ -140,7 +140,7 @@ namespace Fig consumeToken(); // consume `,` } - return new CallExpr(callee, callArgs); + return arena.Allocate(callee, callArgs); } Result Parser::parseExpression(BindingPower rbp) diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index a9915af..1db408d 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -11,7 +11,7 @@ namespace Fig { Result Parser::Parse() { - Program *program = new Program; + Program *program = arena.Allocate(); while (!isEOF) { auto result = parseStatement(); @@ -27,5 +27,6 @@ namespace Fig program->nodes.push_back(stmt); } return program; + } }; // namespace Fig \ No newline at end of file diff --git a/src/Parser/Parser.hpp b/src/Parser/Parser.hpp index d32725b..e1bf44b 100644 --- a/src/Parser/Parser.hpp +++ b/src/Parser/Parser.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -24,6 +25,7 @@ namespace Fig class Parser { private: + Arena arena; Lexer &lexer; SourceManager &srcManager; diff --git a/src/Parser/StmtParser.cpp b/src/Parser/StmtParser.cpp index 5b17ab1..ea13ea5 100644 --- a/src/Parser/StmtParser.cpp +++ b/src/Parser/StmtParser.cpp @@ -12,7 +12,7 @@ namespace Fig Result Parser::parseBlockStmt() // 当前token为 { { SourceLocation location = makeSourceLocation(consumeToken()); // consume `{` - BlockStmt *stmt = new BlockStmt(); + BlockStmt *stmt = arena.Allocate(); 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(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(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(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(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(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(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(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(location); return breakStmt; } @@ -518,7 +518,7 @@ namespace Fig { return std::unexpected(makeExpectSemicolonError()); } - ContinueStmt *continueStmt = new ContinueStmt(location); + ContinueStmt *continueStmt = arena.Allocate(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(*expr_result); if (!match(TokenType::Semicolon)) { return std::unexpected(makeExpectSemicolonError()); diff --git a/src/Parser/TypeExprParser.cpp b/src/Parser/TypeExprParser.cpp index 9556e6f..f56eb91 100644 --- a/src/Parser/TypeExprParser.cpp +++ b/src/Parser/TypeExprParser.cpp @@ -5,8 +5,6 @@ @date 2026-02-25 */ -#pragma once - #include namespace Fig @@ -37,7 +35,7 @@ namespace Fig break; } } - NamedTypeExpr *namedTypeExpr = new NamedTypeExpr(path, location); + NamedTypeExpr *namedTypeExpr = arena.Allocate(path, location); return namedTypeExpr; } diff --git a/src/Sema/Type.hpp b/src/Sema/Type.hpp index 49d11fd..fea4d34 100644 --- a/src/Sema/Type.hpp +++ b/src/Sema/Type.hpp @@ -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; + } }; // 全局唯一类型驻留池 diff --git a/src/Utils/Arena.hpp b/src/Utils/Arena.hpp new file mode 100644 index 0000000..431b83e --- /dev/null +++ b/src/Utils/Arena.hpp @@ -0,0 +1,115 @@ +/*! + @file src/Utils/Arena.hpp + @brief 线性分配内存池,支持非平凡析构对象的自动清理 + @author PuqiAR (im@puqiar.top) + @date 2026-03-08 +*/ + +#pragma once + +#include +#include +#include +#include + +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 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 + 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)...); + + // 如果 T 需要析构(如包含 String),注册到销毁链表 + if constexpr (!std::is_trivially_destructible_v) + { + // 注意: DestructorNode 本身是 POD,直接在 Arena 里分配,不需要注册析构 + void *nodeRaw = allocateRaw(sizeof(DestructorNode), alignof(DestructorNode)); + DestructorNode *node = new (nodeRaw) DestructorNode(); + + node->object = obj; + node->destructor = [](void *p) { static_cast(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(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 diff --git a/src/VM/VM.cpp b/src/VM/VM.cpp index b9a16be..210fc61 100644 --- a/src/VM/VM.cpp +++ b/src/VM/VM.cpp @@ -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 \ No newline at end of file