From 548675eb9ff94c49464fa6b3a4c9b7d6963b19f9 Mon Sep 17 00:00:00 2001 From: Geng Chen Date: Tue, 26 Aug 2025 19:31:11 +0800 Subject: [PATCH 1/5] separate the code gen into 2 phases Signed-off-by: Geng Chen --- ets2panda/compiler/core/compilerImpl.cpp | 74 ++++++++- ets2panda/compiler/core/compilerImpl.h | 2 + ets2panda/compiler/core/emitter.cpp | 173 +++++++++++++++++++++ ets2panda/compiler/core/emitter.h | 54 +++++++ ets2panda/compiler/core/programElement.cpp | 31 ++++ ets2panda/compiler/core/programElement.h | 15 ++ ets2panda/public/public.h | 15 ++ 7 files changed, 357 insertions(+), 7 deletions(-) diff --git a/ets2panda/compiler/core/compilerImpl.cpp b/ets2panda/compiler/core/compilerImpl.cpp index 539573f68c..bb7b4387a8 100644 --- a/ets2panda/compiler/core/compilerImpl.cpp +++ b/ets2panda/compiler/core/compilerImpl.cpp @@ -63,18 +63,43 @@ void CompilerImpl::HandleContextLiterals(public_lib::Context *context) emitter->LiteralBufferIndex() += context->contextLiterals.size(); } -ark::pandasm::Program *CompilerImpl::Emit(public_lib::Context *context) +void CompilerImpl::EmitStage1(public_lib::Context *context) { - HandleContextLiterals(context); - + // 设置Stage1回调 + context->codeGenCb = context->stage1Cb; + + // 调度和执行Stage1任务 queue_.Schedule(context); + queue_.Consume(); + queue_.Wait([](CompileJob *) {}); +} - /* Main thread can also be used instead of idling */ +void CompilerImpl::EmitStage2(public_lib::Context *context) +{ + // 切换到Stage2 + context->SwitchToStage2(); + + // 调度和执行Stage2任务 + queue_.Schedule(context); queue_.Consume(); auto *emitter = context->emitter; - queue_.Wait([emitter](CompileJob *job) { emitter->AddProgramElement(job->GetProgramElement()); }); + queue_.Wait([emitter](CompileJob *job) { + emitter->AddProgramElement(job->GetProgramElement()); + }); +} - return emitter->Finalize(context->config->options->IsDumpDebugInfo(), Signatures::ETS_GLOBAL); +ark::pandasm::Program *CompilerImpl::Emit(public_lib::Context *context) +{ + HandleContextLiterals(context); + + // 执行Stage1 + EmitStage1(context); + + // 执行Stage2 + EmitStage2(context); + + // 最终生成程序 + return context->emitter->Finalize(context->config->options->IsDumpDebugInfo(), Signatures::ETS_GLOBAL); } template @@ -92,6 +117,38 @@ static public_lib::Context::CodeGenCb MakeCompileJob() }; } +// Two-stage compilation: Stage1 job - only execute GenerateStage1 +template +static public_lib::Context::CodeGenCb MakeStage1Job() +{ + return [](public_lib::Context *context, varbinder::FunctionScope *scope, + compiler::ProgramElement *programElement) -> void { + RegSpiller regSpiller; + ArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + AstCompiler astcompiler; + compiler::SetPhaseManager(context->phaseManager); + CodeGen cg(&allocator, ®Spiller, context, std::make_tuple(scope, programElement, &astcompiler)); + FunctionEmitter funcEmitter(&cg, programElement); + funcEmitter.GenerateStage1(); // Only execute Stage1 + }; +} + +// Two-stage compilation: Stage2 job - only execute GenerateStage2 +template +static public_lib::Context::CodeGenCb MakeStage2Job() +{ + return [](public_lib::Context *context, varbinder::FunctionScope *scope, + compiler::ProgramElement *programElement) -> void { + RegSpiller regSpiller; + ArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + AstCompiler astcompiler; // Create AstCompiler instance for Stage2 + compiler::SetPhaseManager(context->phaseManager); + CodeGen cg(&allocator, ®Spiller, context, std::make_tuple(scope, programElement, &astcompiler)); + FunctionEmitter funcEmitter(&cg, programElement); + funcEmitter.GenerateStage2(); // Only execute Stage2 + }; +} + static bool CheckOptionsBeforePhase(const util::Options &options, const parser::Program &program, const std::string &name) { @@ -429,7 +486,10 @@ static pandasm::Program *Compile(const CompilationUnit &unit, CompilerImpl *comp auto analyzer = Analyzer(&checker); checker.SetAnalyzer(&analyzer); context->PushAnalyzer(checker.GetAnalyzer()); - context->codeGenCb = MakeCompileJob(); + // Setup two-stage compilation callbacks + context->stage1Cb = MakeStage1Job(); + context->stage2Cb = MakeStage2Job(); + context->codeGenCb = context->stage1Cb; // Start with Stage1 context->diagnosticEngine = &unit.diagnosticEngine; context->phaseManager = &phaseManager; diff --git a/ets2panda/compiler/core/compilerImpl.h b/ets2panda/compiler/core/compilerImpl.h index 02ac0514b2..37095a3aaa 100644 --- a/ets2panda/compiler/core/compilerImpl.h +++ b/ets2panda/compiler/core/compilerImpl.h @@ -66,6 +66,8 @@ public: static std::string GetPhasesList(ScriptExtension ext); ark::pandasm::Program *Emit(public_lib::Context *context); + void EmitStage1(public_lib::Context *context); + void EmitStage2(public_lib::Context *context); CompileQueue *Queue() { diff --git a/ets2panda/compiler/core/emitter.cpp b/ets2panda/compiler/core/emitter.cpp index f6027fc99e..cb686d1846 100644 --- a/ets2panda/compiler/core/emitter.cpp +++ b/ets2panda/compiler/core/emitter.cpp @@ -132,6 +132,43 @@ void FunctionEmitter::Generate() GenFunctionAnnotations(func); } +void FunctionEmitter::GenerateStage1() +{ + // Stage1: Create function signature and collect frontend-dependent debug snapshots + GenFunctionSignature(); + + // Only collect debug information that depends on frontend components + auto debugSnapshot = std::make_unique(); + CollectInstructionDebugSnapshot(*debugSnapshot); + CollectVariableDebugSnapshot(*debugSnapshot); + + // Store the snapshot in ProgramElement + programElement_->SetDebugSnapshot(std::move(debugSnapshot)); +} + +void FunctionEmitter::GenerateStage2() +{ + // Stage2: Generate Panda instructions and all backend metadata + auto *func = programElement_->Function(); + if (func == nullptr) { + return; + } + + // Generate Panda instructions from IRNodes + GenFunctionInstructions(func); + + // Apply frontend-dependent debug snapshots + auto *debugSnapshot = programElement_->GetDebugSnapshot(); + if (debugSnapshot != nullptr) { + ApplyInstructionDebugFromSnapshot(func, *debugSnapshot); + ApplyVariableDebugFromSnapshot(func, *debugSnapshot); + } + + // Generate backend metadata directly (no snapshots needed) + GenFunctionCatchTables(func); + GenFunctionAnnotations(func); +} + util::StringView FunctionEmitter::SourceCode() const { return cg_->VarBinder()->Program()->SourceCode(); @@ -455,6 +492,14 @@ void Emitter::AddProgramElement(ProgramElement *programElement) literalBufferIndex_ = newLiteralBufferIndex; auto *function = programElement->Function(); + + // Apply debug information from snapshot if available + if (programElement->HasDebugSnapshot()) { + const auto *debugSnapshot = programElement->GetDebugSnapshot(); + FunctionEmitter::ApplyInstructionDebugFromSnapshot(function, *debugSnapshot); + FunctionEmitter::ApplyVariableDebugFromSnapshot(function, *debugSnapshot); + } + prog_->AddToFunctionTable(std::move(*function)); } @@ -549,4 +594,132 @@ pandasm::Program *Emitter::Finalize(bool dumpDebugInfo, std::string_view globalC prog_ = nullptr; return prog; } + +// Debug snapshot collection methods for Stage1 +void FunctionEmitter::CollectInstructionDebugSnapshot(FunctionDebugSnapshot &snapshot) +{ + // Collect instruction debug information from IRNodes + for (const auto &irNode : Cg()->Insns()) { + const ir::AstNode *astNode = irNode->Node(); + if (astNode != nullptr && astNode != FIRST_NODE_OF_FUNCTION) { + InstructionDebugSnapshot insDebug; + insDebug.lineNumber = astNode->Range().start.line; + insDebug.columnNumber = astNode->Range().start.index; + insDebug.wholeLine = WholeLine(astNode->Range()); + snapshot.instructionDebugInfo.push_back(insDebug); + } else if (astNode == FIRST_NODE_OF_FUNCTION) { + // Handle special case for FIRST_NODE_OF_FUNCTION + const ir::AstNode *firstStatement = Cg()->Debuginfo().FirstStatement(); + if (firstStatement != nullptr) { + InstructionDebugSnapshot insDebug; + insDebug.lineNumber = firstStatement->Range().start.line; + insDebug.columnNumber = firstStatement->Range().start.index; + insDebug.wholeLine = WholeLine(firstStatement->Range()); + snapshot.instructionDebugInfo.push_back(insDebug); + } + } + } +} + +void FunctionEmitter::CollectVariableDebugSnapshot(FunctionDebugSnapshot &snapshot) +{ + // Collect variable debug information from varbinder + auto *topScope = Cg()->TopScope(); + if (topScope == nullptr) { + return; + } + + std::function collectScopeVars = [&](const varbinder::Scope *scope) { + ScopeDebugSnapshot scopeSnapshot; + scopeSnapshot.scopeStart = 0; // Will be set during Stage2 + scopeSnapshot.scopeEnd = 0; // Will be set during Stage2 + + for (const auto &[name, var] : scope->Bindings()) { + if (var->HasFlag(varbinder::VariableFlags::LOCAL)) { + VariableDebugSnapshot varSnapshot; + varSnapshot.name = name; // 直接使用StringView + varSnapshot.signature = util::StringView(); // Empty signature + varSnapshot.signatureType = util::StringView(); // Empty signature type + varSnapshot.reg = var->AsLocalVariable()->Vreg().GetIndex(); + // start and length will be set during Stage2 + scopeSnapshot.variables.push_back(varSnapshot); + } + } + + if (!scopeSnapshot.variables.empty()) { + snapshot.scopeDebugInfo.push_back(scopeSnapshot); + } + + // Note: Child scope traversal would require AST node iteration + // For now, we collect only the current scope variables + // TODO: Implement child scope traversal through AST nodes if needed + }; + + collectScopeVars(topScope); +} + + + +// Debug snapshot application methods for Stage2 +void FunctionEmitter::ApplyInstructionDebugFromSnapshot(pandasm::Function *func, const FunctionDebugSnapshot &snapshot) +{ + // Apply instruction debug info from snapshot to pandasm function + if (func->ins.size() != snapshot.instructionDebugInfo.size()) { + return; // Size mismatch, cannot apply debug info + } + + for (size_t i = 0; i < func->ins.size(); ++i) { + const auto &insSnapshot = snapshot.instructionDebugInfo[i]; + auto &insDebug = func->ins[i].insDebug; + + insDebug.SetLineNumber(insSnapshot.lineNumber); + insDebug.SetColumnNumber(insSnapshot.columnNumber); + if (!insSnapshot.wholeLine.empty()) { + insDebug.SetWholeLine(insSnapshot.wholeLine); + } + } +} + +void FunctionEmitter::ApplyVariableDebugFromSnapshot(pandasm::Function *func, const FunctionDebugSnapshot &snapshot) +{ + // Apply variable debug info from snapshot to pandasm function + func->localVariableDebug.clear(); + + for (const auto &scopeSnapshot : snapshot.scopeDebugInfo) { + for (const auto &varSnapshot : scopeSnapshot.variables) { + pandasm::debuginfo::LocalVariable localVar; + localVar.name = std::string(varSnapshot.name); + localVar.signature = std::string(varSnapshot.signature); + localVar.signatureType = std::string(varSnapshot.signatureType); + localVar.reg = static_cast(varSnapshot.reg); + localVar.start = varSnapshot.start; + localVar.length = varSnapshot.length; + + func->localVariableDebug.emplace_back(std::move(localVar)); + } + } +} + +// Emitter file-level debug information methods +void Emitter::CollectFileDebugSnapshot(FileDebugSnapshot &snapshot) +{ + // Get source file information from the context or program + if (context_ != nullptr && context_->parserProgram != nullptr) { + auto *program = context_->parserProgram; + snapshot.sourceFile = program->SourceFile().GetPath(); + snapshot.sourceCode = program->SourceCode(); + } +} + +void Emitter::ApplyFileDebugToAllFunctions(const FileDebugSnapshot &snapshot) +{ + // Apply file-level debug information to all functions in the program + for (auto &[name, func] : prog_->functionStaticTable) { + func.sourceFile = std::string(snapshot.sourceFile); + } + for (auto &[name, func] : prog_->functionInstanceTable) { + func.sourceFile = std::string(snapshot.sourceFile); + } +} + } // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/core/emitter.h b/ets2panda/compiler/core/emitter.h index 7e2623cc38..4d91d1a9fd 100644 --- a/ets2panda/compiler/core/emitter.h +++ b/ets2panda/compiler/core/emitter.h @@ -53,6 +53,39 @@ class IRNode; class ProgramElement; class RegSpiller; +// Debug information snapshot structures for two-stage compilation +struct InstructionDebugSnapshot { + uint32_t lineNumber; + uint32_t columnNumber; + std::string wholeLine; // 保持std::string,因为需要转义处理 +}; + +struct VariableDebugSnapshot { + util::StringView name; + util::StringView signature; + util::StringView signatureType; + uint32_t reg; + uint32_t start; + uint32_t length; +}; + +struct ScopeDebugSnapshot { + uint32_t scopeStart; + uint32_t scopeEnd; + std::vector variables; +}; + +struct FunctionDebugSnapshot { + std::vector instructionDebugInfo; + std::vector scopeDebugInfo; +}; + +// File-level debug information snapshot for two-stage compilation +struct FileDebugSnapshot { + util::StringView sourceFile; + util::StringView sourceCode; +}; + class FunctionEmitter { public: explicit FunctionEmitter(const CodeGen *cg, ProgramElement *programElement) @@ -65,6 +98,10 @@ public: NO_MOVE_SEMANTIC(FunctionEmitter); void Generate(); + + // Two-stage compilation methods + void GenerateStage1(); // Generate IRNodes and collect debug snapshots + void GenerateStage2(); // Generate Panda instructions using snapshots protected: using VariablesStartsMap = std::unordered_map; @@ -84,6 +121,19 @@ protected: void GenFunctionCatchTables(ark::pandasm::Function *func); void GenVariablesDebugInfo(pandasm::Function *func); util::StringView SourceCode() const; + + // Debug snapshot collection methods for Stage1 + void CollectInstructionDebugSnapshot(FunctionDebugSnapshot &snapshot); + void CollectVariableDebugSnapshot(FunctionDebugSnapshot &snapshot); + + +public: + // Debug snapshot application methods for Stage2 + static void ApplyInstructionDebugFromSnapshot(pandasm::Function *func, const FunctionDebugSnapshot &snapshot); + static void ApplyVariableDebugFromSnapshot(pandasm::Function *func, const FunctionDebugSnapshot &snapshot); + + +protected: const CodeGen *Cg() const { @@ -111,6 +161,10 @@ public: void AddProgramElement(ProgramElement *programElement); static void DumpAsm(const pandasm::Program *prog); pandasm::Program *Finalize(bool dumpDebugInfo, std::string_view globalClass = ""); + + // File-level debug information management + void CollectFileDebugSnapshot(FileDebugSnapshot &snapshot); + void ApplyFileDebugToAllFunctions(const FileDebugSnapshot &snapshot); uint32_t &LiteralBufferIndex() { diff --git a/ets2panda/compiler/core/programElement.cpp b/ets2panda/compiler/core/programElement.cpp index 0ba4b63cc3..828d60a5dc 100644 --- a/ets2panda/compiler/core/programElement.cpp +++ b/ets2panda/compiler/core/programElement.cpp @@ -14,6 +14,7 @@ */ #include "programElement.h" +#include "emitter.h" // For FunctionDebugSnapshot #include @@ -43,6 +44,36 @@ void ProgramElement::SetFunction(pandasm::Function *func) func_ = func; } +FunctionDebugSnapshot *ProgramElement::GetDebugSnapshot() +{ + return debugSnapshot_.get(); +} + +void ProgramElement::SetDebugSnapshot(std::unique_ptr snapshot) +{ + debugSnapshot_ = std::move(snapshot); +} + +bool ProgramElement::HasDebugSnapshot() const +{ + return debugSnapshot_ != nullptr; +} + +FileDebugSnapshot *ProgramElement::GetFileDebugSnapshot() +{ + return fileDebugSnapshot_.get(); +} + +void ProgramElement::SetFileDebugSnapshot(std::unique_ptr snapshot) +{ + fileDebugSnapshot_ = std::move(snapshot); +} + +bool ProgramElement::HasFileDebugSnapshot() const +{ + return fileDebugSnapshot_ != nullptr; +} + ProgramElement::~ProgramElement() { delete func_; diff --git a/ets2panda/compiler/core/programElement.h b/ets2panda/compiler/core/programElement.h index 481f693757..1918c45e3c 100644 --- a/ets2panda/compiler/core/programElement.h +++ b/ets2panda/compiler/core/programElement.h @@ -25,6 +25,9 @@ class Function; } // namespace ark::pandasm namespace ark::es2panda::compiler { +struct FunctionDebugSnapshot; // Forward declaration +struct FileDebugSnapshot; // Forward declaration + class ProgramElement { public: explicit ProgramElement() = default; @@ -37,12 +40,24 @@ public: std::vector &BuffStorage(); pandasm::Function *Function(); void SetFunction(pandasm::Function *func); + + // Debug snapshot methods for two-stage compilation + FunctionDebugSnapshot *GetDebugSnapshot(); + void SetDebugSnapshot(std::unique_ptr snapshot); + bool HasDebugSnapshot() const; + + // File-level debug snapshot methods + FileDebugSnapshot *GetFileDebugSnapshot(); + void SetFileDebugSnapshot(std::unique_ptr snapshot); + bool HasFileDebugSnapshot() const; private: std::set strings_; std::vector literalBufferIns_; std::vector buffStorage_; pandasm::Function *func_ {}; + std::unique_ptr debugSnapshot_; // Debug snapshot for two-stage compilation + std::unique_ptr fileDebugSnapshot_; // File-level debug snapshot for two-stage compilation }; } // namespace ark::es2panda::compiler #endif diff --git a/ets2panda/public/public.h b/ets2panda/public/public.h index 72c7553a18..7ece9db6b2 100644 --- a/ets2panda/public/public.h +++ b/ets2panda/public/public.h @@ -215,7 +215,22 @@ struct Context { std::vector const *plugins = nullptr; std::vector contextLiterals; CodeGenCb codeGenCb; + // Two-stage compilation support + CodeGenCb stage1Cb; + CodeGenCb stage2Cb; compiler::PhaseManager *phaseManager = nullptr; + + // Switch to Stage2 and cleanup frontend components + void SwitchToStage2() { + codeGenCb = stage2Cb; + // Clear frontend components to save memory + //ClearCheckers(); + //ClearAnalyzers(); + // Clear parser and AST to free memory + //parser = nullptr; + // Note: parserProgram contains AST, but we keep it for now + // as Stage2 might still need some AST information + } parser::Program *parserProgram = nullptr; parser::ParserImpl *parser = nullptr; -- Gitee From 96bdf2dd0db664547b567085ff7276fbc37a21bf Mon Sep 17 00:00:00 2001 From: Geng Chen Date: Sat, 30 Aug 2025 10:17:46 +0800 Subject: [PATCH 2/5] move insns_ and catchlist_ to programelement Signed-off-by: Geng Chen --- ets2panda/compiler/core/ETSGen.h | 1 + ets2panda/compiler/core/codeGen.cpp | 19 +++++----- ets2panda/compiler/core/codeGen.h | 11 +++--- ets2panda/compiler/core/programElement.cpp | 40 ++++++++++++++++++++++ ets2panda/compiler/core/programElement.h | 32 +++++++++++++---- ets2panda/compiler/core/regScope.cpp | 10 +++--- 6 files changed, 86 insertions(+), 27 deletions(-) diff --git a/ets2panda/compiler/core/ETSGen.h b/ets2panda/compiler/core/ETSGen.h index 4b306cccb2..4f9f580473 100644 --- a/ets2panda/compiler/core/ETSGen.h +++ b/ets2panda/compiler/core/ETSGen.h @@ -23,6 +23,7 @@ #include "checker/ETSchecker.h" #include "ir/expressions/identifier.h" #include "util/helpers.h" +#include "generated/isa.h" #include namespace ark::es2panda::compiler { diff --git a/ets2panda/compiler/core/codeGen.cpp b/ets2panda/compiler/core/codeGen.cpp index fd01a1c9f2..dbd93430ff 100644 --- a/ets2panda/compiler/core/codeGen.cpp +++ b/ets2panda/compiler/core/codeGen.cpp @@ -32,9 +32,9 @@ ArenaAllocator *CodeGen::Allocator() const noexcept return allocator_; } -const ArenaVector &CodeGen::CatchList() const noexcept +const std::vector &CodeGen::CatchList() const noexcept { - return catchList_; + return programElement_->CatchList(); } const varbinder::FunctionScope *CodeGen::TopScope() const noexcept @@ -52,14 +52,14 @@ const ir::AstNode *CodeGen::RootNode() const noexcept return rootNode_; } -ArenaVector &CodeGen::Insns() noexcept +std::vector &CodeGen::Insns() noexcept { - return insns_; + return programElement_->Insns(); } -const ArenaVector &CodeGen::Insns() const noexcept +const std::vector &CodeGen::Insns() const noexcept { - return insns_; + return programElement_->Insns(); } VReg CodeGen::NextReg() const noexcept @@ -272,20 +272,21 @@ std::uint32_t CodeGen::TryDepth() const CatchTable *CodeGen::CreateCatchTable(const util::StringView exceptionType) { auto *catchTable = allocator_->New(this, TryDepth(), exceptionType); - catchList_.push_back(catchTable); + programElement_->CatchList().push_back(catchTable); return catchTable; } CatchTable *CodeGen::CreateCatchTable(const LabelPair tryLabelPair, const util::StringView exceptionType) { auto *catchTable = allocator_->New(this, TryDepth(), tryLabelPair, exceptionType); - catchList_.push_back(catchTable); + programElement_->CatchList().push_back(catchTable); return catchTable; } void CodeGen::SortCatchTables() { - std::stable_sort(catchList_.begin(), catchList_.end(), + auto &catchList = programElement_->CatchList(); + std::stable_sort(catchList.begin(), catchList.end(), [](const CatchTable *a, const CatchTable *b) { return b->Depth() < a->Depth(); }); } diff --git a/ets2panda/compiler/core/codeGen.h b/ets2panda/compiler/core/codeGen.h index 8fbeeb0106..6265c53a17 100644 --- a/ets2panda/compiler/core/codeGen.h +++ b/ets2panda/compiler/core/codeGen.h @@ -78,8 +78,6 @@ public: topScope_(std::get(toCompile)), scope_(topScope_), rootNode_(scope_->Node()), - insns_(allocator_->Adapter()), - catchList_(allocator_->Adapter()), typeMap_(allocator_->Adapter()), programElement_(std::get(toCompile)), sa_(this), @@ -96,13 +94,13 @@ public: [[nodiscard]] virtual IRNode *AllocMov(const ir::AstNode *node, OutVReg vd, VReg vs) = 0; [[nodiscard]] ArenaAllocator *Allocator() const noexcept; - [[nodiscard]] const ArenaVector &CatchList() const noexcept; + [[nodiscard]] const std::vector &CatchList() const noexcept; [[nodiscard]] const varbinder::FunctionScope *TopScope() const noexcept; [[nodiscard]] const varbinder::Scope *Scope() const noexcept; [[nodiscard]] const ir::AstNode *RootNode() const noexcept; - [[nodiscard]] ArenaVector &Insns() noexcept; - [[nodiscard]] const ArenaVector &Insns() const noexcept; + [[nodiscard]] std::vector &Insns() noexcept; + [[nodiscard]] const std::vector &Insns() const noexcept; [[nodiscard]] VReg AllocReg(); [[nodiscard]] VReg AllocRegWithType(const checker::Type *type); @@ -173,8 +171,7 @@ private: varbinder::FunctionScope *topScope_ {}; varbinder::Scope *scope_ {}; const ir::AstNode *rootNode_ {}; - ArenaVector insns_; - ArenaVector catchList_; + // insns_ and catchList_ moved to ProgramElement TypeMap typeMap_; ProgramElement *programElement_ {}; DynamicContext *dynamicContext_ {}; diff --git a/ets2panda/compiler/core/programElement.cpp b/ets2panda/compiler/core/programElement.cpp index 828d60a5dc..1a9b36af03 100644 --- a/ets2panda/compiler/core/programElement.cpp +++ b/ets2panda/compiler/core/programElement.cpp @@ -15,10 +15,30 @@ #include "programElement.h" #include "emitter.h" // For FunctionDebugSnapshot +#include "compiler/base/catchTable.h" +#include "ir/irnode.h" #include +#include +#include +#include + +// Forward declarations +namespace ark::pandasm { +class Ins; +class Function; +} namespace ark::es2panda::compiler { +class IRNode; +class CatchTable; +struct FunctionDebugSnapshot; +struct FileDebugSnapshot; + +ProgramElement::ProgramElement() +{ +} + std::set &ProgramElement::Strings() { return strings_; @@ -44,6 +64,26 @@ void ProgramElement::SetFunction(pandasm::Function *func) func_ = func; } +std::vector &ProgramElement::Insns() +{ + return insns_; +} + +const std::vector &ProgramElement::Insns() const +{ + return insns_; +} + +std::vector &ProgramElement::CatchList() +{ + return catchList_; +} + +const std::vector &ProgramElement::CatchList() const +{ + return catchList_; +} + FunctionDebugSnapshot *ProgramElement::GetDebugSnapshot() { return debugSnapshot_.get(); diff --git a/ets2panda/compiler/core/programElement.h b/ets2panda/compiler/core/programElement.h index 1918c45e3c..24cc5a25f1 100644 --- a/ets2panda/compiler/core/programElement.h +++ b/ets2panda/compiler/core/programElement.h @@ -16,8 +16,13 @@ #ifndef ES2PANDA_COMPILER_CORE_PROGRAM_ELEMENT_H #define ES2PANDA_COMPILER_CORE_PROGRAM_ELEMENT_H -#include "util/es2pandaMacros.h" #include "compiler/base/literals.h" +#include "util/es2pandaMacros.h" + +#include +#include +#include +#include namespace ark::pandasm { class Ins; @@ -25,12 +30,15 @@ class Function; } // namespace ark::pandasm namespace ark::es2panda::compiler { -struct FunctionDebugSnapshot; // Forward declaration -struct FileDebugSnapshot; // Forward declaration +class IRNode; +class CatchTable; +struct FunctionDebugSnapshot; +struct FileDebugSnapshot; + class ProgramElement { public: - explicit ProgramElement() = default; + explicit ProgramElement(); ~ProgramElement(); NO_COPY_SEMANTIC(ProgramElement); NO_MOVE_SEMANTIC(ProgramElement); @@ -41,6 +49,14 @@ public: pandasm::Function *Function(); void SetFunction(pandasm::Function *func); + // Instruction and catch table access methods + std::vector &Insns(); + const std::vector &Insns() const; + std::vector &CatchList(); + const std::vector &CatchList() const; + + + // Debug snapshot methods for two-stage compilation FunctionDebugSnapshot *GetDebugSnapshot(); void SetDebugSnapshot(std::unique_ptr snapshot); @@ -56,8 +72,12 @@ private: std::vector literalBufferIns_; std::vector buffStorage_; pandasm::Function *func_ {}; - std::unique_ptr debugSnapshot_; // Debug snapshot for two-stage compilation - std::unique_ptr fileDebugSnapshot_; // File-level debug snapshot for two-stage compilation + std::unique_ptr debugSnapshot_; + std::unique_ptr fileDebugSnapshot_; + + // Moved from CodeGen + std::vector insns_; + std::vector catchList_; }; } // namespace ark::es2panda::compiler #endif diff --git a/ets2panda/compiler/core/regScope.cpp b/ets2panda/compiler/core/regScope.cpp index f0ef27d3b8..9a77d60453 100644 --- a/ets2panda/compiler/core/regScope.cpp +++ b/ets2panda/compiler/core/regScope.cpp @@ -40,7 +40,7 @@ void RegScope::DebuggerCloseScope() return; } - cg_->scope_->SetScopeEnd(cg_->insns_.back()); + cg_->scope_->SetScopeEnd(cg_->Insns().back()); } // LocalRegScope @@ -59,8 +59,8 @@ LocalRegScope::LocalRegScope(CodeGen *cg, varbinder::Scope *scope) : RegScope(cg } } - if (cg_->IsDebug() && !cg_->insns_.empty()) { - cg_->scope_->SetScopeStart(cg_->insns_.back()); + if (cg_->IsDebug() && !cg_->Insns().empty()) { + cg_->scope_->SetScopeStart(cg_->Insns().back()); cg_->debugInfo_.VariableDebugInfo().push_back(cg_->scope_); } } @@ -155,8 +155,8 @@ FunctionRegScope::FunctionRegScope(PandaGen *pg) : RegScope(pg), envScope_(pg->A FunctionRegScope::~FunctionRegScope() { - if (cg_->IsDebug() && !cg_->insns_.empty()) { - cg_->topScope_->SetScopeStart(cg_->insns_.front()); + if (cg_->IsDebug() && !cg_->Insns().empty()) { + cg_->topScope_->SetScopeStart(cg_->Insns().front()); DebuggerCloseScope(); } -- Gitee From df51c43ef881313b58322f308d6514154117c7f7 Mon Sep 17 00:00:00 2001 From: Geng Chen Date: Wed, 3 Sep 2025 15:33:47 +0800 Subject: [PATCH 3/5] seperate the codegen into 2 stages Signed-off-by: Geng Chen --- ets2panda/compiler/core/compilerImpl.cpp | 240 +++++++++++++++++++++-- ets2panda/compiler/core/compilerImpl.h | 7 + ets2panda/compiler/core/emitter.cpp | 39 +++- ets2panda/compiler/core/emitter.h | 11 ++ 4 files changed, 278 insertions(+), 19 deletions(-) diff --git a/ets2panda/compiler/core/compilerImpl.cpp b/ets2panda/compiler/core/compilerImpl.cpp index bb7b4387a8..18a32e1740 100644 --- a/ets2panda/compiler/core/compilerImpl.cpp +++ b/ets2panda/compiler/core/compilerImpl.cpp @@ -28,6 +28,11 @@ #include "compiler/core/pandagen.h" #include "compiler/core/ETSCompiler.h" #include "compiler/core/ETSGen.h" +#include "compiler/core/programElement.h" +#include "compiler/core/emitter.h" +#include +#include +#include #include "compiler/core/JSCompiler.h" #include "compiler/core/JSemitter.h" #include "compiler/core/ETSemitter.h" @@ -44,6 +49,13 @@ #include "public/public.h" #include "util/ustring.h" #include "util/perfMetrics.h" +#include "assembler/annotation.h" +#include "assembler/assembly-function.h" +#include "assembler/assembly-program.h" +#include "compiler/base/catchTable.h" + +// Forward declarations + #include "varbinder/JSBinder.h" #include "varbinder/ASBinder.h" #include "varbinder/TSBinder.h" @@ -51,6 +63,11 @@ namespace ark::es2panda::compiler { + + +// Use full namespace paths to avoid conflicts + + void CompilerImpl::HandleContextLiterals(public_lib::Context *context) { auto *emitter = context->emitter; @@ -71,21 +88,207 @@ void CompilerImpl::EmitStage1(public_lib::Context *context) // 调度和执行Stage1任务 queue_.Schedule(context); queue_.Consume(); - queue_.Wait([](CompileJob *) {}); + //queue_.Wait([](CompileJob *) {}); } void CompilerImpl::EmitStage2(public_lib::Context *context) { - // 切换到Stage2 - context->SwitchToStage2(); + (void)context; + queue_.Wait([](CompileJob *) {}); +} + +void CompilerImpl::ProcessCollectedProgramElements(public_lib::Context *context) +{ + // 获取在Stage1中收集到的所有ProgramElement + const auto& collectedElements = context->emitter->GetCollectedProgramElements(); - // 调度和执行Stage2任务 - queue_.Schedule(context); - queue_.Consume(); - auto *emitter = context->emitter; - queue_.Wait([emitter](CompileJob *job) { - emitter->AddProgramElement(job->GetProgramElement()); - }); + // 遍历所有收集到的ProgramElement,实现类似Gen*函数的功能 + for (ProgramElement* element : collectedElements) { + if (element == nullptr || element->Function() == nullptr) { + continue; + } + + auto *func = element->Function(); + + // 1. 处理指令生成 - 类似GenFunctionInstructions + ProcessProgramElementInstructions(element, func); + + // 2. 处理Catch表生成 - 类似GenFunctionCatchTables + //ProcessProgramElementCatchTables(element, func); + + // 3. 处理函数注解生成 - 类似GenFunctionAnnotations + //ProcessProgramElementAnnotations(element, func); + + // 4. 处理调试信息 - 类似GenVariablesDebugInfo和GenSourceFileDebugInfo + ProcessProgramElementDebugInfo(element, func); + + // 5. 添加ProgramElement到emitter - 类似emitter->AddProgramElement(job->GetProgramElement()) + context->emitter->AddProgramElement(element); + } + + // 处理完成后清理收集的ProgramElement列表 + //context->emitter->ClearCollectedProgramElements(); +} + +void CompilerImpl::ProcessProgramElementInstructions(ProgramElement *element, pandasm::Function *func) +{ + // 类似GenFunctionInstructions的功能 + // 检查debugsnapshot中是否有totalregs信息,如果没有则设置默认值 + uint32_t totalRegs = 16; // 默认值 + + if (element->HasDebugSnapshot()) { + const auto *debugSnapshot = element->GetDebugSnapshot(); + totalRegs = debugSnapshot->totalRegs; + } + + // 获取IRNode指令集合 + const auto &insns = element->Insns(); + + // 预分配指令空间 + func->ins.reserve(insns.size()); + + // 遍历IRNode并生成panda指令,参考GenFunctionInstructions实现 + for (const auto *ins : insns) { + if (ins == nullptr) { + continue; + } + + // 创建新的panda指令 + auto &pandaIns = func->ins.emplace_back(); + + // 调用IRNode的Transform方法生成panda指令 + // 这里传入element作为ProgramElement参数,totalRegs作为寄存器总数 + ins->Transform(&pandaIns, element, totalRegs); + + // TODO: 生成指令调试信息 + // 这里可以添加类似GenInstructionDebugInfo的功能 + // 但由于我们在Stage2阶段,可能需要从debugSnapshot中恢复调试信息 + } +} + +void CompilerImpl::ProcessProgramElementCatchTables(ProgramElement *element, pandasm::Function *func) +{ + // 类似GenFunctionCatchTables的功能 + // 遍历ProgramElement的CatchList并转换为pandasm::Function的catchBlocks + + if (element == nullptr || func == nullptr) { + return; + } + + const auto &catchList = element->CatchList(); + if (catchList.empty()) { + return; + } + + // 清空现有的catch blocks + func->catchBlocks.clear(); + + // 遍历每个CatchTable并转换为pandasm::CatchBlock + for (const auto *catchTable : catchList) { + if (catchTable == nullptr) { + continue; + } + + pandasm::Function::CatchBlock catchBlock; + + // 设置异常类型 + catchBlock.exceptionRecord = catchTable->Exception(); + + // 设置try块的开始和结束标签 + const auto &labelSet = catchTable->LabelSet(); + if (labelSet.TryBegin() != nullptr) { + catchBlock.tryBeginLabel = labelSet.TryBegin()->Id(); + } + if (labelSet.TryEnd() != nullptr) { + catchBlock.tryEndLabel = labelSet.TryEnd()->Id(); + } + + // 设置catch块的开始标签 + if (labelSet.CatchBegin() != nullptr) { + catchBlock.catchBeginLabel = labelSet.CatchBegin()->Id(); + } + + // 设置catch块的结束标签(可选) + if (labelSet.CatchEnd() != nullptr) { + catchBlock.catchEndLabel = labelSet.CatchEnd()->Id(); + } + + // 添加到函数的catch blocks中 + func->catchBlocks.emplace_back(std::move(catchBlock)); + } +} + +void CompilerImpl::ProcessProgramElementAnnotations(ProgramElement *element, pandasm::Function *func) +{ + (void)element; + (void)func; +} + +void CompilerImpl::ProcessProgramElementDebugInfo(ProgramElement *element, pandasm::Function *func) +{ + // 类似GenVariablesDebugInfo和GenSourceFileDebugInfo的功能 + // 应用从debugsnapshot中收集的调试信息 + + if (element == nullptr || func == nullptr) { + return; + } + + // 获取调试快照 + const auto *debugSnapshot = element->GetDebugSnapshot(); + if (debugSnapshot == nullptr) { + return; + } + + // 1. 应用变量调试信息 (类似GenVariablesDebugInfo) + // 清空现有的本地变量调试信息 + func->localVariableDebug.clear(); + + // 从调试快照中恢复变量调试信息 + for (const auto &scopeSnapshot : debugSnapshot->scopeDebugInfo) { + for (const auto &varSnapshot : scopeSnapshot.variables) { + pandasm::debuginfo::LocalVariable localVar; + localVar.name = std::string(varSnapshot.name); + localVar.signature = std::string(varSnapshot.signature); + localVar.signatureType = std::string(varSnapshot.signatureType); + localVar.reg = static_cast(varSnapshot.reg); + localVar.start = varSnapshot.start; + localVar.length = varSnapshot.length; + + func->localVariableDebug.emplace_back(std::move(localVar)); + } + } + + // 2. 应用源文件调试信息 (类似GenSourceFileDebugInfo) + // 设置源文件路径 + if (element->HasFileDebugSnapshot()) { + const auto *fileSnapshot = element->GetFileDebugSnapshot(); + if (fileSnapshot != nullptr && !fileSnapshot->sourceFile.Empty()) { + func->sourceFile = std::string(fileSnapshot->sourceFile); + + // 如果是初始化方法,设置源代码内容 + if (func->name.find("") != std::string::npos || + func->name.find("_$init$_") != std::string::npos) { + if (!fileSnapshot->sourceCode.Empty()) { + func->sourceCode = std::string(fileSnapshot->sourceCode); + } + } + } + } + + // 3. 应用指令调试信息 + // 确保指令数量匹配 + if (func->ins.size() == debugSnapshot->instructionDebugInfo.size()) { + for (size_t i = 0; i < func->ins.size(); ++i) { + const auto &insSnapshot = debugSnapshot->instructionDebugInfo[i]; + auto &insDebug = func->ins[i].insDebug; + + insDebug.SetLineNumber(insSnapshot.lineNumber + 1); // 行号从1开始 + insDebug.SetColumnNumber(insSnapshot.columnNumber); + if (!insSnapshot.wholeLine.empty()) { + insDebug.SetWholeLine(insSnapshot.wholeLine); + } + } + } } ark::pandasm::Program *CompilerImpl::Emit(public_lib::Context *context) @@ -95,6 +298,9 @@ ark::pandasm::Program *CompilerImpl::Emit(public_lib::Context *context) // 执行Stage1 EmitStage1(context); + // 在Stage1和Stage2之间处理收集到的ProgramElement + ProcessCollectedProgramElements(context); + // 执行Stage2 EmitStage2(context); @@ -127,9 +333,12 @@ static public_lib::Context::CodeGenCb MakeStage1Job() ArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); AstCompiler astcompiler; compiler::SetPhaseManager(context->phaseManager); - CodeGen cg(&allocator, ®Spiller, context, std::make_tuple(scope, programElement, &astcompiler)); + CodeGen cg(context->allocator, ®Spiller, context, std::make_tuple(scope, programElement, &astcompiler)); FunctionEmitter funcEmitter(&cg, programElement); funcEmitter.GenerateStage1(); // Only execute Stage1 + + // Collect ProgramElement in Emitter for later processing + context->emitter->CollectProgramElement(programElement); }; } @@ -137,16 +346,21 @@ static public_lib::Context::CodeGenCb MakeStage1Job() template static public_lib::Context::CodeGenCb MakeStage2Job() { + return [](public_lib::Context *context, varbinder::FunctionScope *scope, compiler::ProgramElement *programElement) -> void { - RegSpiller regSpiller; + (void)context; + (void)scope; + (void)programElement; + /* RegSpiller regSpiller; ArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); AstCompiler astcompiler; // Create AstCompiler instance for Stage2 compiler::SetPhaseManager(context->phaseManager); CodeGen cg(&allocator, ®Spiller, context, std::make_tuple(scope, programElement, &astcompiler)); FunctionEmitter funcEmitter(&cg, programElement); - funcEmitter.GenerateStage2(); // Only execute Stage2 + funcEmitter.GenerateStage2(); // Only execute Stage2 */ }; + } static bool CheckOptionsBeforePhase(const util::Options &options, const parser::Program &program, diff --git a/ets2panda/compiler/core/compilerImpl.h b/ets2panda/compiler/core/compilerImpl.h index 37095a3aaa..e74d9cb76a 100644 --- a/ets2panda/compiler/core/compilerImpl.h +++ b/ets2panda/compiler/core/compilerImpl.h @@ -68,6 +68,13 @@ public: ark::pandasm::Program *Emit(public_lib::Context *context); void EmitStage1(public_lib::Context *context); void EmitStage2(public_lib::Context *context); + void ProcessCollectedProgramElements(public_lib::Context *context); + + // Helper methods for processing ProgramElement components + void ProcessProgramElementInstructions(ProgramElement *element, pandasm::Function *func); + void ProcessProgramElementCatchTables(ProgramElement *element, pandasm::Function *func); + void ProcessProgramElementAnnotations(ProgramElement *element, pandasm::Function *func); + void ProcessProgramElementDebugInfo(ProgramElement *element, pandasm::Function *func); CompileQueue *Queue() { diff --git a/ets2panda/compiler/core/emitter.cpp b/ets2panda/compiler/core/emitter.cpp index cb686d1846..e1f4b2b54a 100644 --- a/ets2panda/compiler/core/emitter.cpp +++ b/ets2panda/compiler/core/emitter.cpp @@ -135,8 +135,11 @@ void FunctionEmitter::Generate() void FunctionEmitter::GenerateStage1() { // Stage1: Create function signature and collect frontend-dependent debug snapshots - GenFunctionSignature(); - + auto *func = GenFunctionSignature(); + GenFunctionAnnotations(func); + + GenFunctionCatchTables(func); + // Only collect debug information that depends on frontend components auto debugSnapshot = std::make_unique(); CollectInstructionDebugSnapshot(*debugSnapshot); @@ -146,7 +149,7 @@ void FunctionEmitter::GenerateStage1() programElement_->SetDebugSnapshot(std::move(debugSnapshot)); } -void FunctionEmitter::GenerateStage2() +/* void FunctionEmitter::GenerateStage2() { // Stage2: Generate Panda instructions and all backend metadata auto *func = programElement_->Function(); @@ -168,7 +171,7 @@ void FunctionEmitter::GenerateStage2() GenFunctionCatchTables(func); GenFunctionAnnotations(func); } - + */ util::StringView FunctionEmitter::SourceCode() const { return cg_->VarBinder()->Program()->SourceCode(); @@ -598,6 +601,12 @@ pandasm::Program *Emitter::Finalize(bool dumpDebugInfo, std::string_view globalC // Debug snapshot collection methods for Stage1 void FunctionEmitter::CollectInstructionDebugSnapshot(FunctionDebugSnapshot &snapshot) { + // Collect totalRegs information for instruction generation + snapshot.totalRegs = Cg()->TotalRegsNum(); + + // Collect icSize information for function annotation generation + snapshot.icSize = Cg()->IcSize(); + // Collect instruction debug information from IRNodes for (const auto &irNode : Cg()->Insns()) { const ir::AstNode *astNode = irNode->Node(); @@ -638,8 +647,8 @@ void FunctionEmitter::CollectVariableDebugSnapshot(FunctionDebugSnapshot &snapsh if (var->HasFlag(varbinder::VariableFlags::LOCAL)) { VariableDebugSnapshot varSnapshot; varSnapshot.name = name; // 直接使用StringView - varSnapshot.signature = util::StringView(); // Empty signature - varSnapshot.signatureType = util::StringView(); // Empty signature type + varSnapshot.signature = util::StringView("any"); + varSnapshot.signatureType = util::StringView("any"); varSnapshot.reg = var->AsLocalVariable()->Vreg().GetIndex(); // start and length will be set during Stage2 scopeSnapshot.variables.push_back(varSnapshot); @@ -722,4 +731,22 @@ void Emitter::ApplyFileDebugToAllFunctions(const FileDebugSnapshot &snapshot) } } +// ProgramElement collection functionality implementation +void Emitter::CollectProgramElement(ProgramElement *programElement) +{ + std::lock_guard lock(collectionMutex_); + collectedProgramElements_.push_back(programElement); +} + +const std::vector& Emitter::GetCollectedProgramElements() const +{ + return collectedProgramElements_; +} + +void Emitter::ClearCollectedProgramElements() +{ + std::lock_guard lock(collectionMutex_); + collectedProgramElements_.clear(); +} + } // namespace ark::es2panda::compiler diff --git a/ets2panda/compiler/core/emitter.h b/ets2panda/compiler/core/emitter.h index 4d91d1a9fd..f9255699a3 100644 --- a/ets2panda/compiler/core/emitter.h +++ b/ets2panda/compiler/core/emitter.h @@ -78,6 +78,8 @@ struct ScopeDebugSnapshot { struct FunctionDebugSnapshot { std::vector instructionDebugInfo; std::vector scopeDebugInfo; + uint32_t totalRegs {0}; // Total register count for instruction generation + uint32_t icSize {0}; // IC size for function annotation generation }; // File-level debug information snapshot for two-stage compilation @@ -162,6 +164,11 @@ public: static void DumpAsm(const pandasm::Program *prog); pandasm::Program *Finalize(bool dumpDebugInfo, std::string_view globalClass = ""); + // ProgramElement collection functionality for stage1 + void CollectProgramElement(ProgramElement *programElement); + const std::vector& GetCollectedProgramElements() const; + void ClearCollectedProgramElements(); + // File-level debug information management void CollectFileDebugSnapshot(FileDebugSnapshot &snapshot); void ApplyFileDebugToAllFunctions(const FileDebugSnapshot &snapshot); @@ -190,6 +197,10 @@ private: pandasm::Program *prog_; const public_lib::Context *context_; uint32_t literalBufferIndex_ {}; + + // Collection for ProgramElements from stage1 + std::vector collectedProgramElements_; + std::mutex collectionMutex_; }; } // namespace ark::es2panda::compiler -- Gitee From fd0a3101471254015f88cedcca226fe67c833cdd Mon Sep 17 00:00:00 2001 From: Geng Chen Date: Wed, 3 Sep 2025 17:26:24 +0800 Subject: [PATCH 4/5] seperate the allocator of IRNode and other things in context Signed-off-by: Geng Chen --- ets2panda/compiler/core/compilerImpl.cpp | 6 ++++-- ets2panda/es2panda.cpp | 4 ++++ ets2panda/public/public.h | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ets2panda/compiler/core/compilerImpl.cpp b/ets2panda/compiler/core/compilerImpl.cpp index 18a32e1740..1dd2150328 100644 --- a/ets2panda/compiler/core/compilerImpl.cpp +++ b/ets2panda/compiler/core/compilerImpl.cpp @@ -298,6 +298,9 @@ ark::pandasm::Program *CompilerImpl::Emit(public_lib::Context *context) // 执行Stage1 EmitStage1(context); + // 释放context->allocator中的所有内容 + context->allocator->Resize(0); + // 在Stage1和Stage2之间处理收集到的ProgramElement ProcessCollectedProgramElements(context); @@ -330,10 +333,9 @@ static public_lib::Context::CodeGenCb MakeStage1Job() return [](public_lib::Context *context, varbinder::FunctionScope *scope, compiler::ProgramElement *programElement) -> void { RegSpiller regSpiller; - ArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); AstCompiler astcompiler; compiler::SetPhaseManager(context->phaseManager); - CodeGen cg(context->allocator, ®Spiller, context, std::make_tuple(scope, programElement, &astcompiler)); + CodeGen cg(context->IRNodeAllocator, ®Spiller, context, std::make_tuple(scope, programElement, &astcompiler)); FunctionEmitter funcEmitter(&cg, programElement); funcEmitter.GenerateStage1(); // Only execute Stage1 diff --git a/ets2panda/es2panda.cpp b/ets2panda/es2panda.cpp index 52aaeb6f0c..d58950bb49 100644 --- a/ets2panda/es2panda.cpp +++ b/ets2panda/es2panda.cpp @@ -88,7 +88,9 @@ pandasm::Program *Compiler::Compile(const SourceFile &input, const util::Options { public_lib::Context context; ThreadSafeArenaAllocator allocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + ThreadSafeArenaAllocator IRNodeAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); context.allocator = &allocator; + context.IRNodeAllocator = &IRNodeAllocator; context.compilingState = public_lib::CompilingState::SINGLE_COMPILING; try { @@ -106,7 +108,9 @@ unsigned int Compiler::CompileM(std::vector &inputs, util::Options & public_lib::Context context; context.transitionMemory = new public_lib::TransitionMemory(new ThreadSafeArenaAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true)); + ThreadSafeArenaAllocator IRNodeAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); context.allocator = context.transitionMemory->PermanentAllocator(); + context.IRNodeAllocator = &IRNodeAllocator; context.compilingState = public_lib::CompilingState::MULTI_COMPILING_INIT; unsigned int overallRes = 0; diff --git a/ets2panda/public/public.h b/ets2panda/public/public.h index 7ece9db6b2..246bdecec2 100644 --- a/ets2panda/public/public.h +++ b/ets2panda/public/public.h @@ -211,6 +211,7 @@ struct Context { std::string input; SourceFile const *sourceFile = nullptr; ThreadSafeArenaAllocator *allocator = nullptr; + ThreadSafeArenaAllocator *IRNodeAllocator = nullptr; compiler::CompileQueue *queue = nullptr; std::vector const *plugins = nullptr; std::vector contextLiterals; -- Gitee From 55ac017b13ce8cb4855a1e009c62a3266852596b Mon Sep 17 00:00:00 2001 From: Geng Chen Date: Thu, 4 Sep 2025 17:30:54 +0800 Subject: [PATCH 5/5] use a seperate allocator for ast node Signed-off-by: Geng Chen --- ets2panda/compiler/core/compilerImpl.cpp | 11 ++++++++--- ets2panda/compiler/core/emitter.cpp | 2 +- ets2panda/compiler/core/emitter.h | 2 +- ets2panda/lexer/lexer.cpp | 3 ++- ets2panda/parser/parserImpl.cpp | 9 +++++++++ ets2panda/parser/parserImpl.h | 5 +---- ets2panda/public/public.h | 9 ++++++++- 7 files changed, 30 insertions(+), 11 deletions(-) diff --git a/ets2panda/compiler/core/compilerImpl.cpp b/ets2panda/compiler/core/compilerImpl.cpp index 1dd2150328..15d2e29faa 100644 --- a/ets2panda/compiler/core/compilerImpl.cpp +++ b/ets2panda/compiler/core/compilerImpl.cpp @@ -247,7 +247,7 @@ void CompilerImpl::ProcessProgramElementDebugInfo(ProgramElement *element, panda for (const auto &scopeSnapshot : debugSnapshot->scopeDebugInfo) { for (const auto &varSnapshot : scopeSnapshot.variables) { pandasm::debuginfo::LocalVariable localVar; - localVar.name = std::string(varSnapshot.name); + localVar.name = varSnapshot.name; localVar.signature = std::string(varSnapshot.signature); localVar.signatureType = std::string(varSnapshot.signatureType); localVar.reg = static_cast(varSnapshot.reg); @@ -298,8 +298,9 @@ ark::pandasm::Program *CompilerImpl::Emit(public_lib::Context *context) // 执行Stage1 EmitStage1(context); - // 释放context->allocator中的所有内容 - context->allocator->Resize(0); + // 在两个阶段之间释放AST分配器(若存在),避免释放通用allocator导致悬空引用 + + context->astAllocator->Resize(0); // 在Stage1和Stage2之间处理收集到的ProgramElement ProcessCollectedProgramElements(context); @@ -688,6 +689,10 @@ static pandasm::Program *Compile(const CompilationUnit &unit, CompilerImpl *comp context->sourceFile = &unit.input; context->queue = compilerImpl->Queue(); context->plugins = &compilerImpl->Plugins(); + // Ensure dedicated AST allocator exists for parsing/AST building + if (context->astAllocator == nullptr) { + context->astAllocator = new ThreadSafeArenaAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true); + } auto program = parser::Program::NewProgram( context->allocator, context->compilingState == public_lib::CompilingState::MULTI_COMPILING_FOLLOW ? context->transitionMemory->VarBinder() diff --git a/ets2panda/compiler/core/emitter.cpp b/ets2panda/compiler/core/emitter.cpp index e1f4b2b54a..022d81c819 100644 --- a/ets2panda/compiler/core/emitter.cpp +++ b/ets2panda/compiler/core/emitter.cpp @@ -646,7 +646,7 @@ void FunctionEmitter::CollectVariableDebugSnapshot(FunctionDebugSnapshot &snapsh for (const auto &[name, var] : scope->Bindings()) { if (var->HasFlag(varbinder::VariableFlags::LOCAL)) { VariableDebugSnapshot varSnapshot; - varSnapshot.name = name; // 直接使用StringView + varSnapshot.name = std::string(name); varSnapshot.signature = util::StringView("any"); varSnapshot.signatureType = util::StringView("any"); varSnapshot.reg = var->AsLocalVariable()->Vreg().GetIndex(); diff --git a/ets2panda/compiler/core/emitter.h b/ets2panda/compiler/core/emitter.h index f9255699a3..67374d4516 100644 --- a/ets2panda/compiler/core/emitter.h +++ b/ets2panda/compiler/core/emitter.h @@ -61,7 +61,7 @@ struct InstructionDebugSnapshot { }; struct VariableDebugSnapshot { - util::StringView name; + std::string name; util::StringView signature; util::StringView signatureType; uint32_t reg; diff --git a/ets2panda/lexer/lexer.cpp b/ets2panda/lexer/lexer.cpp index 326dcaed3c..37862e4b96 100644 --- a/ets2panda/lexer/lexer.cpp +++ b/ets2panda/lexer/lexer.cpp @@ -16,12 +16,13 @@ #include "lexer.h" #include "generated/keywords.h" +#include "public/public.h" namespace ark::es2panda::lexer { LexerPosition::LexerPosition(const util::StringView &source) : iterator_(source) {} Lexer::Lexer(const parser::ParserContext *parserContext, util::DiagnosticEngine &diagnosticEngine, bool startLexer) - : allocator_(parserContext->GetProgram()->Allocator()), + : allocator_(parserContext->GetProgram()->VarBinder()->GetContext()->Allocator()), parserContext_(parserContext), source_(parserContext->GetProgram()->SourceCode()), pos_(source_), diff --git a/ets2panda/parser/parserImpl.cpp b/ets2panda/parser/parserImpl.cpp index 7b7c10dc59..fd2fdcd721 100644 --- a/ets2panda/parser/parserImpl.cpp +++ b/ets2panda/parser/parserImpl.cpp @@ -16,6 +16,7 @@ #include "parserImpl.h" #include "forwardDeclForParserImpl.h" #include "parserStatusContext.h" +#include "public/public.h" #include "generated/diagnostic.h" #include "varbinder/privateBinding.h" @@ -50,6 +51,14 @@ ParserImpl::ParserImpl(Program *program, const util::Options *options, util::Dia { } +ArenaAllocator *ParserImpl::Allocator() const +{ + if (ctx_ != nullptr) { + return ctx_->AstAllocator(); + } + return program_->Allocator(); +} + std::unique_ptr ParserImpl::InitLexer(const SourceFile &sourceFile) { program_->SetSource(sourceFile); diff --git a/ets2panda/parser/parserImpl.h b/ets2panda/parser/parserImpl.h index cd39352b1d..c765b2b136 100644 --- a/ets2panda/parser/parserImpl.h +++ b/ets2panda/parser/parserImpl.h @@ -238,10 +238,7 @@ protected: ir::TypeNode *AllocBrokenType(const lexer::SourcePosition &pos); ir::TypeNode *AllocBrokenType(const lexer::SourceRange &range); - ArenaAllocator *Allocator() const - { - return program_->Allocator(); - } + ArenaAllocator *Allocator() const; bool CheckModuleAsModifier(); diff --git a/ets2panda/public/public.h b/ets2panda/public/public.h index 246bdecec2..7bbb2a0518 100644 --- a/ets2panda/public/public.h +++ b/ets2panda/public/public.h @@ -161,11 +161,17 @@ struct Context { return allocator; } + // Return allocator used specifically for AST nodes + ArenaAllocator *AstAllocator() const + { + return astAllocator; + } + template T *AllocNode(Args &&...args) { // SUPPRESS_CSA_NEXTLINE(alpha.core.AllocatorETSCheckerHint) - return util::NodeAllocator::ForceSetParent(Allocator(), std::forward(args)...); + return util::NodeAllocator::ForceSetParent(AstAllocator(), std::forward(args)...); } checker::Checker *GetChecker() const; @@ -212,6 +218,7 @@ struct Context { SourceFile const *sourceFile = nullptr; ThreadSafeArenaAllocator *allocator = nullptr; ThreadSafeArenaAllocator *IRNodeAllocator = nullptr; + ThreadSafeArenaAllocator *astAllocator = nullptr; // Dedicated allocator for AST nodes compiler::CompileQueue *queue = nullptr; std::vector const *plugins = nullptr; std::vector contextLiterals; -- Gitee