13af6ab5fSopenharmony_ci/*
23af6ab5fSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License.
53af6ab5fSopenharmony_ci * You may obtain a copy of the License at
63af6ab5fSopenharmony_ci *
73af6ab5fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
83af6ab5fSopenharmony_ci *
93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and
133af6ab5fSopenharmony_ci * limitations under the License.
143af6ab5fSopenharmony_ci */
153af6ab5fSopenharmony_ci
163af6ab5fSopenharmony_ci#include "evaluate/debugInfoStorage.h"
173af6ab5fSopenharmony_ci#include "evaluate/helpers.h"
183af6ab5fSopenharmony_ci#include "evaluate/entityDeclarator.h"
193af6ab5fSopenharmony_ci#include "evaluate/scopedDebugInfoPlugin-inl.h"
203af6ab5fSopenharmony_ci#include "evaluate/debugInfoDeserialization/debugInfoDeserializer.h"
213af6ab5fSopenharmony_ci#include "evaluate/debugInfoDeserialization/classBuilder.h"
223af6ab5fSopenharmony_ci#include "evaluate/debugInfoDeserialization/methodBuilder.h"
233af6ab5fSopenharmony_ci
243af6ab5fSopenharmony_ci#include "public/public.h"
253af6ab5fSopenharmony_ci#include "varbinder/variable.h"
263af6ab5fSopenharmony_ci#include "parser/ETSparser.h"
273af6ab5fSopenharmony_ci#include "parser/program/program.h"
283af6ab5fSopenharmony_ci#include "parser/context/parserContext.h"
293af6ab5fSopenharmony_ci#include "compiler/lowering/scopesInit/scopesInitPhase.h"
303af6ab5fSopenharmony_ci#include "compiler/lowering/util.h"
313af6ab5fSopenharmony_ci
323af6ab5fSopenharmony_ci#include "libpandafile/class_data_accessor-inl.h"
333af6ab5fSopenharmony_ci#include "libpandafile/file-inl.h"
343af6ab5fSopenharmony_ci
353af6ab5fSopenharmony_cinamespace ark::es2panda::evaluate {
363af6ab5fSopenharmony_ci
373af6ab5fSopenharmony_cinamespace {
383af6ab5fSopenharmony_ci
393af6ab5fSopenharmony_cistd::string GetVarDeclSourceCode(std::string_view varName, DebugInfoDeserializer::RegisterNumber regNumber,
403af6ab5fSopenharmony_ci                                 const std::string &typeSignature, panda_file::Type::TypeId typeId,
413af6ab5fSopenharmony_ci                                 checker::GlobalTypesHolder *globalTypes)
423af6ab5fSopenharmony_ci{
433af6ab5fSopenharmony_ci    auto returnType = helpers::ToTypeName(typeSignature, globalTypes);
443af6ab5fSopenharmony_ci    ASSERT(returnType.has_value());
453af6ab5fSopenharmony_ci
463af6ab5fSopenharmony_ci    std::stringstream sstream;
473af6ab5fSopenharmony_ci    sstream << "let " << varName << ':' << *returnType << '=' << helpers::DEBUGGER_API_CLASS_NAME << '.'
483af6ab5fSopenharmony_ci            << helpers::CreateGetterName(typeId) << '(' << regNumber << ')';
493af6ab5fSopenharmony_ci    // Must add cast from Object.
503af6ab5fSopenharmony_ci    if (typeId == panda_file::Type::TypeId::REFERENCE) {
513af6ab5fSopenharmony_ci        sstream << " as " << *returnType;
523af6ab5fSopenharmony_ci    }
533af6ab5fSopenharmony_ci    return sstream.str();
543af6ab5fSopenharmony_ci}
553af6ab5fSopenharmony_ci
563af6ab5fSopenharmony_cistd::string GetVarUpdateSourceCode(std::string_view varName, DebugInfoDeserializer::RegisterNumber regNumber,
573af6ab5fSopenharmony_ci                                   panda_file::Type::TypeId typeId)
583af6ab5fSopenharmony_ci{
593af6ab5fSopenharmony_ci    std::stringstream sstream;
603af6ab5fSopenharmony_ci    sstream << helpers::DEBUGGER_API_CLASS_NAME << '.' << helpers::CreateSetterName(typeId) << '(' << regNumber << ','
613af6ab5fSopenharmony_ci            << varName << ')';
623af6ab5fSopenharmony_ci    return sstream.str();
633af6ab5fSopenharmony_ci}
643af6ab5fSopenharmony_ci
653af6ab5fSopenharmony_ci}  // namespace
663af6ab5fSopenharmony_ci
673af6ab5fSopenharmony_ciDebugInfoDeserializer::DebugInfoDeserializer(ScopedDebugInfoPlugin &debugInfoPlugin) : debugInfoPlugin_(debugInfoPlugin)
683af6ab5fSopenharmony_ci{
693af6ab5fSopenharmony_ci}
703af6ab5fSopenharmony_ci
713af6ab5fSopenharmony_civarbinder::Variable *DebugInfoDeserializer::CreateIrClass(panda_file::File::EntityId classId, parser::Program *program,
723af6ab5fSopenharmony_ci                                                          util::StringView pathToSource, util::StringView classDeclName)
733af6ab5fSopenharmony_ci{
743af6ab5fSopenharmony_ci    LOG(DEBUG, ES2PANDA) << "DebugInfoDeserializer::CreateIrClass " << classDeclName << " in " << pathToSource;
753af6ab5fSopenharmony_ci    ASSERT(program);
763af6ab5fSopenharmony_ci
773af6ab5fSopenharmony_ci    const auto *pf = debugInfoPlugin_.GetDebugInfoStorage()->GetPandaFile(pathToSource.Utf8());
783af6ab5fSopenharmony_ci    ASSERT(pf);
793af6ab5fSopenharmony_ci
803af6ab5fSopenharmony_ci    // NOTE: may cache the created `ClassDataAccessor`.
813af6ab5fSopenharmony_ci    auto cda = panda_file::ClassDataAccessor(*pf, classId);
823af6ab5fSopenharmony_ci
833af6ab5fSopenharmony_ci    auto *classDecl = CreateClassDeclaration(classDeclName, cda, GetSuperClass(cda), program);
843af6ab5fSopenharmony_ci    return classDecl->Definition()->Ident()->Variable();
853af6ab5fSopenharmony_ci}
863af6ab5fSopenharmony_ci
873af6ab5fSopenharmony_ciir::ClassDeclaration *DebugInfoDeserializer::CreateClassDeclaration(util::StringView identName,
883af6ab5fSopenharmony_ci                                                                    panda_file::ClassDataAccessor &cda,
893af6ab5fSopenharmony_ci                                                                    ir::ETSTypeReference *superClass,
903af6ab5fSopenharmony_ci                                                                    parser::Program *program)
913af6ab5fSopenharmony_ci{
923af6ab5fSopenharmony_ci    LOG(DEBUG, ES2PANDA) << "Create class declaration from debug info: " << identName;
933af6ab5fSopenharmony_ci
943af6ab5fSopenharmony_ci    auto *checkHelper = debugInfoPlugin_.GetIrCheckHelper();
953af6ab5fSopenharmony_ci    auto *checker = checkHelper->GetChecker();
963af6ab5fSopenharmony_ci    auto *varBinder = debugInfoPlugin_.GetETSBinder();
973af6ab5fSopenharmony_ci
983af6ab5fSopenharmony_ci    auto *classDecl = ClassBuilder(checker, identName, cda, superClass).Build(program);
993af6ab5fSopenharmony_ci
1003af6ab5fSopenharmony_ci    helpers::DoScopedAction(checker, varBinder, program, nullptr, nullptr, [varBinder, classDecl]() {
1013af6ab5fSopenharmony_ci        compiler::InitScopesPhaseETS::RunExternalNode(classDecl, varBinder);
1023af6ab5fSopenharmony_ci        varBinder->ResolveReferencesForScope(classDecl, compiler::NearestScope(classDecl));
1033af6ab5fSopenharmony_ci    });
1043af6ab5fSopenharmony_ci    // Run checker to assign types to all entities.
1053af6ab5fSopenharmony_ci    checkHelper->CheckNewNode(classDecl, program->GlobalScope(), nullptr, program);
1063af6ab5fSopenharmony_ci
1073af6ab5fSopenharmony_ci    return classDecl;
1083af6ab5fSopenharmony_ci}
1093af6ab5fSopenharmony_ci
1103af6ab5fSopenharmony_civarbinder::Variable *DebugInfoDeserializer::CreateIrLocalVariable(
1113af6ab5fSopenharmony_ci    ir::Identifier *ident, const panda_file::LocalVariableTable &localVariableTable, size_t bytecodeOffset)
1123af6ab5fSopenharmony_ci{
1133af6ab5fSopenharmony_ci    ASSERT(ident);
1143af6ab5fSopenharmony_ci
1153af6ab5fSopenharmony_ci    auto typedVarIter = localVariableTable.end();
1163af6ab5fSopenharmony_ci    uint32_t startOffset = 0;
1173af6ab5fSopenharmony_ci
1183af6ab5fSopenharmony_ci    const auto &identName = ident->Name();
1193af6ab5fSopenharmony_ci    for (auto iter = localVariableTable.begin(); iter != localVariableTable.end(); ++iter) {
1203af6ab5fSopenharmony_ci        const auto &var = *iter;
1213af6ab5fSopenharmony_ci        if (identName.Is(var.name) && var.IsAccessibleAt(bytecodeOffset) && startOffset <= var.startOffset) {
1223af6ab5fSopenharmony_ci            typedVarIter = iter;
1233af6ab5fSopenharmony_ci            startOffset = var.startOffset;
1243af6ab5fSopenharmony_ci        }
1253af6ab5fSopenharmony_ci    }
1263af6ab5fSopenharmony_ci    if (typedVarIter != localVariableTable.end()) {
1273af6ab5fSopenharmony_ci        return CreateLocalVarDecl(ident, typedVarIter->regNumber, typedVarIter->typeSignature);
1283af6ab5fSopenharmony_ci    }
1293af6ab5fSopenharmony_ci
1303af6ab5fSopenharmony_ci    return nullptr;
1313af6ab5fSopenharmony_ci}
1323af6ab5fSopenharmony_ci
1333af6ab5fSopenharmony_civarbinder::Variable *DebugInfoDeserializer::CreateIrGlobalVariable(parser::Program *program,
1343af6ab5fSopenharmony_ci                                                                   util::StringView pathToSource,
1353af6ab5fSopenharmony_ci                                                                   util::StringView varDeclName)
1363af6ab5fSopenharmony_ci{
1373af6ab5fSopenharmony_ci    ASSERT(program);
1383af6ab5fSopenharmony_ci
1393af6ab5fSopenharmony_ci    auto *debugInfoStorage = debugInfoPlugin_.GetDebugInfoStorage();
1403af6ab5fSopenharmony_ci    auto *checkHelper = debugInfoPlugin_.GetIrCheckHelper();
1413af6ab5fSopenharmony_ci
1423af6ab5fSopenharmony_ci    const auto *pf = debugInfoStorage->GetPandaFile(pathToSource.Utf8());
1433af6ab5fSopenharmony_ci    ASSERT(pf);
1443af6ab5fSopenharmony_ci
1453af6ab5fSopenharmony_ci    varbinder::Variable *var = nullptr;
1463af6ab5fSopenharmony_ci
1473af6ab5fSopenharmony_ci    auto *cda = debugInfoStorage->GetGlobalClassAccessor(pathToSource.Utf8());
1483af6ab5fSopenharmony_ci    cda->EnumerateFields([program, varDeclName, pf, &var, checkHelper](panda_file::FieldDataAccessor &fda) {
1493af6ab5fSopenharmony_ci        // All ETSGLOBAL fields must be static.
1503af6ab5fSopenharmony_ci        ASSERT(fda.IsStatic());
1513af6ab5fSopenharmony_ci
1523af6ab5fSopenharmony_ci        const char *name = utf::Mutf8AsCString(pf->GetStringData(fda.GetNameId()).data);
1533af6ab5fSopenharmony_ci        if (!varDeclName.Is(name)) {
1543af6ab5fSopenharmony_ci            return;
1553af6ab5fSopenharmony_ci        }
1563af6ab5fSopenharmony_ci        // Must be unique within global variables.
1573af6ab5fSopenharmony_ci        ASSERT(var == nullptr);
1583af6ab5fSopenharmony_ci
1593af6ab5fSopenharmony_ci        auto *typeNode = helpers::PandaTypeToTypeNode(*pf, fda, checkHelper->GetChecker());
1603af6ab5fSopenharmony_ci        ASSERT(typeNode);
1613af6ab5fSopenharmony_ci
1623af6ab5fSopenharmony_ci        // Global variable is found - add it into source module's global class properties.
1633af6ab5fSopenharmony_ci        auto modFlags = helpers::GetModifierFlags(fda, true) | ir::ModifierFlags::EXPORT;
1643af6ab5fSopenharmony_ci        auto *field = helpers::CreateClassProperty(checkHelper->GetChecker(), name, typeNode, modFlags);
1653af6ab5fSopenharmony_ci        // Fields parent will be set in `AddProperties`.
1663af6ab5fSopenharmony_ci        program->GlobalClass()->AddProperties(
1673af6ab5fSopenharmony_ci            ArenaVector<ir::AstNode *>(1, field, checkHelper->GetChecker()->Allocator()->Adapter()));
1683af6ab5fSopenharmony_ci
1693af6ab5fSopenharmony_ci        checkHelper->CheckGlobalEntity(program, field);
1703af6ab5fSopenharmony_ci        var = field->Key()->AsIdentifier()->Variable();
1713af6ab5fSopenharmony_ci    });
1723af6ab5fSopenharmony_ci
1733af6ab5fSopenharmony_ci    return var;
1743af6ab5fSopenharmony_ci}
1753af6ab5fSopenharmony_ci
1763af6ab5fSopenharmony_civarbinder::Variable *DebugInfoDeserializer::CreateIrGlobalMethods(ArenaVector<ir::AstNode *> &createdMethods,
1773af6ab5fSopenharmony_ci                                                                  parser::Program *program,
1783af6ab5fSopenharmony_ci                                                                  util::StringView pathToSource,
1793af6ab5fSopenharmony_ci                                                                  util::StringView methodDeclName)
1803af6ab5fSopenharmony_ci{
1813af6ab5fSopenharmony_ci    ASSERT(program);
1823af6ab5fSopenharmony_ci
1833af6ab5fSopenharmony_ci    varbinder::Variable *var = nullptr;
1843af6ab5fSopenharmony_ci
1853af6ab5fSopenharmony_ci    auto *cda = debugInfoPlugin_.GetDebugInfoStorage()->GetGlobalClassAccessor(pathToSource.Utf8());
1863af6ab5fSopenharmony_ci    cda->EnumerateMethods([this, &var, &createdMethods, program, methodDeclName,
1873af6ab5fSopenharmony_ci                           &cda](panda_file::MethodDataAccessor &mda) {
1883af6ab5fSopenharmony_ci        if (!methodDeclName.Is(mda.GetFullName())) {
1893af6ab5fSopenharmony_ci            return;
1903af6ab5fSopenharmony_ci        }
1913af6ab5fSopenharmony_ci
1923af6ab5fSopenharmony_ci        MethodBuilder builder(debugInfoPlugin_.GetIrCheckHelper()->GetChecker(), mda, helpers::GetModifierFlags(*cda));
1933af6ab5fSopenharmony_ci        auto *method = std::move(builder).Build();
1943af6ab5fSopenharmony_ci
1953af6ab5fSopenharmony_ci        method->SetParent(program->GlobalClass());
1963af6ab5fSopenharmony_ci        createdMethods.emplace_back(method);
1973af6ab5fSopenharmony_ci
1983af6ab5fSopenharmony_ci        // Postpone Checker until the whole overload set is created.
1993af6ab5fSopenharmony_ci        debugInfoPlugin_.GetIrCheckHelper()->CheckGlobalEntity(program, method, false);
2003af6ab5fSopenharmony_ci
2013af6ab5fSopenharmony_ci        // Sanity checks.
2023af6ab5fSopenharmony_ci        auto *methodVar = method->AsClassElement()->Value()->AsFunctionExpression()->Function()->Id()->Variable();
2033af6ab5fSopenharmony_ci        ASSERT(methodVar != nullptr);
2043af6ab5fSopenharmony_ci        ASSERT(var == nullptr || var == methodVar);
2053af6ab5fSopenharmony_ci        var = methodVar;
2063af6ab5fSopenharmony_ci    });
2073af6ab5fSopenharmony_ci
2083af6ab5fSopenharmony_ci    return var;
2093af6ab5fSopenharmony_ci}
2103af6ab5fSopenharmony_ci
2113af6ab5fSopenharmony_civarbinder::Variable *DebugInfoDeserializer::CreateLocalVarDecl(ir::Identifier *ident, RegisterNumber regNumber,
2123af6ab5fSopenharmony_ci                                                               const std::string &typeSignature)
2133af6ab5fSopenharmony_ci{
2143af6ab5fSopenharmony_ci    ASSERT(ident);
2153af6ab5fSopenharmony_ci
2163af6ab5fSopenharmony_ci    auto *checkHelper = debugInfoPlugin_.GetIrCheckHelper();
2173af6ab5fSopenharmony_ci    auto *varBinder = debugInfoPlugin_.GetETSBinder();
2183af6ab5fSopenharmony_ci    auto identName = ident->Name().Utf8();
2193af6ab5fSopenharmony_ci
2203af6ab5fSopenharmony_ci    auto typeId = helpers::GetTypeId(typeSignature);
2213af6ab5fSopenharmony_ci    auto *checker = checkHelper->GetChecker();
2223af6ab5fSopenharmony_ci    auto varDeclSource =
2233af6ab5fSopenharmony_ci        GetVarDeclSourceCode(identName, regNumber, typeSignature, typeId, checker->GetGlobalTypesHolder());
2243af6ab5fSopenharmony_ci
2253af6ab5fSopenharmony_ci    // Set up correct scope before parsing statements.
2263af6ab5fSopenharmony_ci    auto *topStatement = helpers::GetEnclosingBlock(ident);
2273af6ab5fSopenharmony_ci    checker::ScopeContext ctx(checker, topStatement->Scope());
2283af6ab5fSopenharmony_ci    auto statementScope = varbinder::LexicalScope<varbinder::Scope>::Enter(varBinder, topStatement->Scope());
2293af6ab5fSopenharmony_ci
2303af6ab5fSopenharmony_ci    parser::Program p(checker->Allocator(), varBinder);
2313af6ab5fSopenharmony_ci    auto parser = parser::ETSParser(&p, varBinder->GetContext()->config->options->CompilerOptions(),
2323af6ab5fSopenharmony_ci                                    parser::ParserStatus::NO_OPTS);
2333af6ab5fSopenharmony_ci
2343af6ab5fSopenharmony_ci    auto *varDecl = parser.CreateFormattedStatement(varDeclSource, parser::ParserContext::DEFAULT_SOURCE_FILE);
2353af6ab5fSopenharmony_ci    ASSERT(varDecl != nullptr);
2363af6ab5fSopenharmony_ci    varDecl->SetParent(topStatement);
2373af6ab5fSopenharmony_ci    // Declaration will be placed at start of current scope.
2383af6ab5fSopenharmony_ci    // Can't insert right away until block's statements iteration ends.
2393af6ab5fSopenharmony_ci    debugInfoPlugin_.RegisterPrologueEpilogue<true>(topStatement, varDecl);
2403af6ab5fSopenharmony_ci    checkHelper->CheckLocalEntity(varDecl);
2413af6ab5fSopenharmony_ci
2423af6ab5fSopenharmony_ci    // Yet don't track whether the value was modified, so store result unconditionally in the end of the scope.
2433af6ab5fSopenharmony_ci    auto varUpdateSource = GetVarUpdateSourceCode(identName, regNumber, typeId);
2443af6ab5fSopenharmony_ci
2453af6ab5fSopenharmony_ci    auto *varUpdate = parser.CreateFormattedStatement(varUpdateSource, parser::ParserContext::DEFAULT_SOURCE_FILE);
2463af6ab5fSopenharmony_ci    ASSERT(varUpdate != nullptr);
2473af6ab5fSopenharmony_ci    varUpdate->SetParent(topStatement);
2483af6ab5fSopenharmony_ci    // Can't insert right away until block's statements iteration ends.
2493af6ab5fSopenharmony_ci    debugInfoPlugin_.RegisterPrologueEpilogue<false>(topStatement, varUpdate);
2503af6ab5fSopenharmony_ci    checkHelper->CheckLocalEntity(varUpdate);
2513af6ab5fSopenharmony_ci
2523af6ab5fSopenharmony_ci    // Local variables are not registered, as they can be found in local scope.
2533af6ab5fSopenharmony_ci    ASSERT(varDecl->AsVariableDeclaration()->Declarators().size() == 1);
2543af6ab5fSopenharmony_ci    return varDecl->AsVariableDeclaration()->Declarators()[0]->Id()->Variable();
2553af6ab5fSopenharmony_ci}
2563af6ab5fSopenharmony_ci
2573af6ab5fSopenharmony_ci}  // namespace ark::es2panda::evaluate
258