/* * Copyright (c) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ES2PANDA_UTIL_PATCHFIX_H #define ES2PANDA_UTIL_PATCHFIX_H #include #include #include #include #include #include #include #include namespace panda::es2panda::binder { class VariableScope; } // namespace panda::es2panda::binder namespace panda::es2panda::compiler { class PandaGen; } // namespace panda::es2panda::compiler namespace panda::es2panda::util { enum class PatchFixKind { DUMPSYMBOLTABLE, HOTFIX, COLDFIX, HOTRELOAD }; class PatchFix { using LiteralBuffers = ArenaVector>>; public: PatchFix(bool generateSymbolFile, bool generatePatch, PatchFixKind patchFixKind, const std::string &recordName, util::SymbolTable *symbolTable) : generateSymbolFile_(generateSymbolFile), generatePatch_(generatePatch), patchFixKind_(patchFixKind), recordName_(recordName), symbolTable_(symbolTable), allocator_(SpaceType::SPACE_TYPE_COMPILER, nullptr, true), topScopeLexEnvs_(allocator_.Adapter()), patchFuncNames_(allocator_.Adapter()), newFuncNames_(allocator_.Adapter()), funcDefineIns_(allocator_.Adapter()), modifiedClassNames_(allocator_.Adapter()), classMemberFunctions_(allocator_.Adapter()), funcDefinedClasses_(allocator_.Adapter()) { originFunctionInfo_ = symbolTable_->GetOriginFunctionInfo(); originModuleInfo_ = symbolTable_->GetOriginModuleInfo(); originRecordHashFunctionNames_ = symbolTable_->GetOriginRecordHashFunctionNames(); patchMain0_ = recordName_ + ".patch_main_0"; patchMain1_ = recordName_ + ".patch_main_1"; funcMain0_ = recordName_ + ".func_main_0"; } void Finalize(panda::pandasm::Program **prog); bool IsScopeValidToPatchLexical(binder::VariableScope *scope) const; uint32_t GetSlotIdFromSymbolTable(const std::string &variableName); void AllocSlotfromPatchEnv(const std::string &variableName); uint32_t GetPatchLexicalIdx(const std::string &variableName); bool IsPatchVar(uint32_t slot); void ProcessFunction(const compiler::PandaGen *pg, panda::pandasm::Function *func, LiteralBuffers &literalBuffers); void ProcessModule(const std::string &recordName, std::vector &moduleBuffer); void ProcessJsonContentRecord(const std::string &recordName, const std::string &jsonFileContent); void CheckAndRestoreSpecialFunctionName(uint32_t globalIndexForSpecialFunc, std::string &funcName, std::string recordName); bool IsDumpSymbolTable() const; bool IsHotFix() const; bool IsColdFix() const; bool IsHotReload() const; private: void DumpFunctionInfo(const compiler::PandaGen *pg, panda::pandasm::Function *func, LiteralBuffers &literalBuffers); void HandleFunction(const compiler::PandaGen *pg, panda::pandasm::Function *func, LiteralBuffers &literalBuffers); void CollectFunctionsWithDefinedClasses(std::string funcName, std::string className); std::vector> GenerateFunctionAndClassHash(panda::pandasm::Function *func, LiteralBuffers &literalBuffers); void DumpModuleInfo(const std::string &recordName, std::vector &moduleBuffer); void ValidateModuleInfo(const std::string &recordName, std::vector &moduleBuffer); void DumpJsonContentRecInfo(const std::string &recordName, const std::string &jsonFileContent); void ValidateJsonContentRecInfo(const std::string &recordName, const std::string &jsonFileContent); std::string ExpandLiteral(int64_t bufferIdx, LiteralBuffers &literalBuffers); std::string ConvertLiteralToString(std::vector &literalBuffer); void CollectFuncDefineIns(panda::pandasm::Function *func); void AddHeadAndTailInsForPatchFuncMain0(std::vector &ins); void AddTailInsForPatchFuncMain1(std::vector &ins); void CreateFunctionPatchMain0AndMain1(panda::pandasm::Function &patchFuncMain0, panda::pandasm::Function &patchFuncMain1); bool IsAnonymousOrSpecialOrDuplicateFunction(const std::string &funcName); bool CompareLexenv(const std::string &funcName, const compiler::PandaGen *pg, SymbolTable::OriginFunctionInfo &bytecodeInfo); bool CompareClassHash(std::vector> &hashList, SymbolTable::OriginFunctionInfo &bytecodeInfo); void CollectClassMemberFunctions(const std::string &className, int64_t bufferIdx, LiteralBuffers &literalBuffers); std::vector GetLiteralMethods(int64_t bufferIdx, LiteralBuffers &literalBuffers); void HandleModifiedClasses(panda::pandasm::Program *prog); void HandleModifiedDefinedClassFunc(panda::pandasm::Program *prog); int64_t GetLiteralIdxFromStringId(const std::string &stringId); std::mutex m_; uint32_t topScopeIdx_ {0}; bool patchError_ {false}; bool generateSymbolFile_ {false}; bool generatePatch_ {false}; PatchFixKind patchFixKind_; std::string recordName_; std::string funcMain0_; std::string patchMain0_; // stores newly added function define ins, runtime will execute std::string patchMain1_; // stores modified function and class define ins, runtime will scan but not execute util::SymbolTable* symbolTable_ {nullptr}; ArenaAllocator allocator_; ArenaUnorderedMap *originFunctionInfo_ {nullptr}; ArenaUnorderedMap *originModuleInfo_ {nullptr}; ArenaUnorderedMap> *originRecordHashFunctionNames_ { nullptr}; ArenaUnorderedMap topScopeLexEnvs_; ArenaSet patchFuncNames_; ArenaSet newFuncNames_; ArenaVector funcDefineIns_; ArenaSet modifiedClassNames_; ArenaUnorderedMap> classMemberFunctions_; ArenaUnorderedMap> funcDefinedClasses_; }; } // namespace panda::es2panda::util #endif // ES2PANDA_UTIL_PATCHFIX_H