diff --git a/src/mapleall/bin/debug/dex2mpl.tar.gz b/src/mapleall/bin/debug/dex2mpl.tar.gz index 51b04921fd6e48acd9cd08095abd7f6239f0fac2..fc4a647ddfe9ce1ccecb1257b1dcfd6b535a0bb9 100644 Binary files a/src/mapleall/bin/debug/dex2mpl.tar.gz and b/src/mapleall/bin/debug/dex2mpl.tar.gz differ diff --git a/src/mapleall/bin/dex2mpl b/src/mapleall/bin/dex2mpl index cb78732486e16c60b7b13880067538ad9dc45d78..d75ddc70b9bb6554cd9a94aeced6cbbfc1395e20 100755 Binary files a/src/mapleall/bin/dex2mpl and b/src/mapleall/bin/dex2mpl differ diff --git a/src/mapleall/bin/dex2mpl_android b/src/mapleall/bin/dex2mpl_android index 2746a49fcd25715b9f83b6c2a3c24f865bbf9ef4..3a9a8630cf97f74a30d66581eaa1aba9ac9ede2f 100755 Binary files a/src/mapleall/bin/dex2mpl_android and b/src/mapleall/bin/dex2mpl_android differ diff --git a/src/mapleall/bin/jbc2mpl b/src/mapleall/bin/jbc2mpl index d7553b22201c6789a6582976fa36b469b629f014..65ebc0b30be0be2f25861af500379d2ee0e72dbc 100755 Binary files a/src/mapleall/bin/jbc2mpl and b/src/mapleall/bin/jbc2mpl differ diff --git a/src/mapleall/maple_be/include/cg/aarch64/aarch64_operand.h b/src/mapleall/maple_be/include/cg/aarch64/aarch64_operand.h index 9e96d8526cf5af941d07bb5ff1661498bd8a96fa..79ca62de99959b23194b7adcdc98d8f4c3db2cc1 100644 --- a/src/mapleall/maple_be/include/cg/aarch64/aarch64_operand.h +++ b/src/mapleall/maple_be/include/cg/aarch64/aarch64_operand.h @@ -499,7 +499,6 @@ class AArch64MemOperand : public MemOperand { /* * ARMv8-A A64 ISA Overview by Matteo Franchin @ ARM * (presented at 64-bit Android on ARM. Sep. 2015) p.14 - * #endif // ~HUAWEI_EXTERNAL_RELEASE * o Address to load from/store to is a 64-bit base register + an optional offset * LDR X0, [X1] ; Load from address held in X1 * STR X0, [X1] ; Store to address held in X1 diff --git a/src/mapleall/maple_be/src/cg/aarch64/aarch64_args.cpp b/src/mapleall/maple_be/src/cg/aarch64/aarch64_args.cpp index 35a496d4da0f4ef3f553c82ae7f7aa7a68499057..a16ed0cee4524eb3a3df5075a0f0caf7553253cc 100644 --- a/src/mapleall/maple_be/src/cg/aarch64/aarch64_args.cpp +++ b/src/mapleall/maple_be/src/cg/aarch64/aarch64_args.cpp @@ -267,7 +267,7 @@ void AArch64MoveRegArgs::MoveVRegisterArgs() { ParmLocator parmlocator(aarchCGFunc->GetBecommon()); PLocInfo ploc; - uint32 formalCount = aarchCGFunc->GetFunction().GetFormalCount(); + uint32 formalCount = static_cast(aarchCGFunc->GetFunction().GetFormalCount()); uint32 start = 0; if (formalCount) { MIRFunction *func = const_cast(aarchCGFunc->GetBecommon().GetMIRModule().CurFunction()); diff --git a/src/mapleall/maple_driver/include/jbc2mpl_option.h b/src/mapleall/maple_driver/include/jbc2mpl_option.h index 2580ad5e736694f5322e1b04f5335c7d5fad32f7..48bc3b5f0b0bbfa9eaa78e89750bf0958d7b77bd 100644 --- a/src/mapleall/maple_driver/include/jbc2mpl_option.h +++ b/src/mapleall/maple_driver/include/jbc2mpl_option.h @@ -20,6 +20,27 @@ namespace maple { enum JbcOptionIndex { kUseStringFactory, kOutMpl, + kInClass, + kInJar, + kInApkMplt, + kOutClassXML, + kOutPath, + // profiling + kProfileLiteral, + // options + kGenMplt, + kGenAsciiMplt, + kTypeSameName, + kEnableTypeInfer, + kDumpLevel, + kDumpTime, + kDumpPolymorphic, + kDebugJBCFuncName, + kDebugDumpJBCFuncCFG, + kDebugDumpJBCFuncLocalVar, + kDebugDumpFEFuncStmt, + kDebugDumpFEFuncCFG, + kDebugDumpFEFuncDataFlow, }; const mapleOption::Descriptor jbcUsage[] = { @@ -37,6 +58,113 @@ const mapleOption::Descriptor jbcUsage[] = { " -o, -out output.mpl : output mpl name", "jbc2mpl", {} }, + { kInClass, 0, "", "inclass", mapleOption::kBuildTypeAll, mapleOption::kArgCheckPolicyRequired, + " -inclass file1.class,file2.class\n" + " : input class files", + "jbc2mpl", + {} }, + { kInJar, 0, "", "injar", mapleOption::kBuildTypeAll, mapleOption::kArgCheckPolicyRequired, + " -injar file1.jar,file2.jar\n" + " : input jar files", + "jbc2mpl", + {} }, + { kInMplt, 0, "", "mplt", mapleOption::kBuildTypeAll, mapleOption::kArgCheckPolicyRequired, + " -mplt file1.mplt,file2.mplt\n" + " : import mplt files", + "jbc2mpl", + {} }, + { kInApkMplt, 0, "", "apkmplt", mapleOption::kBuildTypeAll, mapleOption::kArgCheckPolicyRequired, + " -apkmplt file1.mplt,file2.mplt\n" + " : import apk mplt files", + "jbc2mpl", + {} }, + { kOutClassXML, 0, "", "out-classXML", mapleOption::kBuildTypeAll, mapleOption::kArgCheckPolicyRequired, + " -out-classXML classes.xml\n" + " : output class in XML", + "jbc2mpl", + {} }, + { kOutPath, 0, "", "output", mapleOption::kBuildTypeAll, mapleOption::kArgCheckPolicyRequired, + " -output path : output path", + "jbc2mpl", + {} }, + { kGenMplt, 0, "t", "", mapleOption::kBuildTypeAll, mapleOption::kArgCheckPolicyNone, + " -t : Generate mplt only", + "jbc2mpl", + {} }, + { kGenAsciiMplt, 0, "", "asciimplt", mapleOption::kBuildTypeAll, mapleOption::kArgCheckPolicyNone, + " -asciimplt : Generate ascii mplt", + "jbc2mpl", + {} }, + { kUnknown, 0, "", "", mapleOption::kBuildTypeAll, mapleOption::kArgCheckPolicyUnknown, + "========== Profiling ==========", + "jbc2mpl", + {} }, + { kProfileLiteral, 0, "", "litprofile", mapleOption::kBuildTypeAll, mapleOption::kArgCheckPolicyRequired, + " -litprofile=litprofilefile\n" + " : optimize based on literal profiling data", + "jbc2mpl", + {} }, + { kTypeSameName, 0, "", "same-name", mapleOption::kBuildTypeAll, mapleOption::kArgCheckPolicyRequired, + " -same-name=strategy\n" + " : strategy when type with the same name\n" + " : strategy list\n" + " : ERROR: print error and stop compiling (default)\n" + " : USELIB: use first imported by sequence apkmplt-mplt-class/jar\n" + " : USEINPUT: use definition in class/jar", + "jbc2mpl", + {} }, + { kEnableTypeInfer, 0, "", "enable-typeinfer", mapleOption::kBuildTypeAll, mapleOption::kArgCheckPolicyNone, + " -enable-typeinfer : enable type infer operation", + "jbc2mpl", + {} }, + { kUnknown, 0, "", "", mapleOption::kBuildTypeAll, mapleOption::kArgCheckPolicyUnknown, + "========== Debugging ==========", + "jbc2mpl", + {} }, + { kDumpLevel, 0, "", "dump-level", mapleOption::kBuildTypeAll, mapleOption::kArgCheckPolicyRequired, + " -dump-level : dump level", + "jbc2mpl", + {} }, + { kDumpTime, 0, "", "dump-time", mapleOption::kBuildTypeAll, mapleOption::kArgCheckPolicyNone, + " -dump-time : dump time", + "jbc2mpl", + {} }, + { kDumpPolymorphic, 0, "", "dump-polymorphic", mapleOption::kBuildTypeAll, mapleOption::kArgCheckPolicyNone, + " -dump-polymorphic : dump polymorphic methods", + "jbc2mpl", + {} }, + { kDebugJBCFuncName, 0, "", "debug-jbcfuncname", mapleOption::kBuildTypeAll, mapleOption::kArgCheckPolicyRequired, + " -debug-jbcfuncname=funcName\n" + " : debug jbc func name", + "jbc2mpl", + {} }, + { kDebugDumpJBCFuncCFG, 0, "", "debug-dump-jbcfunc-cfg", mapleOption::kBuildTypeAll, mapleOption::kArgCheckPolicyNone, + " -debug-dump-jbcfunc-cfg\n" + " : debug dump jbc func cfg", + "jbc2mpl", + {} }, + { kDebugDumpJBCFuncLocalVar, 0, "", "debug-dump-jbcfunc-localvar", + mapleOption::kBuildTypeAll, mapleOption::kArgCheckPolicyNone, + " -debug-dump-jbcfunc-localvar\n" + " : debug dump jbc func local variable info", + "jbc2mpl", + {} }, + { kDebugDumpFEFuncStmt, 0, "", "debug-dump-fefunc-stmt", mapleOption::kBuildTypeAll, mapleOption::kArgCheckPolicyNone, + " -debug-dump-fefunc-stmt\n" + " : debug dump fe func stmt", + "jbc2mpl", + {} }, + { kDebugDumpFEFuncCFG, 0, "", "debug-dump-fefunc-cfg", mapleOption::kBuildTypeAll, mapleOption::kArgCheckPolicyNone, + " -debug-dump-fefunc-cfg\n" + " : debug dump fe func cfg", + "jbc2mpl", + {} }, + { kDebugDumpFEFuncDataFlow, 0, "", "debug-dump-fefunc-dataflow", + mapleOption::kBuildTypeAll, mapleOption::kArgCheckPolicyNone, + " -debug-dump-fefunc-dataflow\n" + " : debug dump fe func dataflow", + "jbc2mpl", + {} }, { kUnknown, 0, "", "", mapleOption::kBuildTypeAll, mapleOption::kArgCheckPolicyNone, "", "jbc2mpl", diff --git a/src/mapleall/maple_driver/src/file_utils.cpp b/src/mapleall/maple_driver/src/file_utils.cpp index 76148174dd9bd67cb198d587b655ec83b6a91d29..75942c03aed6497fa8c3b44b49a89d77341099c0 100644 --- a/src/mapleall/maple_driver/src/file_utils.cpp +++ b/src/mapleall/maple_driver/src/file_utils.cpp @@ -31,9 +31,17 @@ const std::string kFileSeperatorWindowsStyleStr = std::string(1, kFileSeperatorW } // namespace namespace maple { +#if __WIN32 +const char kFileSeperatorChar = kFileSeperatorWindowsStyleChar; +#else const char kFileSeperatorChar = kFileSeperatorLinuxStyleChar; +#endif +#if __WIN32 +const std::string kFileSeperatorStr = kFileSeperatorWindowsStyleStr; +#else const std::string kFileSeperatorStr = kFileSeperatorLinuxStyleStr; +#endif std::string FileUtils::GetRealPath(const std::string &filePath) { #ifdef _WIN32 diff --git a/src/mapleall/maple_driver/src/mpl_options.cpp b/src/mapleall/maple_driver/src/mpl_options.cpp index 466b0632501dd51654d999ca91c83991c3f08af2..08a04d40f35fcc3a4e2332c20b4d38421dda3e0c 100644 --- a/src/mapleall/maple_driver/src/mpl_options.cpp +++ b/src/mapleall/maple_driver/src/mpl_options.cpp @@ -24,6 +24,7 @@ #include "version.h" #include "default_options.def" #include "driver_option_common.h" +#include "ipa_option.h" #include "jbc2mpl_option.h" #include "me_option.h" #include "option.h" @@ -37,6 +38,7 @@ const std::string kMapleDriverVersion = "MapleDriver " + std::to_string(Version: std::to_string(Version::kMinorCompilerVersion) + " 20190929"; const std::vector kMapleCompilers = { "jbc2mpl", + "dex2mpl", "mplipa", "me", "mpl2mpl", "mplcg" }; int MplOptions::Parse(int argc, char **argv) { diff --git a/src/mapleall/maple_ipa/BUILD.gn b/src/mapleall/maple_ipa/BUILD.gn index b607be4e5708ef8ed1626376892566d4fefd4716..7353694d863ef2774736e747d5cf27be6ac2d009 100755 --- a/src/mapleall/maple_ipa/BUILD.gn +++ b/src/mapleall/maple_ipa/BUILD.gn @@ -30,6 +30,11 @@ src_libmplipa = [ "src/clone.cpp", "src/retype.cpp", "src/call_graph.cpp", + "src/method_replace.cpp", + "src/ipa_escape_analysis.cpp", + "src/do_ipa_escape_analysis.cpp", + "src/ea_connection_graph.cpp", + "src/ipa_option.cpp", ] configs = [ "${MAPLEALL_ROOT}:mapleallcompilecfg" ] diff --git a/src/mapleall/maple_ipa/include/do_ipa_escape_analysis.h b/src/mapleall/maple_ipa/include/do_ipa_escape_analysis.h new file mode 100644 index 0000000000000000000000000000000000000000..11e2da72d4c5dc08546b9aee1eaa0aa38ed7f51d --- /dev/null +++ b/src/mapleall/maple_ipa/include/do_ipa_escape_analysis.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) [2019-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef INCLUDE_MAPLEIPA_INCLUDE_IPAESCAPEANALYSIS_H +#define INCLUDE_MAPLEIPA_INCLUDE_IPAESCAPEANALYSIS_H +#include "mir_parser.h" +#include "mir_function.h" +#include "me_function.h" +#include "opcode_info.h" +#include "mir_builder.h" +#include "mempool.h" +#include "mempool_allocator.h" +#include "call_graph.h" +#include "module_phase.h" +#include "me_phase.h" +#include "mir_nodes.h" +#include "me_ir.h" +#include "me_irmap.h" +#include "ipa_escape_analysis.h" +#include "me_loop_analysis.h" + +namespace maple { +class DoIpaEA : public MeFuncPhase { + public: + explicit DoIpaEA(MePhaseID id) : MeFuncPhase(id) {} + ~DoIpaEA() = default; + AnalysisResult *Run(MeFunction*, MeFuncResultMgr*, ModuleResultMgr*) override; + std::string PhaseName() const override { + return "ipaea"; + } +}; + +class DoIpaEAOpt : public MeFuncPhase { + public: + explicit DoIpaEAOpt(MePhaseID id) : MeFuncPhase(id) {} + ~DoIpaEAOpt() = default; + AnalysisResult *Run(MeFunction*, MeFuncResultMgr*, ModuleResultMgr*) override; + std::string PhaseName() const override { + return "ipaeaopt"; + } +}; +} +#endif // INCLUDE_MAPLEIPA_INCLUDE_IPAESCAPEANALYSIS_H diff --git a/src/mapleall/maple_ipa/include/ea_connection_graph.h b/src/mapleall/maple_ipa/include/ea_connection_graph.h new file mode 100644 index 0000000000000000000000000000000000000000..5c0972087d8227c72605b17909a84d3037330a05 --- /dev/null +++ b/src/mapleall/maple_ipa/include/ea_connection_graph.h @@ -0,0 +1,696 @@ +/* + * Copyright (c) [2019] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MAPLEIPA_INCLUDE_ESCAPEANALYSIS_H +#define MAPLEIPA_INCLUDE_ESCAPEANALYSIS_H +#include +#include +#include +#include "call_graph.h" +#include "me_ir.h" +#include "irmap.h" + +namespace maple { +enum NodeKind { + kObejectNode, + kReferenceNode, + kActualNode, + kFieldNode, + kPointerNode +}; + +enum EAStatus { + kNoEscape, + kReturnEscape, + kArgumentEscape, + kGlobalEscape +}; + +const inline std::string EscapeName(EAStatus esc) { + switch (esc) { + case kNoEscape: + return "NoEsc"; + case kReturnEscape: + return "RetEsc"; + case kArgumentEscape: + return "ArgEsc"; + case kGlobalEscape: + return "GlobalEsc"; + default: + return ""; + } +} + +class Location { + public: + Location(std::string modName, uint32 fileId, uint32 lineId) : modName(modName), fileId(fileId), lineId(lineId) {}; + ~Location() = default; + + const std::string &GetModName() const { + return modName; + } + + uint32 GetFileId() const { + return fileId; + } + + uint32 GetLineId() const { + return lineId; + } + + private: + std::string modName; + uint32 fileId; + uint32 lineId; +}; + +class EACGBaseNode; +class EACGObjectNode; +class EACGFieldNode; +class EACGRefNode; +class EACGActualNode; +class EACGPointerNode; + +class EAConnectionGraph { + public: + friend class BinaryMplExport; + friend class BinaryMplImport; + friend class EACGBaseNode; + friend class EACGObjectNode; + friend class EACGFieldNode; + friend class EACGRefNode; + friend class EACGPointerNode; + // If import is false, need init globalNode. + EAConnectionGraph(MIRModule *m, MapleAllocator *allocator, GStrIdx funcName, bool import = false) + : mirModule(m), + alloc(allocator), + nodes(allocator->Adapter()), + expr2Nodes(allocator->Adapter()), + funcArgNodes(allocator->Adapter()), + callSite2Nodes(allocator->Adapter()), + funcStIdx(funcName), + hasUpdated(false), + needConv(false), + imported(import), + exprIdMax(0), + globalObj(nullptr), + globalRef(nullptr), + globalField(nullptr) {}; + ~EAConnectionGraph() = default; + + EACGObjectNode *CreateObjectNode(MeExpr *expr, EAStatus initialEas, bool isPh, TyIdx tyIdx); + EACGRefNode *CreateReferenceNode(MeExpr *expr, EAStatus initialEas, bool isStatic); + EACGActualNode *CreateActualNode(EAStatus initialEas, bool isReurtn, bool isPh, uint8 argIdx, + uint32 callSiteInfo); + EACGFieldNode *CreateFieldNode(MeExpr *expr, EAStatus initialEas, FieldID fId, EACGObjectNode *belongTo, bool isPh); + EACGPointerNode *CreatePointerNode(MeExpr *expr, EAStatus initialEas, int inderictL); + EACGBaseNode *GetCGNodeFromExpr(MeExpr *me); + EACGFieldNode *GetOrCreateFieldNodeFromIdx(EACGObjectNode &obj, uint32 fId); + EACGActualNode *GetReturnNode() const; + const MapleVector *GetFuncArgNodeVector() const; + void TouchCallSite(uint32 callSiteInfo); + MapleVector *GetCallSiteArgNodeVector(uint32 callSite); + bool ExprCanBeOptimized(MeExpr &expr); + + bool CGHasUpdated() const { + return hasUpdated; + } + + void UnSetCGUpdateFlag() { + hasUpdated = false; + } + + void SetCGHasUpdated() { + hasUpdated = true; + } + + void SetExprIdMax(int max) { + exprIdMax = max; + } + + void SetNeedConservation() { + needConv = true; + } + + bool GetNeedConservation() const { + return needConv; + } + + GStrIdx GetFuncNameStrIdx() const { + return funcStIdx; + } + + EACGObjectNode *GetGlobalObject() { + return globalObj; + } + + const EACGObjectNode *GetGlobalObject() const { + return globalObj; + } + + EACGRefNode *GetGlobalReference() { + return globalRef; + } + + const EACGRefNode *GetGlobalReference() const { + return globalRef; + } + + const MapleVector &GetNodes() const { + return nodes; + } + + void ResizeNodes(size_t size, EACGBaseNode *val) { + nodes.resize(size, val); + } + + EACGBaseNode *GetNode(uint32 idx) const { + CHECK_FATAL(idx < nodes.size(), "array check fail"); + return nodes[idx]; + } + + void SetNodeAt(size_t index, EACGBaseNode *val) { + nodes[index] = val; + } + + const MapleVector &GetFuncArgNodes() const { + return funcArgNodes; + } + + const MapleMap*> &GetCallSite2Nodes() const { + return callSite2Nodes; + } + + void InitGlobalNode(); + void AddMaps2Object(EACGObjectNode *caller, EACGObjectNode *callee); + void UpdateExprOfNode(EACGBaseNode &node, MeExpr *me); + void UpdateExprOfGlobalRef(MeExpr *me); + void PropogateEAStatus(); + bool MergeCG(MapleVector &caller, const MapleVector *callee); + void TrimGlobalNode() const; + void UpdateEACGFromCaller(const MapleVector &callerCallSiteArg, + const MapleVector &calleeFuncArg); + void DumpDotFile(const IRMap *irMap, bool dumpPt, MapleVector *dumpVec = nullptr); + void DeleteEACG() const; + void RestoreStatus(bool old); + void CountObjEAStatus() const; + + const std::string &GetFunctionName() const { + return GlobalTables::GetStrTable().GetStringFromStrIdx(funcStIdx); + } + + private: + MIRModule *mirModule; + MapleAllocator *alloc; + MapleVector nodes; + MapleMap*> expr2Nodes; + // this vector contain func arg nodes first in declaration order and the last is return node + MapleVector funcArgNodes; + MapleMap*> callSite2Nodes; + GStrIdx funcStIdx; + bool hasUpdated; + bool needConv; + bool imported; + int exprIdMax; + EACGObjectNode *globalObj; + EACGRefNode *globalRef; + EACGFieldNode *globalField; + // this is used as a tmp varible for merge cg + std::map> callee2Caller; + void CheckArgNodeOrder(MapleVector &funcArgV); + void UpdateCallerNodes(const MapleVector &caller, const MapleVector &callee); + void UpdateCallerRetNode(MapleVector &caller, const MapleVector &callee); + void UpdateCallerEdges(); + void UpdateCallerEdgesInternal(EACGObjectNode *node1, uint32 fieldID, EACGObjectNode *node2); + void UpdateNodes(const EACGBaseNode &actualInCallee, EACGBaseNode &actualInCaller, bool firstTime); + void UpdateCallerWithCallee(EACGObjectNode &objInCaller, const EACGObjectNode &objInCallee, bool firstTime); + + void SetCGUpdateFlag() { + hasUpdated = true; + } +}; + +class EACGBaseNode { + public: + friend class BinaryMplExport; + friend class BinaryMplImport; + friend class EACGObjectNode; + friend class EACGFieldNode; + friend class EACGActualNode; + friend class EACGRefNode; + friend class EACGPointerNode; + friend class EAConnectionGraph; + + EACGBaseNode(MIRModule *m, MapleAllocator *a, NodeKind nk, EAConnectionGraph *ec) + : locInfo(nullptr), mirModule(m), alloc(a), kind(nk), meExpr(nullptr), eaStatus(kNoEscape), id(0), eaCG(ec) {} + + EACGBaseNode(MIRModule *m, MapleAllocator *a, NodeKind nk, EAConnectionGraph &ec, MeExpr *expr, EAStatus initialEas, + int i) + : locInfo(nullptr), mirModule(m), alloc(a), kind(nk), meExpr(expr), eaStatus(initialEas), id(i), eaCG(&ec) { + ec.SetCGUpdateFlag(); + } + + virtual ~EACGBaseNode() = default; + + virtual bool IsFieldNode() const { + return kind == kFieldNode; + } + + virtual bool IsObjectNode() const { + return kind == kObejectNode; + } + + virtual bool IsReferenceNode() const { + return kind == kReferenceNode; + } + + virtual bool IsActualNode() const { + return kind == kActualNode; + } + + virtual bool IsPointerNode() const { + return kind == kPointerNode; + } + + virtual NodeKind GetNodeKind() const { + return kind; + } + + virtual const MeExpr *GetMeExpr() const { + return meExpr; + } + + virtual void SetMeExpr(MeExpr &newExpr) { + if (IsFieldNode() && newExpr.GetMeOp() != kMeOpIvar && newExpr.GetMeOp() != kMeOpOp) { + CHECK_FATAL(false, "must be kMeOpIvar or kMeOpOp"); + } else if (IsReferenceNode() == true && newExpr.GetMeOp() != kMeOpVar && newExpr.GetMeOp() != kMeOpReg && + newExpr.GetMeOp() != kMeOpAddrof && newExpr.GetMeOp() != kMeOpConststr) { + CHECK_FATAL(false, "must be kMeOpVar, kMeOpReg, kMeOpAddrof or kMeOpConststr"); + } + meExpr = &newExpr; + } + + const std::set &GetPointsToSet() const { + CHECK_FATAL(!IsPointerNode(), "must be pointer node"); + return pointsTo; + }; + + virtual void PropagateEAStatusForNode(const EACGBaseNode*) const; + + virtual bool AddOutNode(EACGBaseNode &newOut); + + virtual EAStatus GetEAStatus() const { + return eaStatus; + } + + virtual void SetEAStatus(EAStatus status) { + this->eaStatus = status; + } + + virtual const std::set &GetInSet() const { + return in; + } + + virtual void InsertInSet(EACGBaseNode *val) { + (void)in.insert(val); + } + + virtual const std::set &GetOutSet() const { + CHECK_FATAL(IsActualNode(), "must be actual node"); + return out; + } + + virtual void InsertOutSet(EACGBaseNode *val) { + (void)out.insert(val); + } + + virtual bool UpdateEAStatus(EAStatus newEas) { + if (newEas > eaStatus) { + eaStatus = newEas; + PropagateEAStatusForNode(this); + eaCG->SetCGUpdateFlag(); + return true; + } + return false; + } + + virtual std::string GetName(const IRMap *irMap) const; + virtual bool UpdatePointsTo(const std::set &cPointsTo); + virtual void GetNodeFormatInDot(std::string &label, std::string &color) const; + + virtual void DumpDotFile(std::ostream&, std::map&, bool, const IRMap *irMap = nullptr) = 0; + + virtual void CheckAllConnectionInNodes(); + + bool IsBelongTo(const EAConnectionGraph *cg) const { + return this->eaCG == cg; + } + + const EAConnectionGraph *GetEACG() const { + return eaCG; + } + + EAConnectionGraph *GetEACG() { + return eaCG; + } + + void SetEACG(EAConnectionGraph *cg) { + this->eaCG = cg; + } + + void SetID(int id) { + this->id = id; + } + + bool CanIgnoreRC() const; + + protected: + Location *locInfo; + MIRModule *mirModule; + MapleAllocator *alloc; + NodeKind kind; + MeExpr *meExpr; + EAStatus eaStatus; + int id; + // OBJ<->Field will not in following Set + std::set in; + std::set out; + std::set pointsTo; + EAConnectionGraph *eaCG; + + virtual bool ReplaceByGlobalNode() { + CHECK_FATAL(false, "impossible"); + return false; + } +}; + +class EACGPointerNode : public EACGBaseNode { + public: + friend class BinaryMplExport; + friend class BinaryMplImport; + EACGPointerNode(MIRModule *md, MapleAllocator *alloc, EAConnectionGraph *ec) + : EACGBaseNode(md, alloc, kPointerNode, ec), indirectLevel(0) {} + + EACGPointerNode(MIRModule *md, MapleAllocator *alloc, EAConnectionGraph &ec, MeExpr *expr, EAStatus initialEas, int i, + int indirectL) + : EACGBaseNode(md, alloc, kPointerNode, ec, expr, initialEas, i), indirectLevel(indirectL) {}; + ~EACGPointerNode() = default; + + void SetLocation(Location *loc) { + this->locInfo = loc; + } + + int GetIndirectLevel() const { + return indirectLevel; + } + + bool AddOutNode(EACGBaseNode &newOut) override { + if (indirectLevel == 1) { + CHECK_FATAL(!newOut.IsPointerNode(), "must be pointer node"); + (void)pointingTo.insert(&newOut); + (void)out.insert(&newOut); + (void)newOut.in.insert(this); + } else { + pointingTo.insert(&newOut); + CHECK_FATAL(pointingTo.size() == 1, "the size must be one"); + CHECK_FATAL(newOut.IsPointerNode(), "must be pointer node"); + CHECK_FATAL((indirectLevel - static_cast(newOut).GetIndirectLevel()) == 1, "must be one"); + (void)out.insert(&newOut); + (void)newOut.in.insert(this); + } + return false; + } + + const std::set &GetPointingTo() const { + return pointingTo; + } + + bool UpdatePointsTo(const std::set&) override { + CHECK_FATAL(false, "impossible to update PointsTo"); + return true; + }; + + void PropagateEAStatusForNode(const EACGBaseNode*) const override { + CHECK_FATAL(false, "impossible to propagate EA status for node"); + } + + void DumpDotFile(std::ostream &fout, std::map &dumped, bool dumpPt, + const IRMap *irMap = nullptr) override; + void CheckAllConnectionInNodes() override {} + + private: + int indirectLevel; + std::set pointingTo; + bool ReplaceByGlobalNode() override { + CHECK_FATAL(false, "impossible to replace by global node"); + return true; + } +}; + +class EACGObjectNode : public EACGBaseNode { + public: + friend class EACGFieldNode; + friend class BinaryMplExport; + friend class BinaryMplImport; + EACGObjectNode(MIRModule *md, MapleAllocator *alloc, EAConnectionGraph *ec) + : EACGBaseNode(md, alloc, kObejectNode, ec), rcOperations(0), ignorRC(false), isPhantom(false) {} + + EACGObjectNode(MIRModule *md, MapleAllocator *alloc, EAConnectionGraph &ec, MeExpr *expr, EAStatus initialEas, int i, + bool isPh) + : EACGBaseNode(md, alloc, kObejectNode, ec, expr, initialEas, i), rcOperations(0), ignorRC(false), + isPhantom(isPh) { + (void)pointsBy.insert(this); + (void)pointsTo.insert(this); + }; + ~EACGObjectNode() = default; + bool IsPhantom() const { + return isPhantom == true; + }; + + void SetLocation(Location *loc) { + this->locInfo = loc; + } + + const std::map &GetFieldNodeMap() const { + return fieldNodes; + } + + EACGFieldNode *GetFieldNodeFromIdx(FieldID fId) { + if (fieldNodes.find(-1) != fieldNodes.end()) { // -1 expresses global + return fieldNodes[-1]; + } + if (fieldNodes.find(fId) == fieldNodes.end()) { + return nullptr; + } + return fieldNodes[fId]; + } + + bool AddOutNode(EACGBaseNode &newOut) override; + bool UpdatePointsTo(const std::set&) override { + CHECK_FATAL(false, "impossible"); + return true; + }; + + bool IsPointedByFieldNode() const; + void PropagateEAStatusForNode(const EACGBaseNode *subRoot) const override; + void DumpDotFile(std::ostream &fout, std::map &dumped, bool dumpPt, + const IRMap *irMap = nullptr) override; + void CheckAllConnectionInNodes() override; + + void Insert2PointsBy(EACGBaseNode *node) { + (void)pointsBy.insert(node); + } + + void EraseNodeFromPointsBy(EACGBaseNode *node) { + pointsBy.erase(node); + } + + void IncresRCOperations() { + ++rcOperations; + } + + void IncresRCOperations(int num) { + rcOperations += num; + } + + int GetRCOperations() const { + return rcOperations; + } + + bool GetIgnorRC() const { + return ignorRC; + } + + void SetIgnorRC(bool ignore) { + ignorRC = ignore; + } + + private: + std::set pointsBy; + int rcOperations; + bool ignorRC; + bool isPhantom; + std::map fieldNodes; + bool ReplaceByGlobalNode() override; +}; + +class EACGRefNode : public EACGBaseNode { + public: + friend class BinaryMplExport; + friend class BinaryMplImport; + EACGRefNode(MIRModule *md, MapleAllocator *alloc, EAConnectionGraph *ec) + : EACGBaseNode(md, alloc, kReferenceNode, ec), isStaticField(false), sym(nullptr), version(0) {} + + EACGRefNode(MIRModule *md, MapleAllocator *alloc, EAConnectionGraph &ec, MeExpr *expr, EAStatus initialEas, int i, + bool isS = false) + : EACGBaseNode(md, alloc, kReferenceNode, ec, expr, initialEas, i), + isStaticField(isS), + sym(nullptr), + version(0) {}; + ~EACGRefNode() = default; + bool IsStaticRef() { + return isStaticField == true; + }; + void SetSymbolAndVersion(MIRSymbol *mirSym, int versionIdx) { + if (sym != nullptr) { + CHECK_FATAL(sym == mirSym, "must be sym"); + CHECK_FATAL(versionIdx == version, "must be version "); + } + sym = mirSym; + version = versionIdx; + }; + + void DumpDotFile(std::ostream &fout, std::map &dumped, bool dumpPt, + const IRMap *irMap = nullptr); + + private: + bool isStaticField; + MIRSymbol *sym; + int version; + bool ReplaceByGlobalNode(); +}; +class EACGFieldNode : public EACGBaseNode { + public: + friend class BinaryMplExport; + friend class BinaryMplImport; + friend class EACGObjectNode; + EACGFieldNode(MIRModule *md, MapleAllocator *alloc, EAConnectionGraph *ec) + : EACGBaseNode(md, alloc, kFieldNode, ec), + fieldID(0), + isPhantom(false), + sym(nullptr), + version(0), + mirFieldId(0) {} + + EACGFieldNode(MIRModule *md, MapleAllocator *alloc, EAConnectionGraph &ec, MeExpr *expr, EAStatus initialEas, int i, + FieldID fId, EACGObjectNode *bt, bool isPh) + : EACGBaseNode(md, alloc, kFieldNode, ec, expr, initialEas, i), + fieldID(fId), + isPhantom(isPh), + sym(nullptr), + version(0), + mirFieldId(0) { + bt->fieldNodes[fieldID] = this; + (void)belongsTo.insert(bt); + }; + + ~EACGFieldNode() = default; + + FieldID GetFieldID() const { + return fieldID; + }; + + void SetFieldID(FieldID id) { + fieldID = id; + } + + bool IsPhantom() const { + return isPhantom; + } + + const std::set &GetBelongsToObj() const { + return belongsTo; + } + + void AddBelongTo(EACGObjectNode *newObj) { + (void)belongsTo.insert(newObj); + } + + void SetSymbolAndVersion(MIRSymbol *mirSym, int versionIdx, FieldID fID) { + if (sym != nullptr) { + CHECK_FATAL(sym == mirSym, "must be mirSym"); + CHECK_FATAL(version == versionIdx, "must be version"); + CHECK_FATAL(mirFieldId == fID, "must be mir FieldId"); + } + sym = mirSym; + version = versionIdx; + mirFieldId = fID; + }; + + void DumpDotFile(std::ostream &fout, std::map &dumped, bool dumpPt, + const IRMap *irMap = nullptr); + + private: + FieldID fieldID; + std::set belongsTo; + bool isPhantom; + MIRSymbol *sym; + int version; + FieldID mirFieldId; + bool ReplaceByGlobalNode(); +}; + +class EACGActualNode : public EACGBaseNode { + public: + friend class BinaryMplExport; + friend class BinaryMplImport; + EACGActualNode(MIRModule *md, MapleAllocator *alloc, EAConnectionGraph *ec) + : EACGBaseNode(md, alloc, kActualNode, ec), isReturn(false), isPhantom(false), argIdx(0), callSiteInfo(0) {}; + EACGActualNode(MIRModule *md, MapleAllocator *alloc, EAConnectionGraph &ec, MeExpr *expr, EAStatus initialEas, int i, + bool isR, bool isPh, uint8 aI, uint32 callSite) + : EACGBaseNode(md, alloc, kActualNode, ec, expr, initialEas, i), + isReturn(isR), + isPhantom(isPh), + argIdx(aI), + callSiteInfo(callSite) {}; + ~EACGActualNode() = default; + + bool IsReturn() const { + return isReturn; + }; + + bool IsPhantom() const { + return isPhantom; + }; + + uint32 GetArgIndex() const { + return argIdx; + }; + + uint32 GetCallSite() const { + return callSiteInfo; + } + + void DumpDotFile(std::ostream &fout, std::map &dumped, bool dumpPt, + const IRMap *irMap = nullptr); + + private: + bool isReturn; + bool isPhantom; + uint8 argIdx; + uint32 callSiteInfo; + bool ReplaceByGlobalNode(); +}; +} // namespace maple +#endif diff --git a/src/mapleall/maple_ipa/include/inline.h b/src/mapleall/maple_ipa/include/inline.h new file mode 100644 index 0000000000000000000000000000000000000000..922e599323eb682fce9c77ebc708cf39d81386c0 --- /dev/null +++ b/src/mapleall/maple_ipa/include/inline.h @@ -0,0 +1,174 @@ +/* + * Copyright (c) [2019-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MAPLE_IPA_INCLUDE_INLINE_H +#define MAPLE_IPA_INCLUDE_INLINE_H +#include "mir_parser.h" +#include "mir_function.h" +#include "opcode_info.h" +#include "mir_builder.h" +#include "mempool.h" +#include "mempool_allocator.h" +#include "call_graph.h" +#include "module_phase.h" +#include "string_utils.h" +#include "me_option.h" + +namespace maple { +constexpr char kSpaceTabStr[] = " \t"; +constexpr char kCommentsignStr[] = "#"; +constexpr char kHyphenStr[] = "-"; +constexpr char kAppointStr[] = "->"; +constexpr char kUnderlineStr[] = "_"; +constexpr char kVerticalLineStr[] = "|"; +constexpr char kNumberZeroStr[] = "0"; +constexpr char kReturnlocStr[] = "return_loc_"; +constexpr char kThisStr[] = "_this"; +constexpr char kDalvikSystemStr[] = "Ldalvik_2Fsystem_2FVMStack_3B_7C"; +constexpr char kJavaLangThreadStr[] = "Ljava_2Flang_2FThread_3B_7C"; +constexpr char kReflectionClassStr[] = "Ljava_2Flang_2Freflect"; +constexpr char kJavaLangClassesStr[] = "Ljava_2Flang_2FClass_3B_7C"; +constexpr char kJavaLangReferenceStr[] = "Ljava_2Flang_2Fref_2FReference_3B_7C"; +constexpr char kInlineBeginComment[] = "inlining begin: FUNC "; +constexpr char kInlineEndComment[] = "inlining end: FUNC "; +constexpr char kSecondInlineBeginComment[] = "second inlining begin: FUNC "; +constexpr char kSecondInlineEndComment[] = "second inlining end: FUNC "; + +struct InlineResult { + bool canInline; + std::string reason; + + InlineResult(bool canInline, const std::string &reason) : canInline(canInline), reason(reason) {} + ~InlineResult() = default; +}; + +enum FuncCostResultType { + kNotAllowedNode, + kFuncBodyTooBig, + kSmallFuncBody +}; + +enum ThresholdType { + kSmallFuncThreshold, + kHotFuncThreshold, + kRecursiveFuncThreshold, + kHotAndRecursiveFuncThreshold +}; + +class MInline { + public: + MInline(MIRModule &mod, MemPool *memPool, KlassHierarchy *kh = nullptr, CallGraph *cg = nullptr) + : alloc(memPool), + module(mod), + builder(*mod.GetMIRBuilder()), + inlineTimesMap(std::less(), alloc.Adapter()), + recursiveFuncToInlineLevel(alloc.Adapter()), + funcToCostMap(alloc.Adapter()), + klassHierarchy(kh), + cg(cg), + excludedCaller(alloc.Adapter()), + excludedCallee(alloc.Adapter()), + hardCodedCallee(alloc.Adapter()), + rcWhiteList(alloc.Adapter()), + inlineListCallee(alloc.Adapter()), + noInlineListCallee(alloc.Adapter()) { + Init(); + }; + bool PerformInline(MIRFunction&, BlockNode &enclosingBlk, CallNode&, MIRFunction&); + virtual void Inline(); + void CleanupInline(); + virtual ~MInline() = default; + + protected: + MapleAllocator alloc; + MIRModule &module; + MIRBuilder &builder; + MapleMap inlineTimesMap; + // For recursive inline, will dup the current function body before first recursive inline. + BlockNode *currFuncBody = nullptr; + // store recursive function's inlining levels, and allow inline 4 levels at most. + MapleMap recursiveFuncToInlineLevel; + MapleMap funcToCostMap; // save the cost of calculated func to reduce the amount of calculation + KlassHierarchy *klassHierarchy; + CallGraph *cg; + + private: + void Init(); + void InitParams(); + void InitProfile() const; + void InitExcludedCaller(); + void InitExcludedCallee(); + void InitRCWhiteList(); + void ApplyInlineListInfo(const std::string &list, MapleMap*> &listCallee); + uint32 RenameSymbols(MIRFunction&, const MIRFunction&, uint32) const; + void ReplaceSymbols(BaseNode*, uint32, const std::unordered_map&) const; + uint32 RenameLabels(MIRFunction&, const MIRFunction&, uint32) const; + void ReplaceLabels(BaseNode&, uint32) const; + uint32 RenamePregs(const MIRFunction&, const MIRFunction&, std::unordered_map&) const; + void ReplacePregs(BaseNode*, std::unordered_map&) const; + LabelIdx CreateReturnLabel(MIRFunction&, const MIRFunction&, uint32) const; + FuncCostResultType GetFuncCost(const MIRFunction&, const BaseNode&, uint32&, uint32) const; + bool FuncInlinable(const MIRFunction&) const; + bool IsSafeToInline(const MIRFunction*, const CallNode&) const; + bool IsHotCallSite(const MIRFunction &caller, const MIRFunction &callee, const CallNode &callStmt) const; + InlineResult AnalyzeCallsite(const MIRFunction &caller, MIRFunction &callee, const CallNode &callStmt); + InlineResult AnalyzeCallee(const MIRFunction &caller, MIRFunction &callee, const CallNode &callStmt); + virtual bool CanInline(CGNode*, std::unordered_map&) { + return false; + } + + bool CheckCalleeAndInline(MIRFunction*, BlockNode *enclosingBlk, CallNode*, MIRFunction*); + void InlineCalls(const CGNode&); + void InlineCallsBlock(MIRFunction&, BlockNode&, BaseNode&, bool&); + void InlineCallsBlockInternal(MIRFunction&, BlockNode&, BaseNode&, bool&); + GotoNode *UpdateReturnStmts(const MIRFunction&, BlockNode&, LabelIdx, const CallReturnVector&, int&) const; + void CollectMustInlineFuncs(); + void ComputeTotalSize(); + void MarkSymbolUsed(const StIdx&) const; + void MarkUsedSymbols(const BaseNode*) const; + void MarkUnInlinableFunction() const; + bool ResolveNestedTryBlock(BlockNode&, TryNode&, const StmtNode*) const; + void RecordRealCaller(MIRFunction&, const MIRFunction&); + void SearchCallee(const MIRFunction&, const BaseNode&, std::set&) const; + uint64 totalSize = 0; + bool dumpDetail = false; + std::string dumpFunc = ""; + MapleSet excludedCaller; + MapleSet excludedCallee; + MapleSet hardCodedCallee; + MapleSet rcWhiteList; + MapleMap*> inlineListCallee; + MapleMap*> noInlineListCallee; + uint32 smallFuncThreshold = 0; + uint32 hotFuncThreshold = 0; + uint32 recursiveFuncThreshold = 0; + bool inlineWithProfile = false; + std::string inlineFuncList; + std::string noInlineFuncList; + uint32 maxInlineLevel = 4; //for recursive function, allow inline 4 levels at most. +}; + +class DoInline : public ModulePhase { + public: + explicit DoInline(ModulePhaseID id) : ModulePhase(id) {} + + AnalysisResult *Run(MIRModule *module, ModuleResultMgr *mgr) override; + std::string PhaseName() const override { + return "inline"; + } + + ~DoInline() = default; +}; +} // namespace maple +#endif // MAPLE_IPA_INCLUDE_INLINE_H diff --git a/src/mapleall/maple_ipa/include/interleaved_manager.h b/src/mapleall/maple_ipa/include/interleaved_manager.h index 16935eeaa5226cae687ab353fac93ea80d80ff8e..811849dd0caa5b245af9e0006efa84c63981cc3c 100644 --- a/src/mapleall/maple_ipa/include/interleaved_manager.h +++ b/src/mapleall/maple_ipa/include/interleaved_manager.h @@ -55,6 +55,8 @@ class InterleavedManager { void Run(); void RunMeOptimize(MeFuncPhaseManager &fpm); const PhaseManager *GetSupportPhaseManager(const std::string &phase); + void AddIPAPhases(std::vector &phases, bool timePhases = false, bool genMpl = false); + void IPARun(MeFuncPhaseManager&); long GetEmitVtableImplTime() const { return emitVtableImplMplTime; } diff --git a/src/mapleall/maple_ipa/include/ipa_escape_analysis.h b/src/mapleall/maple_ipa/include/ipa_escape_analysis.h new file mode 100644 index 0000000000000000000000000000000000000000..df6f3facf183b3187a6dc61c8d80a1c187030360 --- /dev/null +++ b/src/mapleall/maple_ipa/include/ipa_escape_analysis.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) [2019] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MAPLEIPA_INCLUDE_IPAESCAPEANALYSIS_H +#define MAPLEIPA_INCLUDE_IPAESCAPEANALYSIS_H + +#include +#include "class_hierarchy.h" +#include "call_graph.h" +#include "irmap.h" +#include "me_function.h" +#include "ea_connection_graph.h" +#include "intrinsics.h" + +namespace maple { +class IPAEscapeAnalysis { + public: + static constexpr int kCalleeCandidateLimit = 600; + static constexpr int kFuncInSCCLimit = 200000; + static constexpr int kSCCConvergenceLimit = 20; + static constexpr int kCalleeNodeLimit = 100000; + static constexpr int kRCOperLB = 0; + static constexpr bool kDebug = false; + + IPAEscapeAnalysis(KlassHierarchy *khTmp, IRMap *irMapTmp, MeFunction *funcTmp, MemPool *mp, CallGraph *pcgTmp) + : kh(khTmp), + irMap(irMapTmp), + ssaTab(&irMap->GetSSATab()), + mirModule(&irMapTmp->GetMIRModule()), + func(funcTmp), + eaCG(func->GetMirFunc()->GetEACG()), + pcg(pcgTmp), + allocator(mp), + cgChangedInSCC(false), + tempCount(0), + retVar(nullptr) {} + ~IPAEscapeAnalysis() = default; + void ConstructConnGraph(); + void DoOptimization(); + + private: + TyIdx GetAggElemType(const MIRType &aggregate) const; + bool IsSpecialEscapedObj(const MeExpr &alloc) const; + EACGRefNode *GetOrCreateCGRefNodeForVar(VarMeExpr &var, bool createObjNode = false); + EACGRefNode *GetOrCreateCGRefNodeForAddrof(AddrofMeExpr &var, bool createObjNode = false); + EACGRefNode *GetOrCreateCGRefNodeForReg(RegMeExpr ®, bool createObjNode = false); + EACGRefNode *GetOrCreateCGRefNodeForVarOrReg(MeExpr &var, bool createObjNode = false); + void GetArrayBaseNodeForReg(std::vector &nodes, RegMeExpr ®Var, MeStmt &stmt); + void GetOrCreateCGFieldNodeForIvar(std::vector &fieldNodes, IvarMeExpr &ivar, MeStmt &stmt, + bool createObjNode); + void GetOrCreateCGFieldNodeForIAddrof(std::vector &fieldNodes, OpMeExpr &expr, MeStmt &stmt, + bool createObjNode); + EACGObjectNode *GetOrCreateCGObjNode(MeExpr *expr, MeStmt *stmt = nullptr, EAStatus easOfPhanObj = kNoEscape); + void GetCGNodeForMeExpr(std::vector &nodes, MeExpr &expr, MeStmt &stmt, bool createObjNode); + void CollectDefStmtForReg(std::set &visited, std::set &defStmts, RegMeExpr ®Var); + void UpdateEscConnGraphWithStmt(MeStmt &stmt); + void UpdateEscConnGraphWithPhi(const BB &bb); + void HandleParaAtFuncEntry(); + void HandleParaAtCallSite(uint32 callInfo, CallMeStmt &call); + void HandleSingleCallee(CallMeStmt &callMeStmt); + bool HandleSpecialCallee(CallMeStmt *callMeStmt); + void HandleMultiCallees(const CallMeStmt &callMeStmt); + EAConnectionGraph *GetEAConnectionGraph(MIRFunction &function) const; + void ProcessNoAndRetEscObj(); + void ProcessRetStmt(); + VarMeExpr *CreateEATempVarWithName(const std::string &name); + VarMeExpr *CreateEATempVar(); + VarMeExpr *GetOrCreateEARetTempVar(); + VarMeExpr *CreateEATempVarMeExpr(OriginalSt &ost); + OriginalSt *CreateEATempOstWithName(const std::string &name); + OriginalSt *CreateEATempOst(); + OriginalSt *CreateEARetTempOst(); + VarMeExpr *GetOrCreateEARetTempVarMeExpr(OriginalSt &ost); + void CountObjRCOperations(); + void DeleteRedundantRC(); + + KlassHierarchy *kh; + IRMap *irMap; + SSATab *ssaTab; + MIRModule *mirModule; + MeFunction *func; + EAConnectionGraph *eaCG; + CallGraph *pcg; + MapleAllocator allocator; + bool cgChangedInSCC; + uint32 tempCount; + std::vector noAndRetEscObj; + VarMeExpr *retVar; + std::vector noAndRetEscOst; + std::vector gcStmts; +}; +} // namespace maple +#endif diff --git a/src/mapleall/maple_ipa/include/ipa_option.h b/src/mapleall/maple_ipa/include/ipa_option.h new file mode 100644 index 0000000000000000000000000000000000000000..9854281b33c7d89ca30330a7e185536969b71c62 --- /dev/null +++ b/src/mapleall/maple_ipa/include/ipa_option.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MAPLE_IPA_OPTION_H +#define MAPLE_IPA_OPTION_H +#include +#include +#include +#include "mir_parser.h" +#include "opcode_info.h" +#include "me_cfg.h" +#include "module_phase_manager.h" +#include "option_parser.h" +#include "interleaved_manager.h" +#include "option.h" +#include "inline.h" +#include "call_graph.h" + +namespace maple { +class IpaOption : public maple::MapleDriverOptionBase { + public: + static IpaOption &GetInstance(); + + ~IpaOption() = default; + + bool SolveOptions(const mapleOption::OptionParser &optionParser) const; + + bool ParseCmdline(int argc, char **argv, std::vector &fileNames); + + private: + IpaOption(); +}; +} // namespace maple +#endif // MAPLE_IPA_OPTION_H \ No newline at end of file diff --git a/src/mapleall/maple_ipa/include/method_replace.h b/src/mapleall/maple_ipa/include/method_replace.h new file mode 100644 index 0000000000000000000000000000000000000000..652396e74cf550fbab556cc2055a5f325ed97982 --- /dev/null +++ b/src/mapleall/maple_ipa/include/method_replace.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) [2019] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MAPLEIPA_INCLUDE_METHODREPLACE_H +#define MAPLEIPA_INCLUDE_METHODREPLACE_H +#include "mir_module.h" +#include "mir_function.h" +#include "mir_builder.h" +#include "mempool.h" +#include "mempool_allocator.h" +#include "module_phase.h" + +namespace maple { +using StrStrMap = std::unordered_map; +using ReplaceMethodMapType = std::unordered_map; + +class MethodReplace : public AnalysisResult { + public: + MethodReplace(MIRModule *mod, MemPool *mp, MIRBuilder &builder) + : AnalysisResult(mp), mirModule(mod), allocator(mp), mBuilder(builder) {} + + ~MethodReplace() = default; + + void DoMethodReplace(); + void Init(); + + private: + MIRModule *mirModule; + MapleAllocator allocator; + MIRBuilder &mBuilder; + ReplaceMethodMapType replaceMethodMap; + + void InsertRecord(const std::string &caller, const std::string &origCallee, const std::string &newCallee); + void FindCalleeAndReplace(MIRFunction &callerFunc, StrStrMap &calleeMap) const; +}; + +class DoMethodReplace : public ModulePhase { + public: + explicit DoMethodReplace(ModulePhaseID id) : ModulePhase(id) {} + + ~DoMethodReplace() = default; + + AnalysisResult *Run(MIRModule *module, ModuleResultMgr *mgr) override; + + std::string PhaseName() const override { + return "methodreplace"; + } +}; +} // namespace maple +#endif \ No newline at end of file diff --git a/src/mapleall/maple_ipa/include/module_phases.def b/src/mapleall/maple_ipa/include/module_phases.def index e0681fd0c2becf5fb4285d49ae7c56d37ffdd35a..0fa015a8e3d258acf2450c2574172b0f4b837b31 100644 --- a/src/mapleall/maple_ipa/include/module_phases.def +++ b/src/mapleall/maple_ipa/include/module_phases.def @@ -25,6 +25,7 @@ MODAPHASE(MoPhase_REFLECTIONANALYSIS, DoReflectionAnalysis) MODAPHASE(MoPhase_ANNOTATIONANALYSIS, DoAnnotationAnalysis) MODTPHASE(MoPhase_VTABLEIMPL, DoVtableImpl) MODTPHASE(MoPhase_JAVAINTRNLOWERING, DoJavaIntrnLowering) +MODTPHASE(MoPhase_BARRIERINSERTION, BarrierInsertion) MODTPHASE(MoPhase_JAVAEHLOWER, JavaEHLowererPhase) MODTPHASE(MoPhase_MUIDREPLACEMENT, DoMUIDReplacement) MODTPHASE(MoPhase_CHECKCASTGENERATION, DoCheckCastGeneration) diff --git a/src/mapleall/maple_ipa/include/mrt_info.def b/src/mapleall/maple_ipa/include/mrt_info.def new file mode 100644 index 0000000000000000000000000000000000000000..e8bd87cf7da66941db95af8c79fab90745d78d47 --- /dev/null +++ b/src/mapleall/maple_ipa/include/mrt_info.def @@ -0,0 +1,639 @@ +/* + * Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +// pure, defArg, defGlobal, retGlobal, throwEh, retArg, defPrivate, name +{ true, false, false, false, false, false, false, "MCC_GetOrInsertLiteral"}, +{ true, false, false, false, false, false, false, "MCC_StringAppend_StringString"}, +{ true, false, false, false, false, false, false, "MCC_CStrToJStr"}, +{ true, false, false, false, false, false, false, "MCC_String_Equals_NotallCompress"}, +{ true, false, false, false, false, false, false, "MCC_StringAppend"}, +{ true, false, false, false, false, false, false, "MCC_StringAppend_StringInt"}, +{ true, false, false, false, false, false, false, "MCC_StringAppend_StringJcharString"}, +{ true, false, false, false, true, false, false, "MCC_ThrowStringIndexOutOfBoundsException"}, +{ true, false, false, false, true, false, false, "Native_java_lang_String_charAt__I"}, +{ false, true, false, false, true, false, false, "Native_java_lang_String_getCharsNoCheck__II_3CI"}, +{ true, false, false, false, true, false, false, "Native_java_lang_String_toCharArray__"}, +{ true, false, false, false, true, false, false, "Native_java_lang_String_fastSubstring__II"}, +{ true, false, false, false, true, false, false, "Native_java_lang_String_compareTo__Ljava_lang_String_2"}, +{ true, false, false, false, true, false, false, "Native_java_lang_String_intern__"}, +{ true, false, false, false, true, false, false, "Native_java_lang_String_doReplace__CC"}, +{ true, false, false, false, true, false, false, "Native_java_lang_String_concat__Ljava_lang_String_2"}, +{ true, false, false, false, true, false, false, "Native_java_lang_String_fastIndexOf__II"}, +{ true, false, false, false, true, false, false, "Native_java_lang_Object_clone_Ljava_lang_Object__"}, +{ false, false, false, true, true, false, false, "Native_Thread_currentThread"}, + +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CisProxy_7C_28_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetName_7C_28_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetTypeName_7C_28_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7Ccast_7C_28Ljava_2Flang_2FObject_3B_29Ljava_2Flang_2FObject_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetPrimitiveClass_7C_28Ljava_2Flang_2FString_3B_29Ljava_2Flang_2FClass_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetComponentType_7C_28_29Ljava_2Flang_2FClass_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetDeclaredField_7C_28Ljava_2Flang_2FString_3B_29Ljava_2Flang_2Freflect_2FField_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CtoString_7C_28_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetGenericInterfaces_7C_28_29ALjava_2Flang_2Freflect_2FType_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CisInstance_7C_28Ljava_2Flang_2FObject_3B_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CforName_7C_28Ljava_2Flang_2FString_3B_29Ljava_2Flang_2FClass_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CforName_7C_28Ljava_2Flang_2FString_3BZLjava_2Flang_2FClassLoader_3B_29Ljava_2Flang_2FClass_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CisAssignableFrom_7C_28Ljava_2Flang_2FClass_3B_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetModifiers_7C_28_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetConstructor_7C_28ALjava_2Flang_2FClass_3B_29Ljava_2Flang_2Freflect_2FConstructor_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetConstructors_7C_28_29ALjava_2Flang_2Freflect_2FConstructor_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CisPrimitive_7C_28_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CisArray_7C_28_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetInterfaces_7C_28_29ALjava_2Flang_2FClass_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetSimpleName_7C_28_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetSuperclass_7C_28_29Ljava_2Flang_2FClass_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetDeclaredMethods_7C_28_29ALjava_2Flang_2Freflect_2FMethod_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetDeclaredFields_7C_28_29ALjava_2Flang_2Freflect_2FField_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetDeclaredConstructors_7C_28_29ALjava_2Flang_2Freflect_2FConstructor_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetDeclaredConstructor_7C_28ALjava_2Flang_2FClass_3B_29Ljava_2Flang_2Freflect_2FConstructor_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetDeclaredMethod_7C_28Ljava_2Flang_2FString_3BALjava_2Flang_2FClass_3B_29Ljava_2Flang_2Freflect_2FMethod_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CisInterface_7C_28_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetCanonicalName_7C_28_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CisEnum_7C_28_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetAnnotation_7C_28Ljava_2Flang_2FClass_3B_29Ljava_2Flang_2Fannotation_2FAnnotation_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetAnnotations_7C_28_29ALjava_2Flang_2Fannotation_2FAnnotation_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetAnnotationsByType_7C_28Ljava_2Flang_2FClass_3B_29ALjava_2Flang_2Fannotation_2FAnnotation_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetDeclaredAnnotation_7C_28Ljava_2Flang_2FClass_3B_29Ljava_2Flang_2Fannotation_2FAnnotation_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetDeclaredAnnotations_7C_28_29ALjava_2Flang_2Fannotation_2FAnnotation_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CcannotCastMsg_7C_28Ljava_2Flang_2FObject_3B_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CclassForName_7C_28Ljava_2Flang_2FString_3BZLjava_2Flang_2FClassLoader_3B_29Ljava_2Flang_2FClass_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CclassNameImpliesTopLevel_7C_28_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CfindInterfaceMethod_7C_28Ljava_2Flang_2FString_3BALjava_2Flang_2FClass_3B_29Ljava_2Flang_2Freflect_2FMethod_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetPublicMethodRecursive_7C_28Ljava_2Flang_2FString_3BALjava_2Flang_2FClass_3B_29Ljava_2Flang_2Freflect_2FMethod_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetConstructor0_7C_28ALjava_2Flang_2FClass_3BI_29Ljava_2Flang_2Freflect_2FConstructor_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetDeclaredConstructorInternal_7C_28ALjava_2Flang_2FClass_3B_29Ljava_2Flang_2Freflect_2FConstructor_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetDeclaredConstructorsInternal_7C_28Z_29ALjava_2Flang_2Freflect_2FConstructor_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetDeclaredMethodInternal_7C_28Ljava_2Flang_2FString_3BALjava_2Flang_2FClass_3B_29Ljava_2Flang_2Freflect_2FMethod_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetEnclosingConstructorNative_7C_28_29Ljava_2Flang_2Freflect_2FConstructor_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetEnclosingMethodNative_7C_28_29Ljava_2Flang_2Freflect_2FMethod_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetInnerClassFlags_7C_28I_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetInnerClassName_7C_28_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetInterfacesInternal_7C_28_29ALjava_2Flang_2FClass_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetMethod_7C_28Ljava_2Flang_2FString_3BALjava_2Flang_2FClass_3BZ_29Ljava_2Flang_2Freflect_2FMethod_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetNameNative_7C_28_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetPublicDeclaredFields_7C_28_29ALjava_2Flang_2Freflect_2FField_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetPublicFieldRecursive_7C_28Ljava_2Flang_2FString_3B_29Ljava_2Flang_2Freflect_2FField_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetPublicFieldsRecursive_7C_28Ljava_2Futil_2FList_3B_29V"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetPublicMethodsInternal_7C_28Ljava_2Futil_2FList_3B_29V"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetDeclaredMethodsUnchecked_7C_28Z_29ALjava_2Flang_2Freflect_2FMethod_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetSignatureAnnotation_7C_28_29ALjava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetSignatureAttribute_7C_28_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CisDeclaredAnnotationPresent_7C_28Ljava_2Flang_2FClass_3B_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CisLocalOrAnonymousClass_7C_28_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CisLocalClass_7C_28_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CisAnonymousClass_7C_28_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CresolveName_7C_28Ljava_2Flang_2FString_3B_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CasSubclass_7C_28Ljava_2Flang_2FClass_3B_29Ljava_2Flang_2FClass_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CdesiredAssertionStatus_7C_28_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetAccessFlags_7C_28_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetEnclosingClass_7C_28_29Ljava_2Flang_2FClass_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetClasses_7C_28_29ALjava_2Flang_2FClass_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetDeclaredClasses_7C_28_29ALjava_2Flang_2FClass_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetDeclaredFieldsUnchecked_7C_28Z_29ALjava_2Flang_2Freflect_2FField_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetDeclaringClass_7C_28_29Ljava_2Flang_2FClass_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetEnclosingConstructor_7C_28_29Ljava_2Flang_2Freflect_2FConstructor_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetEnclosingMethod_7C_28_29Ljava_2Flang_2Freflect_2FMethod_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetEnumConstants_7C_28_29ALjava_2Flang_2FObject_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetEnumConstantsShared_7C_28_29ALjava_2Flang_2FObject_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetField_7C_28Ljava_2Flang_2FString_3B_29Ljava_2Flang_2Freflect_2FField_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetFields_7C_28_29ALjava_2Flang_2Freflect_2FField_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetGenericSuperclass_7C_28_29Ljava_2Flang_2Freflect_2FType_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetInstanceMethod_7C_28Ljava_2Flang_2FString_3BALjava_2Flang_2FClass_3B_29Ljava_2Flang_2Freflect_2FMethod_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetMethod_7C_28Ljava_2Flang_2FString_3BALjava_2Flang_2FClass_3B_29Ljava_2Flang_2Freflect_2FMethod_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetMethods_7C_28_29ALjava_2Flang_2Freflect_2FMethod_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetPackage_7C_28_29Ljava_2Flang_2FPackage_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetPackageName_24_7C_28_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetProtectionDomain_7C_28_29Ljava_2Fsecurity_2FProtectionDomain_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetSigners_7C_28_29ALjava_2Flang_2FObject_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CisMemberClass_7C_28_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CgetTypeParameters_7C_28_29ALjava_2Flang_2Freflect_2FTypeVariable_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CisAnnotation_7C_28_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CisAnnotationPresent_7C_28Ljava_2Flang_2FClass_3B_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CisFinalizable_7C_28_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CisSynthetic_7C_28_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7CtoGenericString_7C_28_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FClass_3B_7ChashCode_7C_28_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Cmin_7C_28II_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Cmax_7C_28JJ_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Cmin_7C_28JJ_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Cmax_7C_28II_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Cabs_7C_28J_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Cabs_7C_28I_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Clog10_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Csignum_7C_28F_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CaddExact_7C_28JJ_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CmultiplyExact_7C_28JJ_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CfloorDiv_7C_28JJ_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CfloorMod_7C_28JJ_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CsubtractExact_7C_28JJ_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CtoIntExact_7C_28J_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CmultiplyExact_7C_28II_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CaddExact_7C_28II_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CsubtractExact_7C_28II_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Cmin_7C_28FF_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Csqrt_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Cabs_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Cmax_7C_28DD_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Cmin_7C_28DD_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CcopySign_7C_28DD_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CgetExponent_7C_28D_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Cmax_7C_28FF_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Cfloor_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Ctan_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Cacos_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Ccos_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Csin_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Casin_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Catan_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Catan2_7C_28DD_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Cpow_7C_28DD_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Cround_7C_28D_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Clog_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Cceil_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CpowerOfTwoD_7C_28I_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CIEEEremainder_7C_28DD_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Cabs_7C_28F_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Ccbrt_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CcopySign_7C_28FF_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Ccosh_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CdecrementExact_7C_28I_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CdecrementExact_7C_28J_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Cexp_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Cexpm1_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CfloorDiv_7C_28II_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CfloorMod_7C_28II_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CgetExponent_7C_28F_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Chypot_7C_28DD_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CincrementExact_7C_28I_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CincrementExact_7C_28J_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Clog1p_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CnegateExact_7C_28I_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CnegateExact_7C_28J_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CnextAfter_7C_28DD_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CnextAfter_7C_28FD_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CnextDown_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CnextDown_7C_28F_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CnextUp_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CnextUp_7C_28F_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CpowerOfTwoF_7C_28I_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Crint_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Cround_7C_28F_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Cscalb_7C_28DI_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Cscalb_7C_28FI_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Csignum_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Csinh_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Ctanh_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CtoDegrees_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7CtoRadians_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Culp_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FMath_3B_7Culp_7C_28F_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Clog_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Csqrt_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CIEEEremainder_7C_28DD_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Cabs_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Cabs_7C_28F_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Cabs_7C_28I_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Cabs_7C_28J_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Cacos_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CaddExact_7C_28II_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CaddExact_7C_28JJ_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Casin_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Catan_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Catan2_7C_28DD_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Ccbrt_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Cceil_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CfloorOrCeil_7C_28DDDD_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CcopySign_7C_28DD_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CcopySign_7C_28FF_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Ccos_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Ccosh_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Cexp_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Cexpm1_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Cfloor_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CfloorDiv_7C_28II_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CfloorDiv_7C_28JJ_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CfloorMod_7C_28II_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CfloorMod_7C_28JJ_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CgetExponent_7C_28D_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CgetExponent_7C_28F_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Chypot_7C_28DD_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Clog10_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Clog1p_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Cmax_7C_28DD_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Cmax_7C_28FF_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Cmax_7C_28II_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Cmax_7C_28JJ_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Cmin_7C_28DD_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Cmin_7C_28FF_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Cmin_7C_28II_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Cmin_7C_28JJ_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CmultiplyExact_7C_28II_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CmultiplyExact_7C_28JJ_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CnextAfter_7C_28DD_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CnextAfter_7C_28FD_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CnextDown_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CnextDown_7C_28F_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CnextUp_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CnextUp_7C_28F_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Cpow_7C_28DD_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Crint_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Cround_7C_28F_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Cround_7C_28D_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Cscalb_7C_28DI_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Cscalb_7C_28FI_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Csignum_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Csignum_7C_28F_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Csin_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Csinh_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CsubtractExact_7C_28II_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CsubtractExact_7C_28JJ_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Ctan_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Ctanh_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CtoDegrees_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CtoIntExact_7C_28J_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7CtoRadians_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Culp_7C_28D_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FStrictMath_3B_7Culp_7C_28F_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7Ccompare_7C_28DD_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7CdoubleToLongBits_7C_28D_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7ChashCode_7C_28D_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7CvalueOf_7C_28D_29Ljava_2Flang_2FDouble_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7ClongBitsToDouble_7C_28J_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7CisNaN_7C_28D_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7CisInfinite_7C_28D_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7CtoString_7C_28D_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7CdoubleValue_7C_28_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7CparseDouble_7C_28Ljava_2Flang_2FString_3B_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7CdoubleToRawLongBits_7C_28D_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7CisFinite_7C_28D_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7Cmax_7C_28DD_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7Cmin_7C_28DD_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7Csum_7C_28DD_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7CtoHexString_7C_28D_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7CvalueOf_7C_28Ljava_2Flang_2FString_3B_29Ljava_2Flang_2FDouble_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7CbyteValue_7C_28_29B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7CcompareTo_7C_28Ljava_2Flang_2FDouble_3B_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7CcompareTo_7C_28Ljava_2Flang_2FObject_3B_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7Cequals_7C_28Ljava_2Flang_2FObject_3B_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7CfloatValue_7C_28_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7ChashCode_7C_28_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7CintValue_7C_28_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7CisInfinite_7C_28_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7CisNaN_7C_28_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7ClongValue_7C_28_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7CshortValue_7C_28_29S"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FDouble_3B_7CtoString_7C_28_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7CfloatToIntBits_7C_28F_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7CintBitsToFloat_7C_28I_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7CisNaN_7C_28F_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7CtoString_7C_28F_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7CvalueOf_7C_28Ljava_2Flang_2FString_3B_29Ljava_2Flang_2FFloat_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7CfloatValue_7C_28_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7CfloatToRawIntBits_7C_28F_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7CparseFloat_7C_28Ljava_2Flang_2FString_3B_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7CisFinite_7C_28F_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7CisInfinite_7C_28F_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7CvalueOf_7C_28F_29Ljava_2Flang_2FFloat_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7Ccompare_7C_28FF_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7ChashCode_7C_28F_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7Cmax_7C_28FF_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7Cmin_7C_28FF_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7Csum_7C_28FF_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7CtoHexString_7C_28F_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7CbyteValue_7C_28_29B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7CcompareTo_7C_28Ljava_2Flang_2FFloat_3B_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7CcompareTo_7C_28Ljava_2Flang_2FObject_3B_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7CdoubleValue_7C_28_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7Cequals_7C_28Ljava_2Flang_2FObject_3B_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7ChashCode_7C_28_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7CintValue_7C_28_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7CisInfinite_7C_28_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7CisNaN_7C_28_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7ClongValue_7C_28_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7CshortValue_7C_28_29S"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FFloat_3B_7CtoString_7C_28_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7Cdigit_7C_28CI_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7Ccompare_7C_28CC_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CvalueOf_7C_28C_29Ljava_2Flang_2FCharacter_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CcharCount_7C_28I_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CcodePointAt_7C_28Ljava_2Flang_2FCharSequence_3BI_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisHighSurrogate_7C_28C_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisLowSurrogate_7C_28C_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CtoCodePoint_7C_28CC_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CcodePointAt_7C_28ACI_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CcodePointAtImpl_7C_28ACII_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CcodePointAt_7C_28ACII_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CcodePointBefore_7C_28Ljava_2Flang_2FCharSequence_3BI_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CcodePointBefore_7C_28ACI_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CcodePointBeforeImpl_7C_28ACII_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CcodePointBefore_7C_28ACII_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CcodePointCount_7C_28Ljava_2Flang_2FCharSequence_3BII_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CcodePointCount_7C_28ACII_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CcodePointCountImpl_7C_28ACII_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7Cdigit_7C_28II_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CdigitImpl_7C_28II_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CforDigit_7C_28II_29C"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CgetDirectionality_7C_28C_29B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CgetDirectionality_7C_28I_29B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CgetType_7C_28I_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CgetDirectionalityImpl_7C_28I_29B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CgetName_7C_28I_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisValidCodePoint_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CgetNameImpl_7C_28I_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CgetNumericValue_7C_28C_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CgetNumericValue_7C_28I_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CgetNumericValueImpl_7C_28I_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CgetType_7C_28C_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CgetTypeImpl_7C_28I_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7ChashCode_7C_28C_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7ChighSurrogate_7C_28I_29C"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisAlphabetic_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisAlphabeticImpl_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisBmpCodePoint_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisDefined_7C_28C_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisDefined_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisDefinedImpl_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisDigit_7C_28C_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisDigit_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisDigitImpl_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisISOControl_7C_28C_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisISOControl_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisIdentifierIgnorable_7C_28C_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisIdentifierIgnorable_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisIdentifierIgnorableImpl_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisIdeographic_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisIdeographicImpl_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisJavaIdentifierPart_7C_28C_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisJavaIdentifierPart_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisJavaIdentifierStart_7C_28C_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisJavaIdentifierStart_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisJavaLetter_7C_28C_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisJavaLetterOrDigit_7C_28C_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisLetter_7C_28C_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisLetter_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisLetterImpl_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisLetterOrDigit_7C_28C_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisLetterOrDigit_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisLetterOrDigitImpl_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisLowerCase_7C_28C_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisLowerCase_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisLowerCaseImpl_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisMirrored_7C_28C_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisMirrored_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisMirroredImpl_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisSpace_7C_28C_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisSpaceChar_7C_28C_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisSpaceChar_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisSpaceCharImpl_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisSupplementaryCodePoint_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisSurrogate_7C_28C_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisSurrogatePair_7C_28CC_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisTitleCase_7C_28C_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisTitleCase_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisTitleCaseImpl_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisUnicodeIdentifierPart_7C_28C_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisUnicodeIdentifierPart_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisUnicodeIdentifierPartImpl_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisUnicodeIdentifierStart_7C_28C_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisUnicodeIdentifierStart_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisUnicodeIdentifierStartImpl_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisUpperCase_7C_28C_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisUpperCase_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisUpperCaseImpl_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisWhitespace_7C_28C_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisWhitespace_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CisWhitespaceImpl_7C_28I_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7ClowSurrogate_7C_28I_29C"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CoffsetByCodePoints_7C_28Ljava_2Flang_2FCharSequence_3BII_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CoffsetByCodePoints_7C_28ACIIII_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CoffsetByCodePointsImpl_7C_28ACIIII_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CreverseBytes_7C_28C_29C"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CtoChars_7C_28I_29AC"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CtoLowerCase_7C_28C_29C"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CtoLowerCase_7C_28I_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CtoLowerCaseImpl_7C_28I_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CtoString_7C_28C_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CtoTitleCase_7C_28C_29C"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CtoTitleCase_7C_28I_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CtoTitleCaseImpl_7C_28I_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CtoUpperCase_7C_28C_29C"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CtoUpperCase_7C_28I_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CtoUpperCaseImpl_7C_28I_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CcharValue_7C_28_29C"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CcompareTo_7C_28Ljava_2Flang_2FCharacter_3B_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CcompareTo_7C_28Ljava_2Flang_2FObject_3B_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7Cequals_7C_28Ljava_2Flang_2FObject_3B_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7ChashCode_7C_28_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FCharacter_3B_7CtoString_7C_28_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Futil_2FDate_3B_7CgetCalendarSystem_7C_28I_29Lsun_2Futil_2Fcalendar_2FBaseCalendar_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Futil_2FDate_3B_7CgetCalendarDate_7C_28_29Lsun_2Futil_2Fcalendar_2FBaseCalendar_24Date_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Futil_2FDate_3B_7CgetCalendarSystem_7C_28J_29Lsun_2Futil_2Fcalendar_2FBaseCalendar_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Futil_2FDate_3B_7CgetJulianCalendar_7C_28_29Lsun_2Futil_2Fcalendar_2FBaseCalendar_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Futil_2FDate_3B_7CgetCalendarSystem_7C_28Lsun_2Futil_2Fcalendar_2FBaseCalendar_24Date_3B_29Lsun_2Futil_2Fcalendar_2FBaseCalendar_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Futil_2FDate_3B_7CgetMillisOf_7C_28Ljava_2Futil_2FDate_3B_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7CgetAnnotationNative_7C_28Ljava_2Flang_2FClass_3B_29Ljava_2Flang_2Fannotation_2FAnnotation_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7CgetNameInternal_7C_28_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7CgetSignatureAnnotation_7C_28_29ALjava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7CgetSignatureAttribute_7C_28_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7CgetDeclaringClass_7C_28_29Ljava_2Flang_2FClass_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7CgetName_7C_28_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7CgetType_7C_28_29Ljava_2Flang_2FClass_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7Cget_7C_28Ljava_2Flang_2FObject_3B_29Ljava_2Flang_2FObject_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7CgetAnnotation_7C_28Ljava_2Flang_2FClass_3B_29Ljava_2Flang_2Fannotation_2FAnnotation_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7CgetAnnotationsByType_7C_28Ljava_2Flang_2FClass_3B_29ALjava_2Flang_2Fannotation_2FAnnotation_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7CgetArtField_7C_28_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7CgetBoolean_7C_28Ljava_2Flang_2FObject_3B_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7CgetByte_7C_28Ljava_2Flang_2FObject_3B_29B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7CgetChar_7C_28Ljava_2Flang_2FObject_3B_29C"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7CgetDeclaredAnnotations_7C_28_29ALjava_2Flang_2Fannotation_2FAnnotation_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7CgetDexFieldIndex_7C_28_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7CgetDouble_7C_28Ljava_2Flang_2FObject_3B_29D"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7CgetFloat_7C_28Ljava_2Flang_2FObject_3B_29F"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7CgetGenericType_7C_28_29Ljava_2Flang_2Freflect_2FType_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7CgetInt_7C_28Ljava_2Flang_2FObject_3B_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7CgetLong_7C_28Ljava_2Flang_2FObject_3B_29J"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7CgetModifiers_7C_28_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7CgetOffset_7C_28_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2Freflect_2FField_3B_7CgetShort_7C_28Ljava_2Flang_2FObject_3B_29S"}, +{ true, false, false, false, false, false, false, "Landroid_2Ficu_2Futil_2FCalendar_3B_7CgetRegionForCalendar_7C_28Landroid_2Ficu_2Futil_2FULocale_3B_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Landroid_2Ficu_2Futil_2FCalendar_3B_7CgetType_7C_28_29Ljava_2Flang_2FString_3B"}, + +{ false, true, false, false, true, false, false, "Native_java_lang_System_arraycopy__Ljava_lang_Object_2ILjava_lang_Object_2II"}, +{ false, true, false, false, true, false, false, "Native_java_lang_System_arraycopyByteUnchecked___3BI_3BII"}, +{ false, true, false, false, true, false, false, "Native_java_lang_System_arraycopyBooleanUnchecked___3ZI_3ZII"}, +{ false, true, false, false, true, false, false, "Native_java_lang_System_arraycopyShortUnchecked___3SI_3SII"}, +{ false, true, false, false, true, false, false, "Native_java_lang_System_arraycopyLongUnchecked___3JI_3JII"}, +{ false, true, false, false, true, false, false, "Native_java_lang_System_arraycopyIntUnchecked___3II_3III"}, +{ false, true, false, false, true, false, false, "Native_java_lang_System_arraycopyFloatUnchecked___3FI_3FII"}, +{ false, true, false, false, true, false, false, "Native_java_lang_System_arraycopyDoubleUnchecked___3DI_3DII"}, +{ false, true, false, false, true, false, false, "Native_java_lang_System_arraycopyCharUnchecked___3CI_3CII"}, + +{ false, false, false, true, true, false, false, "Ljava_2Flang_2FThread_3B_7CcurrentThread_7C_28_29Ljava_2Flang_2FThread_3B"}, +{ true, false, false, false, true, false, false, "Ljava_2Flang_2FStringFactory_3B_7CnewStringFromChars_7C_28IIAC_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, true, false, false, "Ljava_2Flang_2FString_3B_7CfastSubstring_7C_28II_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, true, false, false, "Ljava_2Flang_2FString_3B_7CcompareTo_7C_28Ljava_2Flang_2FString_3B_29I"}, +{ false, true, false, false, true, false, false, "Ljava_2Flang_2FString_3B_7CgetCharsNoCheck_7C_28IIACI_29V"}, +{ true, false, false, false, true, false, false, "Ljava_2Flang_2FStringFactory_3B_7CnewStringFromBytes_7C_28ABIII_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, true, false, false, "Ljava_2Flang_2FStringFactory_3B_7CnewStringFromString_7C_28Ljava_2Flang_2FString_3B_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, true, false, false, "Ljava_2Flang_2FString_3B_7CtoCharArray_7C_28_29AC"}, +{ true, false, false, false, true, false, false, "Ljava_2Flang_2FString_3B_7Cconcat_7C_28Ljava_2Flang_2FString_3B_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, true, false, false, "Ljava_2Flang_2FString_3B_7CfastSubstring_7C_28II_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, true, false, false, "Ljava_2Flang_2FString_3B_7Cintern_7C_28_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, true, false, false, "Ljava_2Flang_2FString_3B_7CdoReplace_7C_28CC_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, true, false, false, "Ljava_2Flang_2FString_3B_7CfastIndexOf_7C_28II_29I"}, +{ false, true, false, false, true, false, false, "Ljava_2Flang_2FSystem_3B_7Carraycopy_7C_28Ljava_2Flang_2FObject_3BILjava_2Flang_2FObject_3BII_29V"}, +{ false, true, false, false, true, false, false, "Ljava_2Flang_2FSystem_3B_7CarraycopyCharUnchecked_7C_28ACIACII_29V"}, +{ false, true, false, false, true, false, false, "Ljava_2Flang_2FSystem_3B_7CarraycopyByteUnchecked_7C_28ABIABII_29V"}, +{ false, true, false, false, true, false, false, "Ljava_2Flang_2FSystem_3B_7CarraycopyShortUnchecked_7C_28ASIASII_29V"}, +{ false, true, false, false, true, false, false, "Ljava_2Flang_2FSystem_3B_7CarraycopyIntUnchecked_7C_28AIIAIII_29V"}, +{ false, true, false, false, true, false, false, "Ljava_2Flang_2FSystem_3B_7CarraycopyLongUnchecked_7C_28AJIAJII_29V"}, +{ false, true, false, false, true, false, false, "Ljava_2Flang_2FSystem_3B_7CarraycopyFloatUnchecked_7C_28AFIAFII_29V"}, +{ false, true, false, false, true, false, false, "Ljava_2Flang_2FSystem_3B_7CarraycopyDoubleUnchecked_7C_28ADIADII_29V"}, +{ false, true, false, false, true, false, false, "Ljava_2Flang_2FSystem_3B_7CarraycopyBooleanUnchecked_7C_28AZIAZII_29V"}, + +{ true, false, false, false, true, false, false, "Native_java_lang_StringFactory_newStringFromChars__II_3C"}, +{ true, false, false, false, true, false, false, "Native_java_lang_StringFactory_newStringFromString__Ljava_lang_String_2"}, +{ true, false, false, false, true, false, false, "Native_java_lang_StringFactory_newStringFromBytes___3BIII"}, + +{ false, false, false, true, false, false, false, "Ljava_2Flang_2FThrowable_3B_7CnativeFillInStackTrace_7C_28_29Ljava_2Flang_2FObject_3B"}, + +{ false, true, false, false, false, false, true, "Ljava_2Futil_2FMap_3B_7Cput_7C_28Ljava_2Flang_2FObject_3BLjava_2Flang_2FObject_3B_29Ljava_2Flang_2FObject_3B"}, +{ false, true, false, false, false, false, true, "Lsun_2Fmisc_2FUnsafe_3B_7CcompareAndSwapObject_7C_28Ljava_2Flang_2FObject_3BJLjava_2Flang_2FObject_3BLjava_2Flang_2FObject_3B_29Z"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FObject_3B_7CidentityHashCodeNative_7C_28Ljava_2Flang_2FObject_3B_29I"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FString_3B_7CcharAt_7C_28I_29C"}, +{ true, false, false, false, false, false, false, "Ljava_2Futil_2FProperties_3B_7CgetProperty_7C_28Ljava_2Flang_2FString_3B_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Futil_2FProperties_3B_7CgetProperty_7C_28Ljava_2Flang_2FString_3BLjava_2Flang_2FString_3B_29Ljava_2Flang_2FString_3B"}, + +{ true, false, false, false, true, false, true, "Lsun_2Fnet_2FNetProperties_3B_7Cget_7C_28Ljava_2Flang_2FString_3B_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, true, false, true, "Lsun_2Fnet_2FNetProperties_3B_7CgetBoolean_7C_28Ljava_2Flang_2FString_3B_29Ljava_2Flang_2FBoolean_3B"}, +{ true, false, false, false, true, false, true, "Lsun_2Fnet_2FNetProperties_3B_7CgetInteger_7C_28Ljava_2Flang_2FString_3BI_29Ljava_2Flang_2FInteger_3B"}, +{ true, false, false, false, true, false, false, "Ljava_2Flang_2Fref_2FReference_3B_7CgetReferent_7C_28_29Ljava_2Flang_2FObject_3B", }, +{ true, false, false, false, true, false, false, "Ljava_2Flang_2FSystem_3B_7CnanoTime_7C_28_29J"}, +{ true, false, false, false, true, false, false, "Llibcore_2Fio_2FLinux_3B_7Cgettid_7C_28_29I"}, +{ true, false, false, false, true, false, false, "Llibcore_2Fio_2FLinux_3B_7Cgetpid_7C_28_29I"}, +{ true, false, false, false, true, false, false, "Ljava_2Flang_2FSystem_3B_7CcurrentTimeMillis_7C_28_29J"}, +{ true, false, false, false, true, false, false, "Lsun_2Futil_2Flocale_2FBaseLocale_24Cache_3B_7Cget_7C_28Ljava_2Flang_2FObject_3B_29Ljava_2Flang_2FObject_3B"}, +{ true, false, false, false, false, false, false, "Ljava_2Flang_2FString_3B_7Cformat_7C_28Ljava_2Flang_2FString_3BALjava_2Flang_2FObject_3B_29Ljava_2Flang_2FString_3B"}, +{ true, false, false, false, false, false, false, "Landroid_2Ficu_2Futil_2FCalendar_3B_7CisEquivalentTo_7C_28Landroid_2Ficu_2Futil_2FCalendar_3B_29Z"}, +{ true, false, false, false, false, false, false, "Landroid_2Ficu_2Futil_2FGregorianCalendar_3B_7CisEquivalentTo_7C_28Landroid_2Ficu_2Futil_2FCalendar_3B_29Z"}, +{ true, false, false, false, false, false, false, "Landroid_2Ficu_2Futil_2FAnnualTimeZoneRule_3B_7CisEquivalentTo_7C_28Landroid_2Ficu_2Futil_2FTimeZoneRule_3B_29Z"}, +{ true, false, false, false, false, false, false, "Landroid_2Ficu_2Futil_2FGregorianCalendar_3B_7CisEquivalentTo_7C_28Landroid_2Ficu_2Futil_2FCalendar_3B_29Z"}, + +{ true, false, false, false, true, false, false, "Landroid_2Fview_2FSurface_3B_7CnativeIsValid_7C_28J_29Z"}, +{ true, false, false, false, true, false, false, "Lsun_2Fmisc_2FUnsafe_3B_7CgetObjectVolatile_7C_28Ljava_2Flang_2FObject_3BJ_29Ljava_2Flang_2FObject_3B"}, +{ true, false, false, false, true, false, false, "Ljava_2Flang_2FThread_3B_7CnativeHoldsLock_7C_28Ljava_2Flang_2FObject_3B_29Z"}, +{ true, false, false, false, true, false, false, "Landroid_2Futil_2FLog_3B_7Clogger__entry__max__payload__native_7C_28_29I"}, +{ true, false, false, false, true, false, false, "Landroid_2Fos_2FSystemProperties_3B_7Cnative__get__int_7C_28Ljava_2Flang_2FString_3BI_29I"}, +{ true, false, false, false, true, false, false, "Ljava_2Flang_2FThread_3B_7CnativeGetStatus_7C_28Z_29I"}, +{ false, true, false, false, true, false, false, "Ljava_2Ftime_2Fformat_2FDateTimeFormatterBuilder_24ReducedPrinterParser_3B_7Clambda_24setValue_240_24DateTimeFormatterBuilder_24ReducedPrinterParser_7C_28Ljava_2Ftime_2Fformat_2FDateTimeParseContext_3BJIILjava_2Ftime_2Fchrono_2FChronology_3B_29V"}, + +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FMessageQueue_3B_7CnativePollOnce_7C_28JI_29V"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FTrace_3B_7CnativeTraceBegin_7C_28JLjava_2Flang_2FString_3B_29V"}, +{ false, false, true, false, true, false, false, "Landroid_2Futil_2FLog_3B_7Cprintln__native_7C_28IILjava_2Flang_2FString_3BLjava_2Flang_2FString_3B_29I"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FSystemProperties_3B_7Cnative__add__change__callback_7C_28_29V"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FProcess_3B_7CreadProcFile_7C_28Ljava_2Flang_2FString_3BAIALjava_2Flang_2FString_3BAJAF_29Z"}, +{ false, false, true, false, true, false, false, "Llibcore_2Fio_2FLinux_3B_7Cstat_7C_28Ljava_2Flang_2FString_3B_29Landroid_2Fsystem_2FStructStat_3B"}, +{ false, false, true, false, true, false, false, "Ljava_2Fio_2FFileInputStream_3B_7Copen0_7C_28Ljava_2Flang_2FString_3B_29V"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FProcess_3B_7CgetGidForName_7C_28Ljava_2Flang_2FString_3B_29I"}, +{ false, false, true, false, true, false, false, "Landroid_2Futil_2FEventLog_3B_7CwriteEvent_7C_28IALjava_2Flang_2FObject_3B_29I"}, +{ false, false, true, false, true, false, false, "Ljava_2Flang_2FObject_3B_7CinternalClone_7C_28_29Ljava_2Flang_2FObject_3B"}, +{ false, false, true, false, true, false, false, "Llibcore_2Fio_2FLinux_3B_7CwriteBytes_7C_28Ljava_2Fio_2FFileDescriptor_3BLjava_2Flang_2FObject_3BII_29I"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FProcess_3B_7CgetPidsForCommands_7C_28ALjava_2Flang_2FString_3B_29AI"}, +{ false, false, true, false, true, false, false, "Ljava_2Fio_2FUnixFileSystem_3B_7CcreateFileExclusively0_7C_28Ljava_2Flang_2FString_3B_29Z"}, +{ false, false, true, false, true, false, false, "Ljava_2Fio_2FUnixFileSystem_3B_7Clist0_7C_28Ljava_2Fio_2FFile_3B_29ALjava_2Flang_2FString_3B"}, +{ false, false, true, false, true, false, false, "Llibcore_2Fio_2FLinux_3B_7Cclose_7C_28Ljava_2Fio_2FFileDescriptor_3B_29V"}, +{ false, false, true, false, true, false, false, "Llibcore_2Fio_2FAsynchronousCloseMonitor_3B_7CsignalBlockedThreads_7C_28Ljava_2Fio_2FFileDescriptor_3B_29V"}, +{ false, false, true, false, true, false, false, "Llibcore_2Fio_2FLinux_3B_7CreadBytes_7C_28Ljava_2Fio_2FFileDescriptor_3BLjava_2Flang_2FObject_3BII_29I"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FBinder_3B_7CsetThreadStrictModePolicy_7C_28I_29V"}, +{ false, false, true, false, true, false, false, "Ljava_2Futil_2Fregex_2FMatcher_3B_7CfindNextImpl_7C_28JAI_29Z"}, +{ false, false, true, false, true, false, false, "Ljava_2Futil_2Fregex_2FMatcher_3B_7CsetInputImpl_7C_28JLjava_2Flang_2FString_3BII_29V"}, +{ false, false, true, false, true, false, false, "Llibcore_2Ficu_2FNativeConverter_3B_7CsetCallbackDecode_7C_28JIILjava_2Flang_2FString_3B_29V"}, +{ false, false, true, false, true, false, false, "Llibcore_2Fio_2FLinux_3B_7Copen_7C_28Ljava_2Flang_2FString_3BII_29Ljava_2Fio_2FFileDescriptor_3B"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FBinderProxy_3B_7CtransactNative_7C_28ILandroid_2Fos_2FParcel_3BLandroid_2Fos_2FParcel_3BI_29Z"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FBinder_3B_7CrestoreCallingIdentity_7C_28J_29V"}, +{ false, false, true, false, true, false, false, "Landroid_2Fnet_2FLocalSocketImpl_3B_7Creadba__native_7C_28ABIILjava_2Fio_2FFileDescriptor_3B_29I"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FProcess_3B_7CgetPids_7C_28Ljava_2Flang_2FString_3BAI_29AI"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FTrace_3B_7CnativeAsyncTraceBegin_7C_28JLjava_2Flang_2FString_3BI_29V"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FTrace_3B_7CnativeAsyncTraceEnd_7C_28JLjava_2Flang_2FString_3BI_29V"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FParcel_3B_7CnativeAppendFrom_7C_28JJII_29J"}, +{ false, false, true, false, true, false, false, "Ljava_2Fio_2FFileDescriptor_3B_7CisSocket_7C_28I_29Z"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FProcess_3B_7CsetProcessGroup_7C_28II_29V"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FProcess_3B_7CsetThreadPriority_7C_28I_29V"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FParcel_3B_7CnativeEnforceInterface_7C_28JLjava_2Flang_2FString_3B_29V"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FParcel_3B_7CnativeWriteFloat_7C_28JF_29V"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FParcel_3B_7CnativeWriteString_7C_28JLjava_2Flang_2FString_3B_29V"}, +{ false, false, true, false, true, false, false, "Llibcore_2Fio_2FLinux_3B_7CioctlInetAddress_7C_28Ljava_2Fio_2FFileDescriptor_3BILjava_2Flang_2FString_3B_29Ljava_2Fnet_2FInetAddress_3B"}, +{ false, false, true, false, true, false, false, "Ljava_2Flang_2FObject_3B_7CidentityHashCodeNative_7C_28Ljava_2Flang_2FObject_3B_29I"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FBinder_3B_7CgetCallingPid_7C_28_29I"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FBinder_3B_7CflushPendingCommands_7C_28_29V"}, +{ false, false, true, false, true, false, false, "Lsun_2Fmisc_2FUnsafe_3B_7CcompareAndSwapLong_7C_28Ljava_2Flang_2FObject_3BJJJ_29Z"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FBinder_3B_7CgetCallingUid_7C_28_29I"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FParcel_3B_7CnativeWriteFileDescriptor_7C_28JLjava_2Fio_2FFileDescriptor_3B_29J"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FParcel_3B_7CnativeReadStrongBinder_7C_28J_29Landroid_2Fos_2FIBinder_3B"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FBinderProxy_3B_7ClinkToDeath_7C_28Landroid_2Fos_2FIBinder_24DeathRecipient_3BI_29V"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FParcel_3B_7CnativeReadLong_7C_28J_29J"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FParcel_3B_7CnativeWriteLong_7C_28JJ_29V"}, +{ false, false, true, false, true, false, false, "Lsun_2Fmisc_2FUnsafe_3B_7CputObject_7C_28Ljava_2Flang_2FObject_3BJLjava_2Flang_2FObject_3B_29V"}, +{ false, false, true, false, true, false, false, "Lsun_2Fmisc_2FUnsafe_3B_7CputOrderedObject_7C_28Ljava_2Flang_2FObject_3BJLjava_2Flang_2FObject_3B_29V"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FParcel_3B_7CnativeUnmarshall_7C_28JABII_29J"}, +{ false, false, true, false, true, false, false, "Landroid_2Fview_2FSurfaceControl_3B_7CnativeIsRogSupport_7C_28_29I"}, +{ false, false, true, false, true, false, false, "Ljava_2Fio_2FUnixFileSystem_3B_7CcheckAccess0_7C_28Ljava_2Fio_2FFile_3BI_29Z"}, +{ false, false, true, false, true, false, false, "Landroid_2Futil_2FMemoryIntArray_3B_7CnativeGet_7C_28IJI_29I"}, +{ false, false, true, false, true, false, false, "Ljava_2Flang_2FObject_3B_7CnotifyAll_7C_28_29V"}, +{ false, false, true, false, true, false, false, "Landroid_2Futil_2FEventLog_3B_7CwriteEvent_7C_28II_29I"}, +{ false, false, true, false, true, false, false, "Llibcore_2Fio_2FLinux_3B_7CgetsockoptLinger_7C_28Ljava_2Fio_2FFileDescriptor_3BII_29Landroid_2Fsystem_2FStructLinger_3B"}, +{ false, false, true, false, true, false, false, "Ljava_2Fio_2FUnixFileSystem_3B_7Ccanonicalize0_7C_28Ljava_2Flang_2FString_3B_29Ljava_2Flang_2FString_3B"}, +{ false, false, true, false, true, false, false, "Landroid_2Fgraphics_2FRegion_3B_7CnativeOp_7C_28JJJI_29Z"}, +{ false, false, true, false, true, false, false, "Landroid_2Futil_2FMemoryIntArray_3B_7CnativeSet_7C_28IJII_29V"}, +{ false, false, true, false, true, false, false, "Ljava_2Fio_2FUnixFileSystem_3B_7Crename0_7C_28Ljava_2Fio_2FFile_3BLjava_2Fio_2FFile_3B_29Z"}, +{ false, false, true, false, true, false, false, "Ljava_2Flang_2FClass_3B_7CclassForName_7C_28Ljava_2Flang_2FString_3BZLjava_2Flang_2FClassLoader_3B_29Ljava_2Flang_2FClass_3B"}, +{ false, false, true, false, true, false, false, "Ldalvik_2Fsystem_2FVMRuntime_3B_7CnewUnpaddedArray_7C_28Ljava_2Flang_2FClass_3BI_29Ljava_2Flang_2FObject_3B"}, +{ false, false, true, false, true, false, false, "Llibcore_2Fio_2FLinux_3B_7Cchmod_7C_28Ljava_2Flang_2FString_3BI_29V"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FUEventObserver_3B_7CnativeSetup_7C_28_29V"}, +{ false, false, true, false, true, false, false, "Landroid_2Fview_2FSurfaceControl_3B_7CnativeSetActiveConfig_7C_28Landroid_2Fos_2FIBinder_3BI_29Z"}, +{ false, false, true, false, true, false, false, "Ljava_2Fio_2FFileDescriptor_3B_7Csync_7C_28_29V"}, +{ false, false, true, false, true, false, false, "Landroid_2Fgraphics_2FMatrix_3B_7CnGetValues_7C_28JAF_29V"}, +{ false, false, true, false, true, false, false, "Landroid_2Fgraphics_2FBaseCanvas_3B_7CnDrawColor_7C_28JII_29V"}, +{ false, false, true, false, true, false, false, "Landroid_2Fgraphics_2FRegion_3B_7CnativeSetRect_7C_28JIIII_29Z"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FDebug_3B_7CgetPss_7C_28IAJAJ_29J"}, +{ false, false, true, false, true, false, false, "Landroid_2Fcontent_2Fres_2FXmlBlock_3B_7CnativeNext_7C_28J_29I"}, +{ false, false, true, false, true, false, false, "Lsun_2Fnio_2Fch_2FFileDispatcherImpl_3B_7Cread0_7C_28Ljava_2Fio_2FFileDescriptor_3BJI_29I"}, +{ false, false, true, false, true, false, false, "Llibcore_2Fio_2FLinux_3B_7Cfstat_7C_28Ljava_2Fio_2FFileDescriptor_3B_29Landroid_2Fsystem_2FStructStat_3B"}, +{ false, false, true, false, true, false, false, "Lsun_2Fnio_2Ffs_2FUnixNativeDispatcher_3B_7Copen0_7C_28JII_29I"}, +{ false, false, true, false, true, false, false, "Llibcore_2Futil_2FNativeAllocationRegistry_3B_7CapplyFreeFunction_7C_28JJ_29V"}, +{ false, false, true, false, true, false, false, "Ldalvik_2Fsystem_2FVMRuntime_3B_7CregisterNativeFree_7C_28I_29V"}, +{ false, false, true, false, true, false, false, "Ljava_2Flang_2FThread_3B_7Cinterrupted_7C_28_29Z"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FParcel_3B_7CnativeCreateByteArray_7C_28J_29AB"}, +{ false, false, true, false, true, false, false, "Ljava_2Flang_2FClass_3B_7CgetDeclaredFields_7C_28_29ALjava_2Flang_2Freflect_2FField_3B"}, +{ false, false, true, false, true, false, false, "Landroid_2Fview_2FSurfaceControl_3B_7CnativeGetContentFrameStats_7C_28JLandroid_2Fview_2FWindowContentFrameStats_3B_29Z"}, +{ false, false, true, false, true, false, false, "Lsun_2Fnio_2Fch_2FFileDispatcherImpl_3B_7Cwrite0_7C_28Ljava_2Fio_2FFileDescriptor_3BJI_29I"}, +{ false, false, true, false, true, false, false, "Ljava_2Flang_2FThread_3B_7CnativeInterrupt_7C_28_29V"}, +{ false, false, true, false, true, false, false, "Ljava_2Flang_2FThread_3B_7CnativeSetPriority_7C_28I_29V"}, +{ false, false, true, false, true, false, false, "Ljava_2Flang_2FRuntime_3B_7CnativeExit_7C_28I_29V"}, +{ false, false, true, false, true, false, false, "Llibcore_2Fio_2FLinux_3B_7Cstrerror_7C_28I_29Ljava_2Flang_2FString_3B"}, +{ false, false, true, false, true, false, false, "Landroid_2Fcontent_2Fres_2FXmlBlock_3B_7CnativeDestroy_7C_28J_29V"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FProcess_3B_7CgetThreadPriority_7C_28I_29I"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FFileObserver_24ObserverThread_3B_7Cinit_7C_28_29I"}, +{ false, false, true, false, true, false, false, "Landroid_2Fview_2FSurface_3B_7CnativeSyncFrameInfo_7C_28JJ_29V"}, +{ false, false, true, false, true, false, false, "Llibcore_2Ficu_2FICU_3B_7CgetCurrencyCode_7C_28Ljava_2Flang_2FString_3B_29Ljava_2Flang_2FString_3B"}, +{ false, false, true, false, true, false, false, "Landroid_2Fos_2FSystemProperties_3B_7Cnative__get_7C_28Ljava_2Flang_2FString_3BLjava_2Flang_2FString_3B_29Ljava_2Flang_2FString_3B"}, +{ false, false, true, false, true, false, false, "Ldalvik_2Fsystem_2FVMRuntime_3B_7Cproperties_7C_28_29ALjava_2Flang_2FString_3B"}, +{ false, false, true, false, true, false, false, "Ljava_2Futil_2Fregex_2FMatcher_3B_7CopenImpl_7C_28J_29J"}, +{ false, false, true, false, true, false, false, "Ljava_2Futil_2Fregex_2FPattern_3B_7CcompileImpl_7C_28Ljava_2Flang_2FString_3BI_29J"}, +{ false, false, true, false, true, false, false, "Ljava_2Flang_2FThrowable_3B_7CnativeFillInStackTrace_7C_28_29Ljava_2Flang_2FObject_3B"}, +{ false, false, true, false, true, false, false, "Llibcore_2Ficu_2FNativeConverter_3B_7CopenConverter_7C_28Ljava_2Flang_2FString_3B_29J"}, +{ false, false, true, false, true, false, false, "Landroid_2Fview_2FDisplayEventReceiver_3B_7CnativeInit_7C_28Ljava_2Flang_2Fref_2FWeakReference_3BLandroid_2Fos_2FMessageQueue_3BI_29J"}, +{ false, false, true, false, true, false, false, "Landroid_2Fcontent_2Fres_2FStringBlock_3B_7CnativeGetString_7C_28JI_29Ljava_2Flang_2FString_3B"}, +{ false, false, true, false, true, false, false, "Llibcore_2Futil_2FCharsetUtils_3B_7CtoUtf8Bytes_7C_28Ljava_2Flang_2FString_3BII_29AB"}, diff --git a/src/mapleall/maple_ipa/include/tobe_cloned_funcs.def b/src/mapleall/maple_ipa/include/tobe_cloned_funcs.def new file mode 100644 index 0000000000000000000000000000000000000000..1da06daba97bfadc64031d3e451f5bb4f523f4cd --- /dev/null +++ b/src/mapleall/maple_ipa/include/tobe_cloned_funcs.def @@ -0,0 +1,22 @@ +/* + * Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ + +/** + ===================================================== FORMAT ====================================================== + ORIFUNC(origin, cloned) + */ + +ORIFUNC(Ljava_2Flang_2FAbstractStringBuilder_3B_7Cappend_7C_28Ljava_2Flang_2FString_3B_29Ljava_2Flang_2FAbstractStringBuilder_3B, + Ljava_2Flang_2FAbstractStringBuilder_3B_7CappendCLONEDignoreret_7C_28Ljava_2Flang_2FString_3B_29V) diff --git a/src/mapleall/maple_ipa/include/tobe_replaced_funcs.def b/src/mapleall/maple_ipa/include/tobe_replaced_funcs.def new file mode 100644 index 0000000000000000000000000000000000000000..97da39412c604ac5ffdd2455f1d2f2033d19cd1f --- /dev/null +++ b/src/mapleall/maple_ipa/include/tobe_replaced_funcs.def @@ -0,0 +1,23 @@ +/* + * Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ + +/** + ===================================================== FORMAT ====================================================== + ORIFUNC(caller, origCallee, newCallee) + */ +ORIFUNC(Ljava_2Flang_2FRuntime_3B_7CrunFinalization_7C_28_29V, + Ldalvik_2Fsystem_2FVMRuntime_3B_7CrunFinalization_7C_28J_29V, + MCC_RunFinalization) + diff --git a/src/mapleall/maple_ipa/src/call_graph.cpp b/src/mapleall/maple_ipa/src/call_graph.cpp index b58de784097d08e86dc7d895460f7967f1291f6f..4aafd4789356a22e0707c32a50d252d9f1fcb7b8 100644 --- a/src/mapleall/maple_ipa/src/call_graph.cpp +++ b/src/mapleall/maple_ipa/src/call_graph.cpp @@ -21,6 +21,7 @@ #include "option.h" #include "retype.h" #include "string_utils.h" + // Call Graph Analysis // This phase is a foundation phase of compilation. This phase build // the call graph not only for this module also for the modules it @@ -748,6 +749,13 @@ void IPODevirtulize::SearchDefInMemberMethods(const Klass &klass) { for (size_t i = 0; i < classType->GetFieldsSize(); ++i) { FieldAttrs attribute = classType->GetFieldsElemt(i).second.second; if (attribute.GetAttr(FLDATTR_final)) { + // Conflict with simplify + if (strcmp(klass.GetKlassName().c_str(), + "Lcom_2Fandroid_2Fserver_2Fpm_2FPackageManagerService_24ActivityIntentResolver_3B") == 0 && + strcmp(GlobalTables::GetStrTable().GetStringFromStrIdx(classType->GetFieldsElemt(i).first).c_str(), + "mActivities") == 0) { + continue; + } FieldID id = mirBuilder->GetStructFieldIDFromFieldNameParentFirst( classType, GlobalTables::GetStrTable().GetStringFromStrIdx(classType->GetFieldsElemt(i).first)); finalPrivateFieldID.push_back(id); @@ -1005,6 +1013,9 @@ void DoDevirtual(const Klass &klass, const KlassHierarchy &klassh) { } // Add this check for the thirdparty APP compile if (tmpMethod == nullptr) { + if (Options::deferredVisit) { + return; + } Klass *parentKlass = klassh.GetKlassFromName(calleeFunc->GetBaseClassName()); CHECK_FATAL(parentKlass != nullptr, "null ptr check"); bool flag = false; diff --git a/src/mapleall/maple_ipa/src/clone.cpp b/src/mapleall/maple_ipa/src/clone.cpp index 973ac513bd37e2873d962ceec66b8ddb4fb0061d..9b69e6ec6345253db048140492e908fba22eb0fb 100644 --- a/src/mapleall/maple_ipa/src/clone.cpp +++ b/src/mapleall/maple_ipa/src/clone.cpp @@ -25,6 +25,9 @@ namespace maple { ReplaceRetIgnored::ReplaceRetIgnored(MemPool *memPool) : memPool(memPool), allocator(memPool), toBeClonedFuncNames(allocator.Adapter()) { +#define ORIFUNC(ORIGINAL, CLONED) toBeClonedFuncNames.insert(MapleString(#ORIGINAL, memPool)); +#include "tobe_cloned_funcs.def" +#undef ORIFUNC } bool ReplaceRetIgnored::RealShouldReplaceWithVoidFunc(Opcode op, size_t nRetSize, diff --git a/src/mapleall/maple_ipa/src/do_ipa_escape_analysis.cpp b/src/mapleall/maple_ipa/src/do_ipa_escape_analysis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bfa60378d8a59ba470cae963f9983bedf8590e4e --- /dev/null +++ b/src/mapleall/maple_ipa/src/do_ipa_escape_analysis.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (c) [2019-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "do_ipa_escape_analysis.h" +#include + +namespace maple { +AnalysisResult *DoIpaEA::Run(MeFunction *func, MeFuncResultMgr *m, ModuleResultMgr *mrm) { + if (func == nullptr) { + return nullptr; + } + MIRFunction *mirFunc = func->GetMirFunc(); + const std::map &summaryMap = mirFunc->GetModule()->GetEASummary(); + if (!mirFunc->GetModule()->IsInIPA() && summaryMap.size() == 0) { + return nullptr; + } + CHECK_FATAL(mrm != nullptr, "Needs module result manager for ipa"); + KlassHierarchy *kh = static_cast(mrm->GetAnalysisResult(MoPhase_CHA, &func->GetMIRModule())); + CHECK_FATAL(kh != nullptr, "KlassHierarchy phase has problem"); + MeIRMap *irMap = static_cast(m->GetAnalysisResult(MeFuncPhase_IRMAPBUILD, func)); + CHECK_FATAL(irMap != nullptr, "irMap phase has problem"); + + CallGraph *pcg = nullptr; + if (mirFunc->GetModule()->IsInIPA()) { + pcg = static_cast(mrm->GetAnalysisResult(MoPhase_CALLGRAPH_ANALYSIS, &func->GetMIRModule())); + } + MemPool *eaMemPool = memPoolCtrler.NewMemPool(PhaseName()); + mirFunc->GetModule()->SetCurFunction(mirFunc); + + if (IPAEscapeAnalysis::kDebug) { + LogInfo::MapleLogger() << "=======IPAEA BEGIN======== " << mirFunc->GetName() << std::endl; + } + + IPAEscapeAnalysis ipaEA(kh, irMap, func, eaMemPool, pcg); + ipaEA.ConstructConnGraph(); + func->GetMirFunc()->GetEACG()->TrimGlobalNode(); + if (!mirFunc->GetModule()->IsInIPA()) { + auto it = summaryMap.find(func->GetMirFunc()->GetNameStrIdx()); + if (it != summaryMap.end() && it->second != nullptr) { + it->second->DeleteEACG(); + } + } + if (!mirFunc->GetModule()->IsInIPA() && IPAEscapeAnalysis::kDebug) { + func->GetMirFunc()->GetEACG()->CountObjEAStatus(); + } + if (IPAEscapeAnalysis::kDebug) { + LogInfo::MapleLogger() << "=======IPAEA END========" << mirFunc->GetName() << std::endl; + } + + memPoolCtrler.DeleteMemPool(eaMemPool); + return nullptr; +} + +AnalysisResult *DoIpaEAOpt::Run(MeFunction *func, MeFuncResultMgr *mgr, ModuleResultMgr *mrm) { + if (func == nullptr) { + return nullptr; + } + MIRFunction *mirFunc = func->GetMirFunc(); + const std::map &summaryMap = mirFunc->GetModule()->GetEASummary(); + if (!mirFunc->GetModule()->IsInIPA() && summaryMap.size() == 0) { + return nullptr; + } + CHECK_FATAL(mrm != nullptr, "Needs module result manager for ipa"); + KlassHierarchy *kh = static_cast(mrm->GetAnalysisResult(MoPhase_CHA, &func->GetMIRModule())); + CHECK_FATAL(kh != nullptr, "KlassHierarchy phase has problem"); + MeIRMap *irMap = static_cast(mgr->GetAnalysisResult(MeFuncPhase_IRMAPBUILD, func)); + CHECK_FATAL(irMap != nullptr, "irMap phase has problem"); + + mgr->InvalidAnalysisResult(MeFuncPhase_MELOOP, func); + IdentifyLoops *meLoop = static_cast(mgr->GetAnalysisResult(MeFuncPhase_MELOOP, func)); + CHECK_FATAL(meLoop != nullptr, "meLoop phase has problem"); + meLoop->MarkBB(); + + CallGraph *pcg = nullptr; + if (mirFunc->GetModule()->IsInIPA()) { + pcg = static_cast(mrm->GetAnalysisResult(MoPhase_CALLGRAPH_ANALYSIS, &func->GetMIRModule())); + } + MemPool *eaMemPool = memPoolCtrler.NewMemPool(PhaseName()); + mirFunc->GetModule()->SetCurFunction(mirFunc); + + if (IPAEscapeAnalysis::kDebug) { + LogInfo::MapleLogger() << "=======IPAEAOPT BEGIN======== " << mirFunc->GetName() << std::endl; + } + + IPAEscapeAnalysis ipaEA(kh, irMap, func, eaMemPool, pcg); + ipaEA.DoOptimization(); + if (IPAEscapeAnalysis::kDebug) { + LogInfo::MapleLogger() << "=======IPAEAOPT END========" << mirFunc->GetName() << std::endl; + } + + memPoolCtrler.DeleteMemPool(eaMemPool); + return nullptr; +} +} diff --git a/src/mapleall/maple_ipa/src/ea_connection_graph.cpp b/src/mapleall/maple_ipa/src/ea_connection_graph.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ab5b06a3dbce4b72eb6b3cb3246e19c1e2c2af1a --- /dev/null +++ b/src/mapleall/maple_ipa/src/ea_connection_graph.cpp @@ -0,0 +1,1059 @@ +/* + * Copyright (c) [2019-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "ea_connection_graph.h" + +namespace maple { +constexpr maple::uint32 kInvalid = 0xffffffff; +void EACGBaseNode::CheckAllConnectionInNodes() { +#if DEBUG + for (EACGBaseNode *inNode : in) { + ASSERT_NOT_NULL(eaCG->nodes[inNode->id - 1]); + ASSERT(eaCG->nodes[inNode->id - 1] == inNode, "must be inNode"); + } + for (EACGBaseNode *outNode : out) { + ASSERT_NOT_NULL(eaCG->nodes[outNode->id - 1]); + ASSERT(eaCG->nodes[outNode->id - 1] == outNode, "must be outNode"); + } + for (EACGObjectNode *obj : pointsTo) { + ASSERT_NOT_NULL(eaCG->nodes[obj->id - 1]); + ASSERT(eaCG->nodes[obj->id - 1] == obj, "must be obj"); + } + if (IsFieldNode()) { + for (EACGObjectNode *obj : static_cast(this)->GetBelongsToObj()) { + ASSERT_NOT_NULL(eaCG->nodes[obj->id - 1]); + ASSERT(eaCG->nodes[obj->id - 1] == obj, "must be obj"); + } + } +#endif +} + +bool EACGBaseNode::AddOutNode(EACGBaseNode &newOut) { + if (out.find(&newOut) != out.end()) { + return false; + } + bool newIsLocal = newOut.UpdateEAStatus(eaStatus); + if (eaStatus == kGlobalEscape && pointsTo.size() > 0) { + if (newIsLocal) { + eaCG->SetCGUpdateFlag(); + } + return newIsLocal; + } + (void)out.insert(&newOut); + (void)newOut.in.insert(this); + ASSERT(newOut.pointsTo.size() != 0, "must be greater than zero"); + bool hasChanged = UpdatePointsTo(newOut.pointsTo); + eaCG->SetCGUpdateFlag(); + return hasChanged; +} + +void EACGBaseNode::PropagateEAStatusForNode(const EACGBaseNode*) const { + for (EACGBaseNode *outNode : out) { + outNode->UpdateEAStatus(eaStatus); + } +} + +std::string EACGBaseNode::GetName(const IRMap *irMap) const { + std::string name; + if (irMap == nullptr || meExpr == nullptr) { + name += std::to_string(id); + } else { + name += std::to_string(id); + name += "\\n"; + if (meExpr->GetMeOp() == kMeOpVar) { + VarMeExpr *varMeExpr = static_cast(meExpr); + const MIRSymbol *sym = varMeExpr->GetOst()->GetMIRSymbol(); + name += ((sym->GetStIdx().IsGlobal() ? "$" : "%") + sym->GetName() + "\\nmx" + + std::to_string(meExpr->GetExprID()) + " (field)" + std::to_string(varMeExpr->GetFieldID())); + } else if (meExpr->GetMeOp() == kMeOpIvar) { + IvarMeExpr *ivarMeExpr = static_cast(meExpr); + MeExpr *base = ivarMeExpr->GetBase(); + VarMeExpr *varMeExpr = nullptr; + if (base->GetMeOp() == kMeOpVar) { + varMeExpr = static_cast(base); + } else { + name += std::to_string(id); + return name; + } + const MIRSymbol *sym = varMeExpr->GetOst()->GetMIRSymbol(); + name += (std::string("base :") + (sym->GetStIdx().IsGlobal() ? "$" : "%") + sym->GetName() + "\\nmx" + + std::to_string(meExpr->GetExprID()) + " (field)" + std::to_string(ivarMeExpr->GetFieldID())); + } else if (meExpr->GetOp() == OP_gcmalloc || meExpr->GetOp() == OP_gcmallocjarray) { + name += "mx" + std::to_string(meExpr->GetExprID()); + } + } + return name; +} + +bool EACGBaseNode::UpdatePointsTo(const std::set &cPointsTo) { + uint32 oldPtSize = pointsTo.size(); + pointsTo.insert(cPointsTo.begin(), cPointsTo.end()); + if (oldPtSize == pointsTo.size()) { + return false; + } + for (EACGObjectNode *pt : pointsTo) { + pt->Insert2PointsBy(this); + } + for (EACGBaseNode *pred : in) { + pred->UpdatePointsTo(pointsTo); + } + return true; +} + +void EACGBaseNode::GetNodeFormatInDot(std::string &label, std::string &color) const { + switch (GetEAStatus()) { + case kNoEscape: + label += "NoEscape"; + color = "darkgreen"; + break; + case kArgumentEscape: + label += "ArgEscape"; + color = "brown"; + break; + case kReturnEscape: + label += "RetEscape"; + color = "orange"; + break; + case kGlobalEscape: + label += "GlobalEscape"; + color = "red"; + break; + } +} + +bool EACGBaseNode::CanIgnoreRC() const { + for (auto obj : pointsTo) { + if (!obj->GetIgnorRC()) { + return false; + } + } + return true; +} + +void EACGObjectNode::CheckAllConnectionInNodes() { +#if DEBUG + for (EACGBaseNode *inNode : in) { + ASSERT_NOT_NULL(eaCG->nodes[inNode->id - 1]); + ASSERT(eaCG->nodes[inNode->id - 1] == inNode, "must be inNode"); + } + for (EACGBaseNode *outNode : out) { + ASSERT_NOT_NULL(eaCG->nodes[outNode->id - 1]); + ASSERT(eaCG->nodes[outNode->id - 1] == outNode, "must be outNode"); + } + for (EACGBaseNode *pBy : pointsBy) { + ASSERT_NOT_NULL(eaCG->nodes[pBy->id - 1]); + ASSERT(eaCG->nodes[pBy->id - 1] == pBy, "must be pBy"); + } + for (auto fieldPair : fieldNodes) { + EACGFieldNode *field = fieldPair.second; + ASSERT(field->fieldID == fieldPair.first, "must be fieldPair.first"); + ASSERT_NOT_NULL(eaCG->nodes[field->id - 1]); + ASSERT(eaCG->nodes[field->id - 1] == field, "must be filed"); + } +#endif +} + +bool EACGObjectNode::IsPointedByFieldNode() const { + for (EACGBaseNode *pBy : pointsBy) { + if (pBy->IsFieldNode()) { + return true; + } + } + return false; +} + +bool EACGObjectNode::AddOutNode(EACGBaseNode &newOut) { + ASSERT(newOut.IsFieldNode(), "must be fieldNode"); + EACGFieldNode *field = static_cast(&newOut); + fieldNodes[field->GetFieldID()] = field; + newOut.UpdateEAStatus(eaStatus); + field->AddBelongTo(this); + return true; +} + +bool EACGObjectNode::ReplaceByGlobalNode() { + ASSERT(out.size() == 0, "must be zero"); + for (EACGBaseNode *node : pointsBy) { + node->pointsTo.erase(this); + (void)node->pointsTo.insert(eaCG->GetGlobalObject()); + } + pointsBy.clear(); + for (EACGBaseNode *inNode : in) { + (void)inNode->out.erase(this); + (void)inNode->out.insert(eaCG->GetGlobalObject()); + } + in.clear(); + for (auto fieldPair : fieldNodes) { + EACGFieldNode *field = fieldPair.second; + field->belongsTo.erase(this); + } + fieldNodes.clear(); + if (meExpr != nullptr) { + eaCG->expr2Nodes[meExpr]->clear(); + eaCG->expr2Nodes[meExpr]->insert(eaCG->GetGlobalObject()); + } + ASSERT(eaCG->nodes[id - 1] == this, "must be"); + eaCG->nodes[id - 1] = nullptr; + return true; +} + +void EACGObjectNode::PropagateEAStatusForNode(const EACGBaseNode*) const { + for (auto fieldNodePair : fieldNodes) { + EACGFieldNode *field = fieldNodePair.second; + field->UpdateEAStatus(eaStatus); + } +} + +void EACGObjectNode::DumpDotFile(std::ostream &fout, std::map &dumped, bool dumpPt, + const IRMap *irMap) { + if (dumped[this]) { + return; + } + dumped[this] = true; + + std::string name = GetName(nullptr); + std::string label; + label = GetName(irMap) + " Object\\n"; + std::string color; + GetNodeFormatInDot(label, color); + std::string style; + if (IsPhantom()) { + style = "dotted"; + } else { + style = "bold"; + } + fout << name << " [shape=box, label=\"" << label << "\", fontcolor=" << color << ", style=" << style << "];\n"; + for (auto fieldPair : fieldNodes) { + EACGBaseNode *field = fieldPair.second; + fout << name << "->" << field->GetName(nullptr) << ";" << "\n"; + } + for (auto fieldPair : fieldNodes) { + EACGBaseNode *field = fieldPair.second; + field->DumpDotFile(fout, dumped, dumpPt, irMap); + } +} + +void EACGRefNode::DumpDotFile(std::ostream &fout, std::map &dumped, bool dumpPt, + const IRMap *irMap) { + if (dumped[this]) { + return; + } + dumped[this] = true; + + std::string name = GetName(nullptr); + std::string label; + label = GetName(irMap) + " Reference\\n"; + if (IsStaticRef()) { + label += "Static\\n"; + } + std::string color; + GetNodeFormatInDot(label, color); + fout << name << " [shape=ellipse, label=\"" << label << "\", fontcolor=" << color << "];" << "\n"; + if (dumpPt) { + for (auto obj : pointsTo) { + fout << name << "->" << obj->GetName(nullptr) << ";" << "\n"; + } + for (auto obj : pointsTo) { + obj->DumpDotFile(fout, dumped, dumpPt, irMap); + } + } else { + for (auto outNode : out) { + std::string edgeStyle; + if (!outNode->IsObjectNode()) { + edgeStyle = " [style =\"dotted\"]"; + } + fout << name << "->" << outNode->GetName(nullptr) << edgeStyle << ";" << "\n"; + } + for (auto outNode : out) { + outNode->DumpDotFile(fout, dumped, dumpPt, irMap); + } + } +} + +bool EACGRefNode::ReplaceByGlobalNode() { + for (EACGBaseNode *inNode : in) { + ASSERT(inNode->id > 3, "must be greater than three"); // the least valid idx is 3 + (void)inNode->out.erase(this); + (void)inNode->out.insert(eaCG->GetGlobalReference()); + } + in.clear(); + for (EACGBaseNode *outNode : out) { + (void)outNode->in.erase(this); + } + out.clear(); + for (EACGObjectNode *base : pointsTo) { + base->EraseNodeFromPointsBy(this); + } + pointsTo.clear(); + if (meExpr != nullptr) { + eaCG->expr2Nodes[meExpr]->clear(); + eaCG->expr2Nodes[meExpr]->insert(eaCG->GetGlobalReference()); + } + ASSERT(eaCG->nodes[id - 1] == this, "must be this"); + eaCG->nodes[id - 1] = nullptr; + return true; +} + +void EACGPointerNode::DumpDotFile(std::ostream &fout, std::map &dumped, bool dumpPt, + const IRMap *irMap) { + if (dumped[this]) { + return; + } + dumped[this] = true; + std::string name = GetName(nullptr); + std::string label; + label = GetName(irMap) + "\\nPointer Indirect Level : " + std::to_string(indirectLevel) + "\\n"; + std::string color; + GetNodeFormatInDot(label, color); + fout << name << " [shape=ellipse, label=\"" << label << "\", fontcolor=" << color << "];" << "\n"; + for (EACGBaseNode *outNode : out) { + fout << name << "->" << outNode->GetName(nullptr) << " [style =\"dotted\", color = \"blue\"];" << "\n"; + } + for (auto outNode : out) { + outNode->DumpDotFile(fout, dumped, dumpPt, irMap); + } +} + +void EACGActualNode::DumpDotFile(std::ostream &fout, std::map &dumped, bool dumpPt, + const IRMap *irMap) { + if (dumped[this]) { + return; + } + dumped[this] = true; + + std::string name = GetName(nullptr); + std::string label; + if (IsReturn()) { + label = GetName(irMap) + "\\nRet Idx : " + std::to_string(GetArgIndex()) + "\\n"; + } else { + label = GetName(irMap) + "\\nArg Idx : " + std::to_string(GetArgIndex()) + + " Call Site : " + std::to_string(GetCallSite()) + "\\n"; + } + std::string style; + if (IsPhantom()) { + style = "dotted"; + } else { + style = "bold"; + } + std::string color; + GetNodeFormatInDot(label, color); + fout << name << " [shape=ellipse, label=\"" << label << "\", fontcolor=" << color << ", style=" << style << "];\n"; + if (dumpPt) { + for (auto obj : pointsTo) { + fout << name << "->" << obj->GetName(nullptr) << ";\n"; + } + for (auto obj : pointsTo) { + obj->DumpDotFile(fout, dumped, dumpPt, irMap); + } + } else { + for (auto outNode : out) { + std::string edgeStyle; + if (!outNode->IsObjectNode()) { + edgeStyle = " [style =\"dotted\"]"; + } + fout << name << "->" << outNode->GetName(nullptr) << edgeStyle << ";\n"; + } + for (auto outNode : out) { + outNode->DumpDotFile(fout, dumped, dumpPt, irMap); + } + } +} + +bool EACGActualNode::ReplaceByGlobalNode() { + ASSERT(callSiteInfo == kInvalid, "must be invalid"); + ASSERT(out.size() == 1, "the size of out must be one"); + ASSERT(pointsTo.size() == 1, "the size of pointsTo must be one"); + for (EACGBaseNode *inNode : in) { + inNode->out.erase(this); + } + in.clear(); + return false; +} + +void EACGFieldNode::DumpDotFile(std::ostream &fout, std::map &dumped, bool dumpPt, + const IRMap *irMap) { + if (dumped[this]) { + return; + } + dumped[this] = true; + std::string name = GetName(nullptr); + std::string label; + label = GetName(irMap) + "\\nFIdx : " + std::to_string(GetFieldID()) + "\\n"; + std::string color; + GetNodeFormatInDot(label, color); + std::string style; + if (IsPhantom()) { + style = "dotted"; + } else { + style = "bold"; + } + fout << name << " [shape=circle, label=\"" << label << "\", fontcolor=" << color << ", style=" << style << + ", margin=0];\n"; + if (dumpPt) { + for (auto obj : pointsTo) { + fout << name << "->" << obj->GetName(nullptr) << ";\n"; + } + for (auto obj : pointsTo) { + obj->DumpDotFile(fout, dumped, dumpPt, irMap); + } + } else { + for (auto outNode : out) { + std::string edgeStyle; + if (!outNode->IsObjectNode()) { + edgeStyle = " [style =\"dotted\"]"; + } + fout << name << "->" << outNode->GetName(nullptr) << edgeStyle << ";\n"; + } + for (auto outNode : out) { + outNode->DumpDotFile(fout, dumped, dumpPt, irMap); + } + } +} + +bool EACGFieldNode::ReplaceByGlobalNode() { + for (EACGObjectNode *obj : pointsTo) { + obj->pointsBy.erase(this); + } + pointsTo.clear(); + (void)pointsTo.insert(eaCG->GetGlobalObject()); + for (EACGBaseNode *outNode : out) { + outNode->in.erase(this); + } + out.clear(); + (void)out.insert(eaCG->GetGlobalObject()); + bool canDelete = true; + std::set tmp = belongsTo; + for (EACGObjectNode *obj : tmp) { + if (obj->GetEAStatus() != kGlobalEscape) { + canDelete = false; + } else { + belongsTo.erase(obj); + } + } + if (canDelete) { + ASSERT(eaCG->nodes[id - 1] == this, "must be this"); + eaCG->nodes[id - 1] = nullptr; + for (EACGBaseNode *inNode : in) { + ASSERT(!inNode->IsObjectNode(), "must be ObjectNode"); + inNode->out.erase(this); + (void)inNode->out.insert(eaCG->globalField); + } + for (auto exprPair : eaCG->expr2Nodes) { + size_t eraseSize = exprPair.second->erase(this); + if (eraseSize != 0 && exprPair.first->GetMeOp() != kMeOpIvar && exprPair.first->GetMeOp() != kMeOpOp) { + ASSERT(false, "must be kMeOpIvar or kMeOpOp"); + } + if (exprPair.second->size() == 0) { + exprPair.second->insert(eaCG->globalField); + } + } + in.clear(); + return true; + } + return false; +} + +void EAConnectionGraph::DeleteEACG() const { + for (EACGBaseNode *node : nodes) { + if (node == nullptr) { + continue; + } + delete node; + node = nullptr; + } +} + +void EAConnectionGraph::TrimGlobalNode() const { + for (EACGBaseNode *node : nodes) { + if (node == nullptr) { + continue; + } + constexpr int leastIdx = 3; + if (node->id <= leastIdx) { + continue; + } + bool canDelete = false; + if (node->GetEAStatus() == kGlobalEscape) { + canDelete = node->ReplaceByGlobalNode(); + } +#ifdef DEBUG + node->CheckAllConnectionInNodes(); +#endif + if (canDelete) { + delete node; + node = nullptr; + } + } +} + +void EAConnectionGraph::InitGlobalNode() { + globalObj = CreateObjectNode(nullptr, kNoEscape, true, TyIdx(0)); + globalRef = CreateReferenceNode(nullptr, kNoEscape, true); + globalRef->AddOutNode(*globalObj); + globalRef->AddOutNode(*globalRef); + globalField = CreateFieldNode(nullptr, kNoEscape, -1, globalObj, true); // -1 expresses global + globalField->AddOutNode(*globalObj); + globalField->AddOutNode(*globalRef); + globalField->AddOutNode(*globalField); + globalRef->AddOutNode(*globalField); + globalObj->eaStatus = kGlobalEscape; + globalField->eaStatus = kGlobalEscape; + globalRef->eaStatus = kGlobalEscape; +} + +EACGObjectNode *EAConnectionGraph::CreateObjectNode(MeExpr *expr, EAStatus initialEas, bool isPh, TyIdx) { + EACGObjectNode *newObjNode = + new (std::nothrow) EACGObjectNode(mirModule, alloc, *this, expr, initialEas, nodes.size() + 1, isPh); + ASSERT_NOT_NULL(newObjNode); + nodes.push_back(newObjNode); + if (expr != nullptr) { + if (expr2Nodes.find(expr) == expr2Nodes.end()) { + expr2Nodes[expr] = alloc->GetMemPool()->New>(alloc->Adapter()); + expr2Nodes[expr]->insert(newObjNode); + } else { + ASSERT(false, "must find expr"); + } + } + return newObjNode; +} + +EACGPointerNode *EAConnectionGraph::CreatePointerNode(MeExpr *expr, EAStatus initialEas, int inderictL) { + EACGPointerNode *newPointerNode = + new (std::nothrow) EACGPointerNode(mirModule, alloc, *this, expr, initialEas, nodes.size() + 1, inderictL); + ASSERT_NOT_NULL(newPointerNode); + nodes.push_back(newPointerNode); + if (expr != nullptr) { + if (expr2Nodes.find(expr) == expr2Nodes.end()) { + expr2Nodes[expr] = alloc->GetMemPool()->New>(alloc->Adapter()); + expr2Nodes[expr]->insert(newPointerNode); + } else { + ASSERT(false, "must find expr"); + } + } + return newPointerNode; +} + +EACGRefNode *EAConnectionGraph::CreateReferenceNode(MeExpr *expr, EAStatus initialEas, bool isStatic) { + EACGRefNode *newRefNode = + new (std::nothrow) EACGRefNode(mirModule, alloc, *this, expr, initialEas, nodes.size() + 1, isStatic); + ASSERT_NOT_NULL(newRefNode); + nodes.push_back(newRefNode); + if (expr != nullptr) { + if (expr2Nodes.find(expr) == expr2Nodes.end()) { + expr2Nodes[expr] = alloc->GetMemPool()->New>(alloc->Adapter()); + expr2Nodes[expr]->insert(newRefNode); + } else { + ASSERT(false, "must find expr"); + } + if (expr->GetMeOp() != kMeOpVar && expr->GetMeOp() != kMeOpAddrof && + expr->GetMeOp() != kMeOpReg && expr->GetMeOp() != kMeOpOp) { + ASSERT(false, "must be kMeOpVar, kMeOpAddrof, kMeOpReg or kMeOpOp"); + } + } + return newRefNode; +} + +void EAConnectionGraph::TouchCallSite(uint32 callSiteInfo) { + CHECK_FATAL(callSite2Nodes.find(callSiteInfo) != callSite2Nodes.end(), "find failed"); + if (callSite2Nodes[callSiteInfo] == nullptr) { + MapleVector *tmp = alloc->GetMemPool()->New>(alloc->Adapter()); + callSite2Nodes[callSiteInfo] = tmp; + } +} + +EACGActualNode *EAConnectionGraph::CreateActualNode(EAStatus initialEas, bool isReurtn, bool isPh, + uint8 argIdx, uint32 callSiteInfo) { + MeExpr *expr = nullptr; + ASSERT(isPh, "must be ph"); + ASSERT(callSiteInfo != 0, "must not be zero"); + EACGActualNode *newActNode = new (std::nothrow) EACGActualNode( + mirModule, alloc, *this, expr, initialEas, nodes.size() + 1, isReurtn, isPh, argIdx, callSiteInfo); + ASSERT_NOT_NULL(newActNode); + nodes.push_back(newActNode); + if (expr != nullptr) { + if (expr2Nodes.find(expr) == expr2Nodes.end()) { + expr2Nodes[expr] = alloc->GetMemPool()->New>(alloc->Adapter()); + expr2Nodes[expr]->insert(newActNode); + } else { + ASSERT(false, "must find expr"); + } + } + if (callSiteInfo != kInvalid) { + ASSERT(callSite2Nodes[callSiteInfo] != nullptr, "must touched before"); + callSite2Nodes[callSiteInfo]->push_back(newActNode); +#ifdef DEBUG + CheckArgNodeOrder(*callSite2Nodes[callSiteInfo]); +#endif + } else { + funcArgNodes.push_back(newActNode); + } + return newActNode; +} + +EACGFieldNode *EAConnectionGraph::CreateFieldNode(MeExpr *expr, EAStatus initialEas, FieldID fId, + EACGObjectNode *belongTo, bool isPh) { + EACGFieldNode *newFieldNode = new (std::nothrow) EACGFieldNode( + mirModule, alloc, *this, expr, initialEas, nodes.size() + 1, fId, belongTo, isPh); + ASSERT_NOT_NULL(newFieldNode); + nodes.push_back(newFieldNode); + if (expr != nullptr) { + if (expr2Nodes.find(expr) == expr2Nodes.end()) { + expr2Nodes[expr] = alloc->GetMemPool()->New>(alloc->Adapter()); + expr2Nodes[expr]->insert(newFieldNode); + } else { + expr2Nodes[expr]->insert(newFieldNode); + } + if (expr->GetMeOp() != kMeOpIvar && expr->GetMeOp() != kMeOpOp) { + ASSERT(false, "must be kMeOpIvar or kMeOpOp"); + } + } + return newFieldNode; +} + +EACGBaseNode *EAConnectionGraph::GetCGNodeFromExpr(MeExpr *me) { + if (expr2Nodes.find(me) == expr2Nodes.end()) { + return nullptr; + } + return *(expr2Nodes[me]->begin()); +} + +void EAConnectionGraph::UpdateExprOfNode(EACGBaseNode &node, MeExpr *me) { + if (expr2Nodes.find(me) == expr2Nodes.end()) { + expr2Nodes[me] = alloc->GetMemPool()->New>(alloc->Adapter()); + expr2Nodes[me]->insert(&node); + } else { + if (node.IsFieldNode()) { + expr2Nodes[me]->insert(&node); + } else { + if (expr2Nodes[me]->find(&node) == expr2Nodes[me]->end()) { + CHECK_FATAL(false, "must be filed node"); + } + } + } + node.SetMeExpr(*me); +} + +void EAConnectionGraph::UpdateExprOfGlobalRef(MeExpr *me) { + UpdateExprOfNode(*globalRef, me); +} + +EACGActualNode *EAConnectionGraph::GetReturnNode() const { + if (funcArgNodes.size() == 0) { + return nullptr; + } + EACGActualNode *ret = static_cast(funcArgNodes[funcArgNodes.size() - 1]); + if (ret->IsReturn()) { + return ret; + } + return nullptr; +} +#ifdef DEBUG +void EAConnectionGraph::CheckArgNodeOrder(MapleVector &funcArgV) { + uint8 preIndex = 0; + for (size_t i = 0; i < funcArgV.size(); ++i) { + ASSERT(funcArgV[i]->IsActualNode(), "must be ActualNode"); + EACGActualNode *actNode = static_cast(funcArgV[i]); + if (i == funcArgV.size() - 1) { + if (actNode->IsReturn()) { + continue; + } else { + ASSERT(actNode->GetArgIndex() >= preIndex, "must be greater than preIndex"); + } + } else { + ASSERT(!actNode->IsReturn(), "must be return"); + ASSERT(actNode->GetArgIndex() >= preIndex, "must be greater than preIndex"); + } + preIndex = actNode->GetArgIndex(); + } +} +#endif +bool EAConnectionGraph::ExprCanBeOptimized(MeExpr &expr) { + if (expr2Nodes.find(&expr) == expr2Nodes.end()) { + MeExpr *rhs = nullptr; + if (expr.GetMeOp() == kMeOpVar) { + ASSERT(static_cast(&expr)->GetDefBy() == kDefByStmt, "must be kDefByStmt"); + ASSERT(static_cast(&expr)->GetDefStmt()->GetOp() == OP_dassign, "must be OP_dassign"); + MeStmt *defStmt = static_cast(&expr)->GetDefStmt(); + DassignMeStmt *dassignStmt = static_cast(defStmt); + rhs = dassignStmt->GetRHS(); + } else if (expr.GetMeOp() == kMeOpReg) { + ASSERT(static_cast(&expr)->GetDefBy() == kDefByStmt, "must be kDefByStmt"); + ASSERT(static_cast(&expr)->GetDefStmt()->GetOp() == OP_regassign, "must be OP_regassign"); + MeStmt *defStmt = static_cast(&expr)->GetDefStmt(); + RegassignMeStmt *regassignStmt = static_cast(defStmt); + rhs = regassignStmt->GetRHS(); + } else { + CHECK_FATAL(false, "impossible"); + } + ASSERT(expr2Nodes.find(rhs) != expr2Nodes.end(), "impossible"); + expr = *rhs; + } + MapleSet &nodesTmp = *expr2Nodes[&expr]; + + for (EACGBaseNode *node : nodesTmp) { + for (EACGObjectNode *obj : node->GetPointsToSet()) { + if (obj->GetEAStatus() != kNoEscape && obj->GetEAStatus() != kReturnEscape) { + return false; + } + } + } + return true; +} + +MapleVector *EAConnectionGraph::GetCallSiteArgNodeVector(uint32 callSite) { + CHECK_FATAL(callSite2Nodes.find(callSite) != callSite2Nodes.end(), "find failed"); + ASSERT_NOT_NULL(callSite2Nodes[callSite]); + return callSite2Nodes[callSite]; +} + +// if we have scc of connection graph, it will be more efficient. +void EAConnectionGraph::PropogateEAStatus() { + bool oldStatus = CGHasUpdated(); + do { + UnSetCGUpdateFlag(); + for (EACGBaseNode *node : nodes) { + if (node == nullptr) { + continue; + } + if (node->IsObjectNode()) { + EACGObjectNode *obj = static_cast(node); + for (auto fieldPair : obj->GetFieldNodeMap()) { + EACGBaseNode *field = fieldPair.second; + field->UpdateEAStatus(obj->GetEAStatus()); + } + } else { + for (EACGBaseNode *pointsToNode : node->GetPointsToSet()) { + pointsToNode->UpdateEAStatus(node->GetEAStatus()); + } + } + } + ASSERT(!CGHasUpdated(), "must be Updated"); + } while (CGHasUpdated()); + RestoreStatus(oldStatus); +} + +const MapleVector *EAConnectionGraph::GetFuncArgNodeVector() const { + return &funcArgNodes; +} + +// this func is called from callee context +void EAConnectionGraph::UpdateEACGFromCaller(const MapleVector &callerCallSiteArg, + const MapleVector &calleeFuncArg) { + ASSERT(abs(static_cast(callerCallSiteArg.size()) - static_cast(calleeFuncArg.size())) <= 1, "greater than"); + + UnSetCGUpdateFlag(); + for (uint32 i = 0; i < callerCallSiteArg.size(); ++i) { + EACGBaseNode *callerNode = callerCallSiteArg[i]; + ASSERT_NOT_NULL(callerNode); + ASSERT(callerNode->IsActualNode(), "must be ActualNode"); + if ((i == callerCallSiteArg.size() - 1) && static_cast(callerNode)->IsReturn()) { + continue; + } + bool hasGlobalEA = false; + for (EACGObjectNode *obj : callerNode->GetPointsToSet()) { + if (obj->GetEAStatus() == kGlobalEscape) { + hasGlobalEA = true; + break; + } + } + if (hasGlobalEA) { + EACGBaseNode *calleeNode = (calleeFuncArg)[i]; + for (EACGObjectNode *obj : calleeNode->GetPointsToSet()) { + obj->UpdateEAStatus(kGlobalEscape); + } + } + } + if (CGHasUpdated()) { + PropogateEAStatus(); + } + TrimGlobalNode(); +} + +void EAConnectionGraph::DumpDotFile(const IRMap *irMap, bool dumpPt, MapleVector *dumpVec) { + if (dumpVec == nullptr) { + dumpVec = &nodes; + } + std::filebuf fb; + std::string outFile = GlobalTables::GetStrTable().GetStringFromStrIdx(funcStIdx) + "-connectiongraph.dot"; + fb.open(outFile, std::ios::trunc | std::ios::out); + CHECK_FATAL(fb.is_open(), "open file failed"); + std::ostream cgDotFile(&fb); + cgDotFile << "digraph connectiongraph{\n"; + std::map dumped; + for (auto node : nodes) { + dumped[node] = false; + } + for (EACGBaseNode *node : *dumpVec) { + if (node == nullptr) { + continue; + } + if (dumped[node]) { + continue; + } + node->DumpDotFile(cgDotFile, dumped, dumpPt, irMap); + dumped[node] = true; + } + cgDotFile << "}\n"; + fb.close(); +} + +void EAConnectionGraph::CountObjEAStatus() const { + int sum = 0; + int eaCount[4]; // There are four EAStatus. + for (size_t i = 0; i < 4; ++i) { + eaCount[i] = 0; + } + for (EACGBaseNode *node : nodes) { + if (node == nullptr) { + continue; + } + + if (node->IsObjectNode()) { + EACGObjectNode *objNode = static_cast(node); + if (!objNode->IsPhantom()) { + CHECK_FATAL(objNode->locInfo != nullptr, "Impossible"); + MIRType *type = nullptr; + const MeExpr *expr = objNode->GetMeExpr(); + CHECK_FATAL(expr != nullptr, "Impossible"); + if (expr->GetOp() == OP_gcmalloc || expr->GetOp() == OP_gcpermalloc) { + TyIdx tyIdx = static_cast(expr)->GetTyIdx(); + type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx); + } else { + TyIdx tyIdx = static_cast(expr)->GetTyIdx(); + type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx); + } + LogInfo::MapleLogger() << "[LOCATION] [" << objNode->locInfo->GetModName() << " " << + objNode->locInfo->GetFileId() << " " << objNode->locInfo->GetLineId() << " " << + EscapeName(objNode->GetEAStatus()) << " " << expr->GetExprID() << " "; + type->Dump(0, false); + LogInfo::MapleLogger() << "]\n"; + ++sum; + ++eaCount[node->GetEAStatus()]; + } + } + } + LogInfo::MapleLogger() << "[gcmalloc object statistics] " << + GlobalTables::GetStrTable().GetStringFromStrIdx(funcStIdx) << " " << + "Gcmallocs: " << sum << " " << "NoEscape: " << eaCount[kNoEscape] << " " << + "RetEscape: " << eaCount[kReturnEscape] << " " << "ArgEscape: " << eaCount[kArgumentEscape] << " " << + "GlobalEscape: " << eaCount[kGlobalEscape] << "\n"; +} + +void EAConnectionGraph::RestoreStatus(bool old) { + if (old) { + SetCGHasUpdated(); + } else { + UnSetCGUpdateFlag(); + } +} + +// Update caller's ConnectionGraph using callee's summary information. +// If the callee's summary is not found, we just mark all the pointsTo nodes of caller's actual node to GlobalEscape. +// Otherwise, we do these steps: +// +// 1, update caller nodes using callee's summary, new node might be added into caller's CG in this step. +// +// 2, update caller edges using callee's summary, new points-to edge might be added into caller's CG in this step. +bool EAConnectionGraph::MergeCG(MapleVector &caller, const MapleVector *callee) { + TrimGlobalNode(); + bool cgChanged = false; + bool oldStatus = CGHasUpdated(); + UnSetCGUpdateFlag(); + if (callee == nullptr) { + for (EACGBaseNode *actualInCaller : caller) { + for (EACGObjectNode *p : actualInCaller->GetPointsToSet()) { + p->UpdateEAStatus(EAStatus::kGlobalEscape); + } + } + cgChanged = CGHasUpdated(); + if (!cgChanged) { + RestoreStatus(oldStatus); + } + TrimGlobalNode(); + return cgChanged; + } + size_t callerSize = caller.size(); + size_t calleeSize = callee->size(); + if (callerSize > calleeSize) { + ASSERT((callerSize - calleeSize) <= 1, "must be one in EAConnectionGraph::MergeCG()"); + } else { + ASSERT((calleeSize - callerSize) <= 1, "must be one in EAConnectionGraph::MergeCG()"); + } + if (callerSize == 0 || calleeSize == 0) { + cgChanged = CGHasUpdated(); + if (!cgChanged) { + RestoreStatus(oldStatus); + } + return cgChanged; + } + if ((callerSize != calleeSize) && + (callerSize != calleeSize + 1 || static_cast(callee->back())->IsReturn()) && + (callerSize != calleeSize - 1 || !static_cast(callee->back())->IsReturn())) { + ASSERT(false, "Impossible"); + } + + callee2Caller.clear(); + UpdateCallerNodes(caller, *callee); + UpdateCallerEdges(); + UpdateCallerRetNode(caller, *callee); + callee2Caller.clear(); + + cgChanged = CGHasUpdated(); + if (!cgChanged) { + RestoreStatus(oldStatus); + } + TrimGlobalNode(); + return cgChanged; +} + +void EAConnectionGraph::AddMaps2Object(EACGObjectNode *caller, EACGObjectNode *callee) { + if (callee2Caller.find(callee) == callee2Caller.end()) { + std::set callerSet; + callee2Caller[callee] = callerSet; + } + (void)callee2Caller[callee].insert(caller); +} + +void EAConnectionGraph::UpdateCallerRetNode(MapleVector &caller, + const MapleVector &callee) { + EACGActualNode *lastInCaller = static_cast(caller.back()); + EACGActualNode *lastInCallee = static_cast(callee.back()); + if (!lastInCaller->IsReturn()) { + return; + } + CHECK_FATAL(lastInCaller->GetOutSet().size() == 1, "Impossible"); + for (EACGBaseNode *callerRetNode : lastInCaller->GetOutSet()) { + for (EACGObjectNode *calleeRetNode : lastInCallee->GetPointsToSet()) { + for (EACGObjectNode *objInCaller : callee2Caller[calleeRetNode]) { + auto pointsToSet = callerRetNode->GetPointsToSet(); + if (pointsToSet.find(objInCaller) == pointsToSet.end()) { + callerRetNode->AddOutNode(*objInCaller); + } + } + } + } +} + +// Update caller node by adding some nodes which are mapped from callee. +void EAConnectionGraph::UpdateCallerNodes(const MapleVector &caller, + const MapleVector &callee) { + const size_t callerSize = caller.size(); + const size_t calleeSize = callee.size(); + const size_t actualCount = ((callerSize < calleeSize) ? callerSize : calleeSize); + bool firstTime = true; + + for (size_t i = 0; i < actualCount; ++i) { + EACGBaseNode *actualInCaller = caller.at(i); + EACGBaseNode *actualInCallee = callee.at(i); + UpdateNodes(*actualInCallee, *actualInCaller, firstTime); + } +} + +// Update caller edges using information from callee. +void EAConnectionGraph::UpdateCallerEdges() { + std::set set; + for (auto pair : callee2Caller) { + (void)set.insert(pair.first); + } + for (EACGObjectNode *p : set) { + for (auto tempPair : p->GetFieldNodeMap()) { + uint32 fieldID = tempPair.first; + EACGBaseNode *fieldNode = tempPair.second; + for (EACGObjectNode *q : fieldNode->GetPointsToSet()) { + UpdateCallerEdgesInternal(p, fieldID, q); + } + } + } +} + +// Update caller edges using information of given ObjectNode from callee. +void EAConnectionGraph::UpdateCallerEdgesInternal(EACGObjectNode *node1, uint32 fieldID, EACGObjectNode *node2) { + CHECK_FATAL(callee2Caller.find(node1) != callee2Caller.end(), "find failed"); + CHECK_FATAL(callee2Caller.find(node2) != callee2Caller.end(), "find failed"); + for (EACGObjectNode *p1 : callee2Caller[node1]) { + for (EACGObjectNode *q1 : callee2Caller[node2]) { + EACGFieldNode *fieldNode = p1->GetFieldNodeFromIdx(fieldID); + if (fieldNode == nullptr) { + CHECK_NULL_FATAL(node1); + fieldNode = node1->GetFieldNodeFromIdx(fieldID); + CHECK_FATAL(fieldNode != nullptr, "fieldNode must not be nullptr because we have handled it before!"); + CHECK_FATAL(fieldNode->IsBelongTo(this), "must be belong to this"); + p1->AddOutNode(*fieldNode); + } + fieldNode->AddOutNode(*q1); + } + } +} + +void EAConnectionGraph::UpdateNodes(const EACGBaseNode &actualInCallee, EACGBaseNode &actualInCaller, bool firstTime) { + ASSERT(actualInCallee.GetPointsToSet().size() > 0, "actualInCallee->GetPointsToSet().size() must gt 0!"); + for (EACGObjectNode *objInCallee : actualInCallee.GetPointsToSet()) { + if (actualInCaller.GetPointsToSet().size() == 0) { + std::set &mapsTo = callee2Caller[objInCallee]; + if (mapsTo.size() > 0) { + for (EACGObjectNode *temp : mapsTo) { + actualInCaller.AddOutNode(*temp); + } + } else if (objInCallee->IsBelongTo(this)) { + ASSERT(false, "must be belong to this"); + } else { + EACGObjectNode *phantom = CreateObjectNode(nullptr, actualInCaller.GetEAStatus(), true, TyIdx(0)); + actualInCaller.AddOutNode(*phantom); + AddMaps2Object(phantom, objInCallee); + UpdateCallerWithCallee(*phantom, *objInCallee, firstTime); + } + } else { + for (EACGObjectNode *objInCaller : actualInCaller.GetPointsToSet()) { + std::set &mapsTo = callee2Caller[objInCallee]; + if (mapsTo.find(objInCaller) == mapsTo.end()) { + AddMaps2Object(objInCaller, objInCallee); + UpdateCallerWithCallee(*objInCaller, *objInCallee, firstTime); + } + } + } + } +} + +// The escape state of the nodes in MapsTo(which is the object node in caller) is marked +// GlobalEscape if the escape state of object node in callee is GlobalEscape. +// Otherwise, the escape state of the caller nodes is not affected. +void EAConnectionGraph::UpdateCallerWithCallee(EACGObjectNode &objInCaller, const EACGObjectNode &objInCallee, + bool firstTime) { + if (objInCallee.GetEAStatus() == EAStatus::kGlobalEscape) { + objInCaller.UpdateEAStatus(EAStatus::kGlobalEscape); + } + + // At this moment, a node in caller is mapped to the corresponding node in callee, + // we need make sure that all the field nodes also exist in caller. If not, + // we create both the field node and the phantom object node it should point to for the caller. + for (auto tempPair : objInCallee.GetFieldNodeMap()) { + EACGFieldNode *fieldInCaller = objInCaller.GetFieldNodeFromIdx(tempPair.first); + EACGFieldNode *fieldInCallee = tempPair.second; + if (fieldInCaller == nullptr && fieldInCallee->IsBelongTo(this)) { + objInCaller.AddOutNode(*fieldInCallee); + } + fieldInCaller = GetOrCreateFieldNodeFromIdx(objInCaller, tempPair.first); + UpdateNodes(*fieldInCallee, *fieldInCaller, firstTime); + } +} + +EACGFieldNode *EAConnectionGraph::GetOrCreateFieldNodeFromIdx(EACGObjectNode &obj, uint32 fieldID) { + EACGFieldNode *ret = obj.GetFieldNodeFromIdx(fieldID); + if (ret == nullptr) { + // this node is always phantom + ret = CreateFieldNode(nullptr, obj.GetEAStatus(), fieldID, &obj, true); + } + return ret; +} +} // namespace maple diff --git a/src/mapleall/maple_ipa/src/inline.cpp b/src/mapleall/maple_ipa/src/inline.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f0501865979f7f51fff0c5b86359939fe3370a28 --- /dev/null +++ b/src/mapleall/maple_ipa/src/inline.cpp @@ -0,0 +1,1410 @@ +/* + * Copyright (c) [2019-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "inline.h" +#include +#include +#include "mpl_logging.h" +#include "global_tables.h" + +namespace maple { +// This phase replaces a function call site with the body of the called function. +// Step 0: See if CALLEE have been inlined to CALLER once. +// Step 1: Clone CALLEE's body. +// Step 2: Rename symbols, labels, pregs. +// Step 3: Replace symbols, labels, pregs. +// Step 4: Null check 'this' and assign actuals to formals. +// Step 5: Insert the callee'return jump dest label. +// Step 6: Handle return values. +// Step 7: Remove the successive goto statement and label statement in some circumstances. +// Step 8: Replace the call-stmt with new CALLEE'body. +// Step 9: Update inlined_times. +constexpr uint32 kHalfInsn = 1; +constexpr uint32 kOneInsn = 2; +constexpr uint32 kDoubleInsn = 4; +constexpr uint32 kQuadrupleInsn = 8; +constexpr uint32 kPentupleInsn = 10; + +static bool IsFinalMethod(const MIRFunction *mirFunc) { + if (mirFunc == nullptr) { + return false; + } + const auto *cType = static_cast(mirFunc->GetClassType()); + // Return true if the method or its class is declared as final + return (cType != nullptr && (mirFunc->IsFinal() || cType->IsFinal())); +} + +void MInline::Init() { + InitParams(); + if (inlineWithProfile) { + InitProfile(); + } + InitRCWhiteList(); + InitExcludedCaller(); + InitExcludedCallee(); +} + +void MInline::InitParams() { + dumpDetail = (Options::dumpPhase == "inline"); + dumpFunc = Options::dumpFunc; + inlineFuncList = MeOption::inlineFuncList; + noInlineFuncList = Options::noInlineFuncList; + smallFuncThreshold = Options::inlineSmallFunctionThreshold; + hotFuncThreshold = Options::inlineHotFunctionThreshold; + recursiveFuncThreshold = Options::inlineRecursiveFunctionThreshold; + inlineWithProfile = Options::inlineWithProfile; +} + +void MInline::InitProfile() const { + uint32 dexNameIdx = module.GetFileinfo(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName("INFO_filename")); + const std::string &dexName = GlobalTables::GetStrTable().GetStringFromStrIdx(GStrIdx(dexNameIdx)); + bool deCompressSucc = module.GetProfile().DeCompress(Options::profile, dexName); + LogInfo::MapleLogger() << "dexName: " << dexName << '\n'; + if (!deCompressSucc) { + LogInfo::MapleLogger() << "WARN: DeCompress() failed in DoInline::Run()\n"; + } +} + +void MInline::InitRCWhiteList() { + std::set whitelistFunc{ +#include "rcwhitelist.def" + }; + for (auto it = whitelistFunc.begin(); it != whitelistFunc.end(); ++it) { + GStrIdx strIdx = GlobalTables::GetStrTable().GetStrIdxFromName(*it); + (void)rcWhiteList.insert(strIdx); + } +} + +void MInline::InitExcludedCaller() { + std::set specialfunc = { + std::string("Landroid_2Fcontent_2Fpm_2FFallbackCategoryProvider_3B_7CloadFallbacks_7C_28_29V"), + }; + for (auto it = specialfunc.begin(); it != specialfunc.end(); ++it) { + GStrIdx strIdx = GlobalTables::GetStrTable().GetStrIdxFromName(*it); + (void)excludedCaller.insert(strIdx); + } +} + +void MInline::InitExcludedCallee() { + std::set excludedFunc{ +#include "castcheck_whitelist.def" +#define PROPILOAD(funcname) #funcname, +#include "propiloadlist.def" +#undef PROPILOAD +#define DEF_MIR_INTRINSIC(X, NAME, INTRN_CLASS, RETURN_TYPE, ...) NAME, +#include "simplifyintrinsics.def" +#undef DEF_MIR_INTRINSIC + }; + for (auto it = excludedFunc.begin(); it != excludedFunc.end(); ++it) { + GStrIdx strIdx = GlobalTables::GetStrTable().GetStrIdxFromName(*it); + (void)excludedCallee.insert(strIdx); + } + std::set setArrayHotFunc = { + std::string("Landroid_2Ficu_2Fimpl_2Fduration_2FBasicDurationFormat_3B_7CformatDuration_7C_28Ljava_2Flang_2FObject_3B_29Ljava_2Flang_2FString_3B"), + std::string("Landroid_2Fapp_2FIActivityManager_24Stub_3B_7ConTransact_7C_28ILandroid_2Fos_2FParcel_3BLandroid_2Fos_2FParcel_3BI_29Z"), + std::string("Landroid_2Fcontent_2Fpm_2FIPackageManager_24Stub_3B_7ConTransact_7C_28ILandroid_2Fos_2FParcel_3BLandroid_2Fos_2FParcel_3BI_29Z"), + std::string("Landroid_2Fcontent_2FIContentService_24Stub_3B_7ConTransact_7C_28ILandroid_2Fos_2FParcel_3BLandroid_2Fos_2FParcel_3BI_29Z"), + std::string("Lcom_2Fandroid_2Fserver_2Fam_2FHwActivityManagerService_3B_7ConTransact_7C_28ILandroid_2Fos_2FParcel_3BLandroid_2Fos_2FParcel_3BI_29Z"), + std::string("Lcom_2Fandroid_2Fserver_2Fam_2FActivityManagerService_3B_7ConTransact_7C_28ILandroid_2Fos_2FParcel_3BLandroid_2Fos_2FParcel_3BI_29Z"), + std::string("Ljava_2Flang_2Freflect_2FMethod_3B_7Cinvoke_7C_28Ljava_2Flang_2FObject_3BALjava_2Flang_2FObject_3B_29Ljava_2Flang_2FObject_3B"), + std::string("Lcom_2Fandroid_2Fserver_2FSystemServer_3B_7Crun_7C_28_29V"), + std::string("Lcom_2Fandroid_2Finternal_2Ftelephony_2FIPhoneStateListener_24Stub_24Proxy_3B_7ConMessageWaitingIndicatorChanged_7C_28Z_29V"), + std::string("Landroid_2Fview_2Fanimation_2FTransformation_3B_7C_3Cinit_3E_7C_28_29V"), + std::string("Lcom_2Fandroid_2Fserver_2FSystemServer_3B_7CstartOtherServices_7C_28_29V"), + std::string("Lcom_2Fandroid_2Fserver_2Fpm_2FSettings_3B_7CreadLPw_7C_28Ljava_2Futil_2FList_3B_29Z"), + std::string("Lcom_2Fandroid_2Fserver_2Fam_2FActivityManagerService_3B_7CupdateOomAdjLocked_7C_28_29V"), + std::string("Lcom_2Fandroid_2Fserver_2Fpm_2FHwPackageManagerService_3B_7ConTransact_7C_28ILandroid_2Fos_2FParcel_3BLandroid_2Fos_2FParcel_3BI_29Z"), + std::string("Lcom_2Fandroid_2Fserver_2Fpm_2FPackageManagerService_3B_7CgeneratePackageInfo_7C_28Lcom_2Fandroid_2Fserver_2Fpm_2FPackageSetting_3BII_29Landroid_2Fcontent_2Fpm_2FPackageInfo_3B"), + std::string("Ljava_2Flang_2FThrowable_3B_7CprintStackTrace_7C_28Ljava_2Flang_2FThrowable_24PrintStreamOrWriter_3B_29V"), + std::string("Lcom_2Fandroid_2Fserver_2FSystemServer_3B_7CstartBootstrapServices_7C_28_29V"), + std::string("Ljava_2Flang_2FThrowable_3B_7CgetOurStackTrace_7C_28_29ALjava_2Flang_2FStackTraceElement_3B"), + std::string("Ldalvik_2Fsystem_2FVMStack_3B_7CgetStackClass2_7C_28_29Ljava_2Flang_2FClass_3B"), + std::string("Lcom_2Fandroid_2Fserver_2Fam_2FActivityManagerService_3B_7CattachApplicationLocked_7C_28Landroid_2Fapp_2FIApplicationThread_3BI_29Z"), + std::string("Lcom_2Fandroid_2Fserver_2FInputMethodManagerService_3B_7ChideCurrentInputLocked_7C_28ILandroid_2Fos_2FResultReceiver_3B_29Z"), + }; + for (auto it = setArrayHotFunc.begin(); it != setArrayHotFunc.end(); ++it) { + GStrIdx strIdx = GlobalTables::GetStrTable().GetStrIdxFromName(*it); + (void)excludedCallee.insert(strIdx); + } +} + +// trim both leading and trailing space and tab +static void TrimString(std::string &str) { + size_t pos = str.find_first_not_of(kSpaceTabStr); + if (pos != std::string::npos) { + str = str.substr(pos); + } else { + str.clear(); + } + pos = str.find_last_not_of(kSpaceTabStr); + if (pos != std::string::npos) { + str = str.substr(0, pos + 1); + } +} + +void MInline::ApplyInlineListInfo(const std::string &list, MapleMap*> &listCallee) { + if (list.empty()) { + return; + } + std::ifstream infile(list); + if (!infile.is_open()) { + LogInfo::MapleLogger(kLlErr) << "Cannot open function list file " << list << '\n'; + return; + } + LogInfo::MapleLogger() << "[INLINE] read function from list: " << list << '\n'; + std::string str; + GStrIdx calleeStrIdx; + while (getline(infile, str)) { + TrimString(str); + if (str.empty() || str[0] == kCommentsignStr[0]) { + continue; + } + if (str[0] != kHyphenStr[0]) { + calleeStrIdx = GlobalTables::GetStrTable().GetStrIdxFromName(str); + auto it = listCallee.find(calleeStrIdx); + if (it == listCallee.end()) { + auto callerList = alloc.GetMemPool()->New>(alloc.Adapter()); + (void)listCallee.insert(std::pair*>(calleeStrIdx, callerList)); + } + } else { + size_t pos = str.find_first_not_of(kAppointStr); + CHECK_FATAL(pos != std::string::npos, "cannot find '->' "); + str = str.substr(pos); + GStrIdx callerStrIdx = GlobalTables::GetStrTable().GetStrIdxFromName(str); + auto it = listCallee.find(calleeStrIdx); + CHECK_FATAL(it != listCallee.end(), "illegal configuration for inlineList"); + it->second->insert(callerStrIdx); + } + } + infile.close(); +} + +// Common rename function +uint32 MInline::RenameSymbols(MIRFunction &caller, const MIRFunction &callee, uint32 inlinedTimes) const { + size_t symTabSize = callee.GetSymbolTabSize(); + size_t stIdxOff = caller.GetSymTab()->GetSymbolTableSize() - 1; + for (size_t i = 0; i < symTabSize; ++i) { + const MIRSymbol *sym = callee.GetSymbolTabItem(i); + if (sym == nullptr) { + continue; + } + std::string syName(kUnderlineStr); + // Use puIdx here instead of func name because our mangled func name can be + // really long. + syName.append(std::to_string(callee.GetPuidx())); + syName.append(kVerticalLineStr); + syName.append((sym->GetName() == "") ? std::to_string(i) : sym->GetName()); + syName.append(kUnderlineStr); + if (!module.firstInline) { + syName.append("SECOND_"); + } + GStrIdx strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(syName + std::to_string(inlinedTimes)); + if (sym->GetScopeIdx() == 0) { + CHECK_FATAL(false, "sym->GetScopeIdx() should be != 0"); + } + MIRSymbol *newSym = nullptr; + newSym = caller.GetSymTab()->CloneLocalSymbol(*sym); + newSym->SetNameStrIdx(strIdx); + if (newSym->GetStorageClass() == kScFormal) { + newSym->SetStorageClass(kScAuto); + } + newSym->SetIsTmp(true); + newSym->ResetIsDeleted(); + if (!caller.GetSymTab()->AddStOutside(newSym)) { + CHECK_FATAL(false, "Reduplicate names."); + } + if (newSym->GetStIndex() != (i + stIdxOff)) { + CHECK_FATAL(false, "wrong symbol table index"); + } + CHECK_FATAL(caller.GetSymTab()->IsValidIdx(newSym->GetStIndex()), "symbol table index out of range"); + } + return stIdxOff; +} + +static StIdx UpdateIdx(const StIdx &stIdx, uint32 stIdxOff, const std::unordered_map &staticOld2New) { + StIdx newStIdx = stIdx; + auto it = staticOld2New.find(newStIdx.FullIdx()); + if (it != staticOld2New.end()) { + newStIdx.SetFullIdx(it->second); + } else { + newStIdx.SetIdx(newStIdx.Idx() + stIdxOff); + } + return newStIdx; +} + +void MInline::ReplaceSymbols(BaseNode *baseNode, uint32 stIdxOff, + const std::unordered_map &staticOld2New) const { + if (baseNode == nullptr) { + return; + } + CallReturnVector *returnVector = baseNode->GetCallReturnVector(); + if (baseNode->GetOpCode() == OP_block) { + BlockNode *blockNode = static_cast(baseNode); + for (auto &stmt : blockNode->GetStmtNodes()) { + ReplaceSymbols(&stmt, stIdxOff, staticOld2New); + } + } else if (baseNode->GetOpCode() == OP_dassign) { + DassignNode *dassNode = static_cast(baseNode); + // Skip globals. + if (dassNode->GetStIdx().Islocal()) { + dassNode->SetStIdx(UpdateIdx(dassNode->GetStIdx(), stIdxOff, staticOld2New)); + } + } else if ((baseNode->GetOpCode() == OP_addrof || baseNode->GetOpCode() == OP_dread)) { + AddrofNode *addrNode = static_cast(baseNode); + // Skip globals. + if (addrNode->GetStIdx().Islocal()) { + addrNode->SetStIdx(UpdateIdx(addrNode->GetStIdx(), stIdxOff, staticOld2New)); + } + } else if (returnVector != nullptr) { + if (returnVector->size() > 1) { + CHECK_FATAL(false, "multiple return values are not supported"); + } + // Skip globals. + if (returnVector->size() == 1 && !(*returnVector).at(0).second.IsReg() && (*returnVector).at(0).first.Islocal()) { + (*returnVector)[0].first = UpdateIdx((*returnVector).at(0).first, stIdxOff, staticOld2New); + } + } else if (baseNode->GetOpCode() == OP_foreachelem) { + ForeachelemNode *forEachNode = static_cast(baseNode); + // Skip globals. + if (forEachNode->GetElemStIdx().Idx() != 0) { + forEachNode->SetElemStIdx(UpdateIdx(forEachNode->GetElemStIdx(), stIdxOff, staticOld2New)); + } + if (forEachNode->GetArrayStIdx().Idx() != 0) { + forEachNode->SetArrayStIdx(UpdateIdx(forEachNode->GetArrayStIdx(), stIdxOff, staticOld2New)); + } + } else if (baseNode->GetOpCode() == OP_doloop) { + DoloopNode *doLoopNode = static_cast(baseNode); + // Skip globals. + if (!doLoopNode->IsPreg() && doLoopNode->GetDoVarStIdx().Idx()) { + doLoopNode->SetDoVarStIdx(UpdateIdx(doLoopNode->GetDoVarStIdx(), stIdxOff, staticOld2New)); + } + } + // Search for nested dassign/dread/addrof node that may include a symbol index. + for (size_t i = 0; i < baseNode->NumOpnds(); ++i) { + ReplaceSymbols(baseNode->Opnd(i), stIdxOff, staticOld2New); + } +} + +uint32 MInline::RenameLabels(MIRFunction &caller, const MIRFunction &callee, uint32 inlinedTimes) const { + size_t labelTabSize = callee.GetLabelTab()->GetLabelTableSize(); + size_t labIdxOff = caller.GetLabelTab()->GetLabelTableSize() - 1; + // label table start at 1. + for (size_t i = 1; i < labelTabSize; ++i) { + std::string labelName = callee.GetLabelTabItem(static_cast(i)); + std::string newLableName(kUnderlineStr); + newLableName.append(std::to_string(callee.GetPuidx())); + newLableName.append(kVerticalLineStr); + newLableName.append(labelName); + newLableName.append(kUnderlineStr); + newLableName.append(std::to_string(inlinedTimes)); + GStrIdx strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(newLableName); + LabelIdx labIdx = caller.GetLabelTab()->AddLabel(strIdx); + CHECK_FATAL(labIdx == (i + labIdxOff), "wrong label index"); + } + return labIdxOff; +} + +#define MPLTOOL +void MInline::ReplaceLabels(BaseNode &baseNode, uint32 labIdxOff) const { + // Now only mpltool would allow try in the callee. +#ifdef MPLTOOL + if (baseNode.GetOpCode() == OP_try) { + TryNode *tryNode = static_cast(&baseNode); + for (size_t i = 0; i < tryNode->GetOffsetsCount(); ++i) { + tryNode->SetOffset(tryNode->GetOffset(i) + labIdxOff, i); + } + } +#else + CHECK_FATAL(baseNode->op != OP_try, "Java `try` not allowed"); +#endif + if (baseNode.GetOpCode() == OP_block) { + BlockNode *blockNode = static_cast(&baseNode); + for (auto &stmt : blockNode->GetStmtNodes()) { + ReplaceLabels(stmt, labIdxOff); + } + } else if (baseNode.IsCondBr()) { + CondGotoNode *temp = static_cast(&baseNode); + temp->SetOffset(temp->GetOffset() + labIdxOff); + } else if (baseNode.GetOpCode() == OP_label) { + static_cast(&baseNode)->SetLabelIdx(static_cast(&baseNode)->GetLabelIdx() + labIdxOff); + } else if (baseNode.GetOpCode() == OP_addroflabel) { + uint32 offset = static_cast(&baseNode)->GetOffset(); + static_cast(&baseNode)->SetOffset(offset + labIdxOff); + } else if (baseNode.GetOpCode() == OP_goto) { + static_cast(&baseNode)->SetOffset(static_cast(&baseNode)->GetOffset() + labIdxOff); + } else if (baseNode.GetOpCode() == OP_multiway || baseNode.GetOpCode() == OP_rangegoto) { + ASSERT(false, "MInline::ReplaceLabels: OP_multiway and OP_rangegoto are not supported"); + } else if (baseNode.GetOpCode() == OP_switch) { + SwitchNode *switchNode = static_cast(&baseNode); + switchNode->SetDefaultLabel(switchNode->GetDefaultLabel() + labIdxOff); + for (size_t i = 0; i < switchNode->GetSwitchTable().size(); ++i) { + LabelIdx idx = switchNode->GetSwitchTable()[i].second + labIdxOff; + switchNode->UpdateCaseLabelAt(i, idx); + } + } else if (baseNode.GetOpCode() == OP_doloop) { + ReplaceLabels(*static_cast(baseNode).GetDoBody(), labIdxOff); + } else if (baseNode.GetOpCode() == OP_foreachelem) { + ReplaceLabels(*static_cast(baseNode).GetLoopBody(), labIdxOff); + } else if (baseNode.GetOpCode() == OP_dowhile || baseNode.GetOpCode() == OP_while) { + ReplaceLabels(*static_cast(baseNode).GetBody(), labIdxOff); + } else if (baseNode.GetOpCode() == OP_if) { + ReplaceLabels(*static_cast(baseNode).GetThenPart(), labIdxOff); + if (static_cast(&baseNode)->GetElsePart()) { + ReplaceLabels(*static_cast(baseNode).GetElsePart(), labIdxOff); + } + } +} + +uint32 MInline::RenamePregs(const MIRFunction &caller, const MIRFunction &callee, + std::unordered_map &pregOld2new) const { + const MapleVector &tab = callee.GetPregTab()->GetPregTable(); + size_t tableSize = tab.size(); + size_t regIdxOff = caller.GetPregTab()->Size() - 1; + for (size_t i = 1; i < tableSize; ++i) { + MIRPreg *mirPreg = tab[i]; + PregIdx idx = 0; + if (mirPreg->GetPrimType() == PTY_ptr || mirPreg->GetPrimType() == PTY_ref) { + idx = caller.GetPregTab()->ClonePreg(*mirPreg); + } else { + idx = caller.GetPregTab()->CreatePreg(mirPreg->GetPrimType()); + } + (void)pregOld2new.insert(std::pair(i, idx)); + } + return regIdxOff; +} + +static PregIdx GetNewPregIdx(PregIdx regIdx, std::unordered_map &pregOld2New) { + if (regIdx < 0) { + return regIdx; + } + auto it = pregOld2New.find(regIdx); + if (it == pregOld2New.end()) { + CHECK_FATAL(false, "Unable to find the regIdx to replace"); + } + return it->second; +} + +void MInline::ReplacePregs(BaseNode *baseNode, std::unordered_map &pregOld2New) const { + if (baseNode == nullptr) { + return; + } + switch (baseNode->GetOpCode()) { + case OP_block: { + BlockNode *blockNode = static_cast(baseNode); + for (auto &stmt : blockNode->GetStmtNodes()) { + ReplacePregs(&stmt, pregOld2New); + } + break; + } + case OP_regassign: { + RegassignNode *regassign = static_cast(baseNode); + regassign->SetRegIdx(GetNewPregIdx(regassign->GetRegIdx(), pregOld2New)); + break; + } + case OP_regread: { + RegreadNode *regread = static_cast(baseNode); + regread->SetRegIdx(GetNewPregIdx(regread->GetRegIdx(), pregOld2New)); + break; + } + case OP_doloop: { + DoloopNode *doloop = static_cast(baseNode); + if (doloop->IsPreg()) { + PregIdx oldIdx = static_cast(doloop->GetDoVarStIdx().FullIdx()); + doloop->SetDoVarStFullIdx(static_cast(GetNewPregIdx(oldIdx, pregOld2New))); + } + break; + } + case OP_callassigned: + case OP_virtualcallassigned: + case OP_superclasscallassigned: + case OP_interfacecallassigned: + case OP_customcallassigned: + case OP_polymorphiccallassigned: + case OP_icallassigned: + case OP_intrinsiccallassigned: + case OP_xintrinsiccallassigned: + case OP_intrinsiccallwithtypeassigned: { + CallReturnVector *retVec = baseNode->GetCallReturnVector(); + CHECK_FATAL(retVec != nullptr, "retVec is nullptr in MInline::ReplacePregs"); + for (size_t i = 0; i < retVec->size(); ++i) { + CallReturnPair &callPair = (*retVec).at(i); + if (callPair.second.IsReg()) { + PregIdx oldIdx = callPair.second.GetPregIdx(); + callPair.second.SetPregIdx(static_cast(GetNewPregIdx(oldIdx, pregOld2New))); + } + } + break; + } + default: + break; + } + for (size_t i = 0; i < baseNode->NumOpnds(); ++i) { + ReplacePregs(baseNode->Opnd(i), pregOld2New); + } +} + +LabelIdx MInline::CreateReturnLabel(MIRFunction &caller, const MIRFunction &callee, uint32 inlinedTimes) const { + std::string labelName(kUnderlineStr); + labelName.append(std::to_string(callee.GetPuidx())); + labelName.append(kVerticalLineStr); + labelName.append(kReturnlocStr); + labelName.append(std::to_string(inlinedTimes)); + GStrIdx strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(labelName); + LabelIdx labIdx = caller.GetLabelTab()->AddLabel(strIdx); + return labIdx; +} + +GotoNode *MInline::UpdateReturnStmts(const MIRFunction &caller, BlockNode &newBody, LabelIdx retLabIdx, + const CallReturnVector &callReturnVector, int &retCount) const { + // For callee: return f ==> + // rval = f; goto label x; + GotoNode *lastGoto = nullptr; + for (auto &stmt : newBody.GetStmtNodes()) { + switch (stmt.GetOpCode()) { + case OP_foreachelem: + lastGoto = UpdateReturnStmts(caller, *static_cast(stmt).GetLoopBody(), retLabIdx, + callReturnVector, retCount); + break; + case OP_doloop: + lastGoto = UpdateReturnStmts(caller, *static_cast(stmt).GetDoBody(), + retLabIdx, callReturnVector, retCount); + break; + case OP_dowhile: + case OP_while: + lastGoto = UpdateReturnStmts(caller, *static_cast(stmt).GetBody(), + retLabIdx, callReturnVector, retCount); + break; + case OP_if: { + IfStmtNode &ifStmt = static_cast(stmt); + lastGoto = UpdateReturnStmts(caller, *ifStmt.GetThenPart(), retLabIdx, callReturnVector, retCount); + if (ifStmt.GetElsePart() != nullptr) { + lastGoto = UpdateReturnStmts(caller, *ifStmt.GetElsePart(), retLabIdx, callReturnVector, retCount); + } + break; + } + case OP_return: { + if (callReturnVector.size() > 1) { + CHECK_FATAL(false, "multiple return values are not supported"); + } + ++retCount; + GotoNode *gotoNode = builder.CreateStmtGoto(OP_goto, retLabIdx); + lastGoto = gotoNode; + if (callReturnVector.size() == 1) { + BaseNode *currBaseNode = static_cast(stmt).Opnd(0); + StmtNode *dStmt = nullptr; + if (!callReturnVector.at(0).second.IsReg()) { + dStmt = builder.CreateStmtDassign( + callReturnVector.at(0).first, callReturnVector.at(0).second.GetFieldID(), currBaseNode); + } else { + PregIdx pregIdx = callReturnVector.at(0).second.GetPregIdx(); + const MIRPreg *mirPreg = caller.GetPregTab()->PregFromPregIdx(pregIdx); + dStmt = builder.CreateStmtRegassign(mirPreg->GetPrimType(), pregIdx, currBaseNode); + } + newBody.ReplaceStmt1WithStmt2(&stmt, dStmt); + newBody.InsertAfter(dStmt, gotoNode); + } else { + newBody.ReplaceStmt1WithStmt2(&stmt, gotoNode); + } + break; + } + default: + break; + } + } + return lastGoto; +} + +void MInline::SearchCallee(const MIRFunction &func, const BaseNode &baseNode, std::set &ret) const { + Opcode op = baseNode.GetOpCode(); + switch (op) { + case OP_block: { + const BlockNode &blk = static_cast(baseNode); + for (auto &stmt : blk.GetStmtNodes()) { + SearchCallee(func, stmt, ret); + } + break; + } + case OP_call: + case OP_callassigned: { + const CallNode &call = static_cast(baseNode); + MIRFunction *callee = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(call.GetPUIdx()); + (void)ret.insert(callee->GetNameStrIdx()); + break; + } + case OP_dread: { + const DreadNode &dread = static_cast(baseNode); + const MIRSymbol *mirSymbol = func.GetLocalOrGlobalSymbol(dread.GetStIdx()); + if (mirSymbol->IsStatic()) { + (void)ret.insert(mirSymbol->GetNameStrIdx()); + } + break; + } + case OP_dassign: { + const DassignNode &dassign = static_cast(baseNode); + const MIRSymbol *mirSymbol = func.GetLocalOrGlobalSymbol(dassign.GetStIdx()); + if (mirSymbol->IsStatic()) { + (void)ret.insert(mirSymbol->GetNameStrIdx()); + } + break; + } + default: + break; + } + for (size_t i = 0; i < baseNode.NumOpnds(); ++i) { + CHECK_FATAL(baseNode.Opnd(i) != nullptr, "funcName: %s", func.GetName().c_str()); + SearchCallee(func, *(baseNode.Opnd(i)), ret); + } +} + +void MInline::RecordRealCaller(MIRFunction &caller, const MIRFunction &callee) { + auto it = funcToCostMap.find(&caller); + if (it != funcToCostMap.end()) { + (void)funcToCostMap.erase(it); + } + auto &realCaller = module.GetRealCaller(); + std::set names; + CHECK_FATAL(callee.GetBody() != nullptr, "funcName: %s", callee.GetName().c_str()); + SearchCallee(callee, *(callee.GetBody()), names); + for (auto name : names) { + auto pairOld = std::pair(callee.GetNameStrIdx(), name); + auto pairNew = std::pair(caller.GetNameStrIdx(), name); + if (realCaller.find(pairOld) != realCaller.end()) { + (void)realCaller.insert(std::pair, GStrIdx>(pairNew, realCaller[pairOld])); + } else { + (void)realCaller.insert(std::pair, + GStrIdx>(pairNew, callee.GetBaseClassNameStrIdx())); + } + } +} + +// Inline CALLEE into CALLER. +bool MInline::PerformInline(MIRFunction &caller, BlockNode &enclosingBlk, CallNode &callStmt, MIRFunction &callee) { + if (callee.IsEmpty()) { + enclosingBlk.RemoveStmt(&callStmt); + return false; + } + // Record stmt right before and after the callStmt. + StmtNode *stmtBeforeCall = callStmt.GetPrev(); + StmtNode *stmtAfterCall = callStmt.GetNext(); + // Step 0: See if CALLEE have been inlined to CALLER once. + uint32 inlinedTimes = 0; + if (inlineTimesMap.find(&callee) != inlineTimesMap.end()) { + inlinedTimes = inlineTimesMap[&callee]; + } else { + inlinedTimes = 0; + } + // Step 1: Clone CALLEE's body. + auto getBody = [callee, this] (BlockNode* funcBody) { + if (callee.IsFromMpltInline()) { + return funcBody->CloneTree(module.GetCurFuncCodeMPAllocator()); + } + return funcBody->CloneTreeWithSrcPosition(module); + }; + + BlockNode *newBody = nullptr; + if (recursiveFuncToInlineLevel.find(&callee) != recursiveFuncToInlineLevel.end() && + recursiveFuncToInlineLevel[&callee] >= maxInlineLevel) { + return false; + } + if (&caller == &callee) { + if (dumpDetail) { + LogInfo::MapleLogger() << "[INLINE Recursive]: " << caller.GetName() << '\n'; + constexpr int32 dumpIndent = 4; + callStmt.Dump(dumpIndent); + } + if (currFuncBody == nullptr) { + // For Inline recursive, we save the original function body before first inline. + currFuncBody = getBody(callee.GetBody()); + // update inlining levels + if (recursiveFuncToInlineLevel.find(&callee) != recursiveFuncToInlineLevel.end()) { + recursiveFuncToInlineLevel[&callee]++; + } else { + recursiveFuncToInlineLevel[&callee] = 1; + } + } + newBody = getBody(currFuncBody); + } else { + newBody = getBody(callee.GetBody()); + } + // Step 2: Rename symbols, labels, pregs + std::unordered_map staticOld2New; + uint32 stIdxOff = RenameSymbols(caller, callee, inlinedTimes); + uint32 labIdxOff = RenameLabels(caller, callee, inlinedTimes); + std::unordered_map pregOld2New; + uint32 regIdxOff = RenamePregs(caller, callee, pregOld2New); + // Step 3: Replace symbols, labels, pregs + CHECK_NULL_FATAL(newBody); + ReplaceSymbols(newBody, stIdxOff, staticOld2New); + ReplaceLabels(*newBody, labIdxOff); + ReplacePregs(newBody, pregOld2New); + // Step 4: Null check 'this' and assign actuals to formals. + if (static_cast(callStmt.NumOpnds()) != callee.GetFormalCount()) { + CHECK_FATAL(false, "# formal arguments != # actual arguments"); + } + if (callee.GetFormalCount() > 0 && callee.GetFormal(0)->GetName() == kThisStr) { + UnaryStmtNode *nullCheck = module.CurFuncCodeMemPool()->New(OP_assertnonnull); + nullCheck->SetOpnd(callStmt.Opnd(0), 0); + newBody->InsertBefore(newBody->GetFirst(), nullCheck); + } + for (size_t i = 0; i < callStmt.NumOpnds(); ++i) { + BaseNode *currBaseNode = callStmt.Opnd(i); + MIRSymbol *formal = callee.GetFormal(i); + if (formal->IsPreg()) { + PregIdx idx = callee.GetPregTab()->GetPregIdxFromPregno(formal->GetPreg()->GetPregNo()); + RegassignNode *regAssign = builder.CreateStmtRegassign( + formal->GetPreg()->GetPrimType(), static_cast(idx) + regIdxOff, currBaseNode); + newBody->InsertBefore(newBody->GetFirst(), regAssign); + } else { + MIRSymbol *newFormal = caller.GetSymTab()->GetSymbolFromStIdx(formal->GetStIndex() + stIdxOff); + DassignNode *stmt = builder.CreateStmtDassign(*newFormal, 0, currBaseNode); + newBody->InsertBefore(newBody->GetFirst(), stmt); + } + } + // Step 5: Insert the callee'return jump dest label. + // For caller: a = foo() ==> + // a = foo(), label x. + LabelIdx retLabIdx; + // record the created label + StmtNode *labelStmt = nullptr; + if (callStmt.GetNext() != nullptr && callStmt.GetNext()->GetOpCode() == OP_label) { + // if the next stmt is a label, just reuse it + LabelNode *nextLabel = static_cast(callStmt.GetNext()); + retLabIdx = nextLabel->GetLabelIdx(); + } else { + retLabIdx = CreateReturnLabel(caller, callee, inlinedTimes); + labelStmt = builder.CreateStmtLabel(retLabIdx); + newBody->AddStatement(labelStmt); + } + // Step 6: Handle return values. + // Find the rval of call-stmt + // calcute number of return stmt in CALLEE'body + int retCount = 0; + // record the last return stmt in CALLEE'body + GotoNode *lastGoto = nullptr; + CallReturnVector currReturnVec(alloc.Adapter()); + if (callStmt.GetOpCode() == OP_callassigned || callStmt.GetOpCode() == OP_virtualcallassigned || + callStmt.GetOpCode() == OP_superclasscallassigned || callStmt.GetOpCode() == OP_interfacecallassigned) { + currReturnVec = callStmt.GetReturnVec(); + if (currReturnVec.size() > 1) { + CHECK_FATAL(false, "multiple return values are not supported"); + } + } + lastGoto = UpdateReturnStmts(caller, *newBody, retLabIdx, currReturnVec, retCount); + // Step 6.5: remove the successive goto statement and label statement in some circumstances. + // There is no return stmt in CALLEE'body, if we have create a new label in Step5, remove it. + if (retCount == 0) { + if (labelStmt != nullptr) { + newBody->RemoveStmt(labelStmt); + } + } else { + // There are one or more goto stmt, remove the successive goto stmt and label stmt, + // if there is only one return stmt, we can remove the label created in Step5, too. + CHECK_FATAL(lastGoto != nullptr, "there should be at least one goto statement"); + if (labelStmt != nullptr) { + // if we have created a new label in Step5, then last_goto->next == label_stmt means they are successive. + if (lastGoto->GetNext() == labelStmt) { + newBody->RemoveStmt(lastGoto); + if (retCount == 1) { + newBody->RemoveStmt(labelStmt); + } + } + } else { + // if we haven't created a new label in Step5, then new_body->last == last_goto means they are successive. + if (newBody->GetLast() == lastGoto) { + newBody->RemoveStmt(lastGoto); + } + } + } + // Step 7: Replace the call-stmt with new CALLEE'body. + // begin inlining function + if (!Options::noComment) { + MapleString beginCmt(module.CurFuncCodeMemPool()); + if (module.firstInline) { + (void)beginCmt.append(kInlineBeginComment); + } else { + (void)beginCmt.append(kSecondInlineBeginComment); + } + beginCmt.append(callee.GetName()); + enclosingBlk.InsertBefore(&callStmt, builder.CreateStmtComment(beginCmt.c_str())); + // end inlining function + MapleString endCmt(module.CurFuncCodeMemPool()); + if (module.firstInline) { + (void)endCmt.append(kInlineEndComment); + } else { + (void)endCmt.append(kSecondInlineEndComment); + } + endCmt.append(callee.GetName()); + if (enclosingBlk.GetLast() != nullptr && &callStmt != enclosingBlk.GetLast()) { + CHECK_FATAL(callStmt.GetNext() != nullptr, "null ptr check"); + } + enclosingBlk.InsertAfter(&callStmt, builder.CreateStmtComment(endCmt.c_str())); + CHECK_FATAL(callStmt.GetNext() != nullptr, "null ptr check"); + } + if (newBody->IsEmpty()) { + enclosingBlk.RemoveStmt(&callStmt); + } else { + enclosingBlk.ReplaceStmtWithBlock(callStmt, *newBody); + } + RecordRealCaller(caller, callee); + + // Step 8: Update inlined_times. + inlineTimesMap[&callee] = inlinedTimes + 1; + // Step 9: After inlining, if there exists nested try-catch block, flatten them all. + // Step 9.1 Find whether there is a javatry before callStmt. + bool hasOuterTry = false; + TryNode *outerTry = nullptr; + StmtNode *outerEndTry = nullptr; + for (StmtNode *stmt = stmtBeforeCall; stmt != nullptr; stmt = stmt->GetPrev()) { + if (stmt->op == OP_endtry) { + break; + } + if (stmt->op == OP_try) { + hasOuterTry = true; + outerTry = static_cast(stmt); + break; + } + } + if (!hasOuterTry) { + return true; + } + for (StmtNode *stmt = stmtAfterCall; stmt != nullptr; stmt = stmt->GetNext()) { + if (stmt->op == OP_endtry) { + outerEndTry = stmt; + break; + } + if (stmt->op == OP_try) { + ASSERT(false, "Impossible, caller: [%s] callee: [%s]", + caller.GetName().c_str(), callee.GetName().c_str()); + break; + } + } + ASSERT(outerTry != nullptr, "Impossible, caller: [%s] callee: [%s]", + caller.GetName().c_str(), callee.GetName().c_str()); + ASSERT(outerEndTry != nullptr, "Impossible, caller: [%s] callee: [%s]", + caller.GetName().c_str(), callee.GetName().c_str()); + + // Step 9.2 We have found outerTry and outerEndTry node, resolve the nested try-catch blocks between them. + bool hasInnerTry = ResolveNestedTryBlock(*caller.GetBody(), *outerTry, outerEndTry); + if (hasOuterTry && hasInnerTry) { + if (dumpDetail) { + LogInfo::MapleLogger() << "[NESTED_TRY_CATCH]" << callee.GetName() << " to " << caller.GetName() << '\n'; + } + } + return true; +} + +bool MInline::ResolveNestedTryBlock(BlockNode &body, TryNode &outerTryNode, const StmtNode *outerEndTryNode) const { + StmtNode *stmt = outerTryNode.GetNext(); + StmtNode *next = nullptr; + bool changed = false; + while (stmt != outerEndTryNode) { + next = stmt->GetNext(); + switch (stmt->op) { + case OP_try: { + // Find previous meaningful stmt. + StmtNode *last = stmt->GetPrev(); + while (last->op == OP_comment || last->op == OP_label) { + last = last->GetPrev(); + } + ASSERT(last->op != OP_endtry, "Impossible"); + ASSERT(last->op != OP_try, "Impossible"); + StmtNode *newEnd = module.CurFuncCodeMemPool()->New(OP_endtry); + body.InsertAfter(last, newEnd); + TryNode *tryNode = static_cast(stmt); + tryNode->OffsetsInsert(tryNode->GetOffsetsEnd(), outerTryNode.GetOffsetsBegin(), outerTryNode.GetOffsetsEnd()); + changed = true; + break; + } + case OP_endtry: { + // Find next meaningful stmt. + StmtNode *first = stmt->GetNext(); + while (first->op == OP_comment || first->op == OP_label) { + first = first->GetNext(); + } + ASSERT(first != outerEndTryNode, "Impossible"); + next = first->GetNext(); + if (first->op == OP_try) { + // In this case, there are no meaningful statements between last endtry and the next try, + // we just solve the trynode and move the cursor to the statement right after the trynode. + TryNode *tryNode = static_cast(first); + tryNode->OffsetsInsert( + tryNode->GetOffsetsEnd(), outerTryNode.GetOffsetsBegin(), outerTryNode.GetOffsetsEnd()); + changed = true; + break; + } else { + TryNode *node = outerTryNode.CloneTree(module.GetCurFuncCodeMPAllocator()); + CHECK_FATAL(node != nullptr, "Impossible"); + body.InsertBefore(first, node); + changed = true; + break; + } + } + default: { + break; + } + } + stmt = next; + } + return changed; +} + +// Here, one insn's cost is 2. +FuncCostResultType MInline::GetFuncCost(const MIRFunction &func, const BaseNode &baseNode, uint32 &cost, + uint32 threshold) const { + if (cost > threshold) { + return kFuncBodyTooBig; + } + Opcode op = baseNode.GetOpCode(); + switch (op) { + case OP_block: { + const BlockNode &blk = static_cast(baseNode); + for (auto &stmt : blk.GetStmtNodes()) { + FuncCostResultType funcCostResultType = GetFuncCost(func, stmt, cost, threshold); + if (funcCostResultType != kSmallFuncBody) { + return funcCostResultType; + } + } + break; + } + case OP_switch: { + const SwitchNode &switchNode = static_cast(baseNode); + cost += static_cast(switchNode.GetSwitchTable().size() + 1); + break; + } + case OP_customcallassigned: + case OP_polymorphiccallassigned: + case OP_customcall: + case OP_polymorphiccall: + case OP_intrinsiccall: + case OP_intrinsiccallwithtype: + case OP_xintrinsiccall: + case OP_intrinsiccallassigned: + case OP_intrinsiccallwithtypeassigned: + case OP_xintrinsiccallassigned: + case OP_virtualcall: + case OP_superclasscall: + case OP_interfacecall: + case OP_virtualcallassigned: + case OP_superclasscallassigned: + case OP_interfacecallassigned: + case OP_call: + case OP_callassigned: + case OP_throw: { + cost += kPentupleInsn; + break; + } + case OP_intrinsicop: + case OP_intrinsicopwithtype: { + const IntrinsicopNode &node = static_cast(baseNode); + MIRIntrinsicID id = node.GetIntrinsic(); + if (id == INTRN_JAVA_CONST_CLASS || id == INTRN_JAVA_ARRAY_LENGTH) { + cost += kOneInsn; + } else if (id == INTRN_JAVA_MERGE) { + cost += kHalfInsn; + } else if (id == INTRN_JAVA_INSTANCE_OF) { + cost += kPentupleInsn; + } else if (id == INTRN_MPL_READ_OVTABLE_ENTRY) { + cost += kDoubleInsn; + } else { + CHECK_FATAL(false, "[IMPOSSIBLE] %s", func.GetName().c_str()); + cost += kQuadrupleInsn; + } + break; + } + case OP_jstry: + case OP_try: + case OP_jscatch: + case OP_catch: + case OP_finally: + case OP_cleanuptry: + case OP_endtry: + case OP_syncenter: + case OP_syncexit: { + return kNotAllowedNode; + } + case OP_membaracquire: + case OP_membarrelease: + case OP_membarstoreload: + case OP_membarstorestore: { + cost += kOneInsn; + break; + } + case OP_comment: + case OP_return: + case OP_label: + break; + case OP_dread: { + const DreadNode &dread = static_cast(baseNode); + bool isLocal = dread.GetStIdx().Islocal(); + if (!isLocal) { + cost += kDoubleInsn; + } + break; + } + case OP_dassign: { + const DassignNode &dassign = static_cast(baseNode); + bool isLocal = dassign.GetStIdx().Islocal(); + if (!isLocal) { + cost += kDoubleInsn; + } + break; + } + case OP_cvt: { + cost += kHalfInsn; + break; + } + default: { + cost += kOneInsn; + break; + } + } + for (size_t i = 0; i < baseNode.NumOpnds(); ++i) { + FuncCostResultType funcCostResultType = GetFuncCost(func, *(baseNode.Opnd(i)), cost, threshold); + if (funcCostResultType != kSmallFuncBody) { + return funcCostResultType; + } + } + return kSmallFuncBody; +} + +static void MarkParent(const CGNode &node) { + for (auto it = node.CallerBegin(); it != node.CallerEnd(); ++it) { + CGNode *parent = *it; + parent->SetMustNotBeInlined(); + } +} + +bool MInline::IsHotCallSite(const MIRFunction &caller, const MIRFunction &callee, const CallNode &callStmt) const { + if (dumpDetail) { + LogInfo::MapleLogger() << "[CHECK_HOT] " << callee.GetName() << " to " << caller.GetName() << + " op " << callStmt.GetOpCode() << '\n'; + } + return module.GetProfile().CheckFuncHot(caller.GetName()); +} + +bool MInline::FuncInlinable(const MIRFunction &func) const { + std::string name = func.GetName(); + if (StringUtils::StartsWith(name, kReflectionClassStr) || + StringUtils::StartsWith(name, kJavaLangClassesStr) || + StringUtils::StartsWith(name, kJavaLangReferenceStr)) { + return false; + } + if (func.GetAttr(FUNCATTR_abstract) || func.GetAttr(FUNCATTR_const) || func.GetAttr(FUNCATTR_declared_synchronized) || + func.GetAttr(FUNCATTR_synchronized) || func.GetAttr(FUNCATTR_weak) || + ((func.GetAttr(FUNCATTR_critical_native) || func.GetAttr(FUNCATTR_fast_native) || + func.GetAttr(FUNCATTR_native)) && + (func.GetBody() == nullptr || func.GetBody()->GetFirst() == nullptr))) { + return false; + } + const BlockNode *body = func.GetBody(); + for (auto &stmt : body->GetStmtNodes()) { + if (stmt.GetOpCode() == OP_iassign) { + const IassignNode &assign = static_cast(stmt); + MIRPtrType *ptrType = static_cast(GlobalTables::GetTypeTable().GetTypeFromTyIdx(assign.GetTyIdx())); + TyIdxFieldAttrPair fieldPair = ptrType->GetPointedTyIdxFldAttrPairWithFieldID(assign.GetFieldID()); + if (fieldPair.second.GetAttr(FLDATTR_final)) { + return false; + } + if (assign.Opnd(1)->GetPrimType() == PTY_ref) { + return false; + } + } + } + return true; +} + +bool MInline::IsSafeToInline(const MIRFunction *callee, const CallNode &callStmt) const { + Opcode op = callStmt.GetOpCode(); + if (op == OP_callassigned || op == OP_call) { + return true; + } + if (IsFinalMethod(callee)) { + return true; + } + return false; +} + +void MInline::InlineCalls(const CGNode &node) { + MIRFunction *func = node.GetMIRFunction(); + if (func == nullptr || func->GetBody() == nullptr || func->IsFromMpltInline()) { + return; + } + bool changed = false; + do { + changed = false; + currFuncBody = nullptr; + InlineCallsBlock(*func, *(func->GetBody()), *(func->GetBody()), changed); + } while (changed); +} + +void MInline::InlineCallsBlock(MIRFunction &func, BlockNode &enclosingBlk, BaseNode &baseNode, bool &changed) { + if (baseNode.GetOpCode() == OP_block) { + BlockNode &blk = static_cast(baseNode); + for (auto &stmt : blk.GetStmtNodes()) { + InlineCallsBlock(func, blk, stmt, changed); + } + } else if (baseNode.GetOpCode() == OP_callassigned || baseNode.GetOpCode() == OP_call || + baseNode.GetOpCode() == OP_virtualcallassigned || baseNode.GetOpCode() == OP_superclasscallassigned || + baseNode.GetOpCode() == OP_interfacecallassigned) { + InlineCallsBlockInternal(func, enclosingBlk, baseNode, changed); + } else if (baseNode.GetOpCode() == OP_doloop) { + BlockNode *blk = static_cast(baseNode).GetDoBody(); + InlineCallsBlock(func, enclosingBlk, *blk, changed); + } else if (baseNode.GetOpCode() == OP_foreachelem) { + BlockNode *blk = static_cast(baseNode).GetLoopBody(); + InlineCallsBlock(func, enclosingBlk, *blk, changed); + } else if (baseNode.GetOpCode() == OP_dowhile || baseNode.GetOpCode() == OP_while) { + BlockNode *blk = static_cast(baseNode).GetBody(); + InlineCallsBlock(func, enclosingBlk, *blk, changed); + } else if (baseNode.GetOpCode() == OP_if) { + BlockNode *blk = static_cast(baseNode).GetThenPart(); + InlineCallsBlock(func, enclosingBlk, *blk, changed); + blk = static_cast(baseNode).GetElsePart(); + if (blk != nullptr) { + InlineCallsBlock(func, enclosingBlk, *blk, changed); + } + } +} + +InlineResult MInline::AnalyzeCallsite(const MIRFunction &caller, MIRFunction &callee, const CallNode &callStmt) { + GStrIdx callerStrIdx = caller.GetNameStrIdx(); + GStrIdx calleeStrIdx = callee.GetNameStrIdx(); + // For noInlineList function. + if (noInlineListCallee.find(calleeStrIdx) != noInlineListCallee.end()) { + auto callerList = noInlineListCallee[calleeStrIdx]; + if (callerList->empty()) { + return InlineResult(false, "LIST_NOINLINE_FUNC"); + } + if (callerList->find(calleeStrIdx) != callerList->end()) { + return InlineResult(false, "LIST_NOINLINE_CALLSITE"); + } + } + // For hardCoded function, we check nothing. + if (hardCodedCallee.find(calleeStrIdx) != hardCodedCallee.end()) { + return InlineResult(true, "HARD_INLINE"); + } + if (excludedCaller.find(callerStrIdx) != excludedCaller.end()) { + return InlineResult(false, "EXCLUDED_CALLER"); + } + if (excludedCallee.find(calleeStrIdx) != excludedCallee.end()) { + return InlineResult(false, "EXCLUDED_CALLEE"); + } + if (StringUtils::StartsWith(callee.GetName(), "MCC_")) { + return InlineResult(false, "INTRINSIC"); + } + auto itCaller = rcWhiteList.find(callerStrIdx); + auto itCallee = rcWhiteList.find(calleeStrIdx); + if (itCaller != rcWhiteList.end() && itCallee == rcWhiteList.end()) { + return InlineResult(false, "RC_UNSAFE"); + } + if (callee.GetBody() == nullptr) { + return InlineResult(false, "EMPTY_CALLEE"); + } + if (!FuncInlinable(callee)) { + return InlineResult(false, "ATTR"); + } + // For inlineList function. + if (inlineListCallee.find(calleeStrIdx) != inlineListCallee.end()) { + auto callerList = inlineListCallee[calleeStrIdx]; + if (callerList->empty()) { + return InlineResult(true, "LIST_INLINE_FUNC"); + } + if (callerList->find(calleeStrIdx) != callerList->end()) { + return InlineResult(true, "LIST_INLINE_CALLSITE"); + } + } + CGNode *node = cg->GetCGNode(&callee); + if (node == nullptr) { + return InlineResult(false, "NODE_NULL"); + } + if (node->IsMustNotBeInlined()) { + return InlineResult(false, "VMStack"); + } + return AnalyzeCallee(caller, callee, callStmt); +} + +static InlineResult GetInlineResult(uint32 threshold, uint32 thresholdType, uint32 cost) { + if (cost == UINT32_MAX) { + return InlineResult(false, "NOT_ALLOWED_NODE"); + } + + if (cost <= threshold) { + switch (thresholdType) { + case kSmallFuncThreshold: + return InlineResult(true, "AUTO_INLINE"); + case kHotFuncThreshold: + return InlineResult(true, "AUTO_INLINE_HOT"); + case kRecursiveFuncThreshold: + return InlineResult(true, "AUTO_INLINE_RECURSICE_FUNCTION"); + case kHotAndRecursiveFuncThreshold: + return InlineResult(true, "AUTO_INLINE_HOT_RECURSICE_FUNCTION"); + default: + break; + } + } + switch (thresholdType) { + case kSmallFuncThreshold: + return InlineResult(false, "TOO_BIG " + std::to_string(cost)); + case kHotFuncThreshold: + return InlineResult(false, "HOT_METHOD_TOO_BIG " + std::to_string(cost)); + case kRecursiveFuncThreshold: + return InlineResult(false, "RECURSIVE_FUNCTION_TOO_BIG " + std::to_string(cost)); + case kHotAndRecursiveFuncThreshold: + return InlineResult(false, "HOT_RECURSIVE_FUNCTION_TOO_BIG " + std::to_string(cost)); + default: + break; + } + return InlineResult(false, "IMPOSSIBLE SITUATION!!!"); +} + +InlineResult MInline::AnalyzeCallee(const MIRFunction &caller, MIRFunction &callee, const CallNode &callStmt) { + if (!IsSafeToInline(&callee, callStmt)) { + return InlineResult(false, "UNSAFE_TO_INLINE"); + } + uint32 thresholdType = kSmallFuncThreshold; + // Update threshold if this callsite is hot, or dealing with recursive function + uint32 threshold = smallFuncThreshold; + if (inlineWithProfile && IsHotCallSite(caller, callee, callStmt)) { + threshold = hotFuncThreshold; + thresholdType = kHotFuncThreshold; + } + if (&caller == &callee) { + threshold = (threshold > recursiveFuncThreshold) ? threshold : recursiveFuncThreshold; + if (thresholdType != kHotFuncThreshold) { + thresholdType = kRecursiveFuncThreshold; + } else { + thresholdType = kHotAndRecursiveFuncThreshold; + } + } + uint32 cost = 0; + BlockNode *calleeBody = callee.GetBody(); + if (&caller == &callee && currFuncBody != nullptr) { + // This is self recursive inline + calleeBody = currFuncBody; + } + + if (funcToCostMap.find(&callee) != funcToCostMap.end()) { + cost = funcToCostMap[&callee]; + } else { + FuncCostResultType checkResult = GetFuncCost(callee, *calleeBody, cost, threshold); + if (checkResult == kNotAllowedNode) { + funcToCostMap[&callee] = UINT32_MAX; + return InlineResult(false, "NOT_ALLOWED_NODE"); + } else { + funcToCostMap[&callee] = cost; + } + } + return GetInlineResult(threshold, thresholdType, cost); +} + +void MInline::InlineCallsBlockInternal(MIRFunction &func, BlockNode &enclosingBlk, BaseNode &baseNode, bool &changed) { + CallNode &callStmt = static_cast(baseNode); + MIRFunction *callee = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callStmt.GetPUIdx()); + InlineResult result = AnalyzeCallsite(func, *callee, callStmt); + if (result.canInline) { + module.SetCurFunction(&func); + if (dumpDetail && dumpFunc == func.GetName()) { + LogInfo::MapleLogger() << "[Dump before inline ] " << func.GetName() << '\n'; + func.Dump(false); + } + bool inlined = PerformInline(func, enclosingBlk, callStmt, *callee); + if (dumpDetail && dumpFunc == func.GetName()) { + LogInfo::MapleLogger() << "[Dump after inline ] " << func.GetName() << '\n'; + func.Dump(false); + } + changed = (inlined ? true : changed); + if (dumpDetail && inlined) { + LogInfo::MapleLogger() << "[" << result.reason << "] " << callee->GetName() << " to " << func.GetName() << '\n'; + } + } else { + if (dumpDetail) { + LogInfo::MapleLogger() << "[INLINE_FAILED] " << "[" << result.reason << "] " << callee->GetName() << + " to " << func.GetName() << '\n'; + } + } +} + +void MInline::ComputeTotalSize() { + for (auto it = cg->Begin(); it != cg->End(); ++it) { + CGNode *caller = it->second; + totalSize += caller->GetNodeCount(); + } +} + +void MInline::CollectMustInlineFuncs() { + // Add here the function names that must be inlined. + std::unordered_set funcs = {}; + for (auto name : funcs) { + GStrIdx nameStrIdx = GlobalTables::GetStrTable().GetStrIdxFromName(name); + (void)hardCodedCallee.insert(nameStrIdx); + } +} + +void MInline::MarkUnInlinableFunction() const { + const MapleVector &topVec = cg->GetSCCTopVec(); + for (MapleVector::const_reverse_iterator it = topVec.rbegin(); it != topVec.rend(); ++it) { + for (CGNode *node : (*it)->GetCGNodes()) { + std::string name = node->GetMIRFunction()->GetName(); + if (node->IsMustNotBeInlined() || + StringUtils::StartsWith(name, kDalvikSystemStr) || + StringUtils::StartsWith(name, kJavaLangThreadStr)) { + node->SetMustNotBeInlined(); + if (node->HasCaller()) { + MarkParent(*node); + } + } + } + } +} + +void MInline::Inline() { + ApplyInlineListInfo(inlineFuncList, inlineListCallee); + ApplyInlineListInfo(noInlineFuncList, noInlineListCallee); + CollectMustInlineFuncs(); + ComputeTotalSize(); + MarkUnInlinableFunction(); + const MapleVector &topVec = cg->GetSCCTopVec(); + for (MapleVector::const_reverse_iterator it = topVec.rbegin(); it != topVec.rend(); ++it) { + for (CGNode *node : (*it)->GetCGNodes()) { + InlineCalls(*node); + } + } + return; +} + +void MInline::CleanupInline() { + const MapleVector &topVec = cg->GetSCCTopVec(); + for (MapleVector::const_reverse_iterator it = topVec.rbegin(); it != topVec.rend(); ++it) { + for (CGNode *node : (*it)->GetCGNodes()) { + MIRFunction *func = node->GetMIRFunction(); + if (func != nullptr && func->IsFromMpltInline()) { + // visit all the func which has been inlined, mark the static symbol, string symbol and function symbol as used. + auto f = inlineTimesMap.find(func); + if (f != inlineTimesMap.end() && inlineTimesMap[func] > 0) { + MarkUsedSymbols(func->GetBody()); + } + func->SetBody(nullptr); + } + } + } + // after marking all the used symbols, set the other symbols as unused. + for (size_t i = 1; i < GlobalTables::GetGsymTable().GetSymbolTableSize(); ++i) { + MIRSymbol *symbol = GlobalTables::GetGsymTable().GetSymbolFromStidx(i); + if (symbol != nullptr && symbol->IsTmpUnused()) { + symbol->SetStorageClass(kScUnused); + if (dumpDetail) { + LogInfo::MapleLogger() << "[INLINE_UNUSED_SYMBOL] " << symbol->GetName() << '\n'; + } + } + } + if (dumpDetail) { + LogInfo::MapleLogger() << "[INLINE_SUMMARY] " << module.GetFileName() << '\n'; + for (auto it = inlineTimesMap.begin(); it != inlineTimesMap.end(); ++it) { + LogInfo::MapleLogger() << "[INLINE_SUMMARY] " << it->first->GetName() << " => " << it->second << '\n'; + } + LogInfo::MapleLogger() << "[INLINE_SUMMARY] " << module.GetFileName() << '\n'; + } + + if (dumpDetail) { + auto &records = module.GetRealCaller(); + for (auto it : records) { + std::string caller = GlobalTables::GetStrTable().GetStringFromStrIdx(it.first.first); + std::string callee = GlobalTables::GetStrTable().GetStringFromStrIdx(it.first.second); + std::string realCaller = GlobalTables::GetStrTable().GetStringFromStrIdx(it.second); + LogInfo::MapleLogger() << "[REAL_CALLER] caller: " << caller << " callee: " << callee << + " realCaller: " << realCaller << '\n'; + } + } + return; +} + +void MInline::MarkSymbolUsed(const StIdx &symbolIdx) const { + MIRSymbol *symbol = GlobalTables::GetGsymTable().GetSymbolFromStidx(symbolIdx.Idx()); + symbol->SetIsTmpUnused(false); + std::string syName = symbol->GetName(); + // when _PTR_C_STR_XXXX is used, mark _C_STR_XXXX as used too. + if (StringUtils::StartsWith(syName, namemangler::kPtrPrefixStr)) { + GStrIdx gStrIdx = GlobalTables::GetStrTable().GetStrIdxFromName(syName.substr(strlen(namemangler::kPtrPrefixStr))); + MIRSymbol *anotherSymbol = GlobalTables::GetGsymTable().GetSymbolFromStrIdx(gStrIdx); + anotherSymbol->SetIsTmpUnused(false); + } +} + +void MInline::MarkUsedSymbols(const BaseNode *baseNode) const { + if (baseNode == nullptr) { + return; + } + Opcode op = baseNode->GetOpCode(); + switch (op) { + case OP_block: { + const BlockNode *blk = static_cast(baseNode); + for (auto &stmt : blk->GetStmtNodes()) { + MarkUsedSymbols(&stmt); + } + break; + } + case OP_dassign: { + const DassignNode *dassignNode = static_cast(baseNode); + MarkSymbolUsed(dassignNode->GetStIdx()); + break; + } + case OP_addrof: + case OP_dread: { + const AddrofNode *dreadNode = static_cast(baseNode); + MarkSymbolUsed(dreadNode->GetStIdx()); + break; + } + case OP_callassigned: + case OP_virtualcallassigned: + case OP_superclasscallassigned: + case OP_interfacecallassigned: + case OP_customcallassigned: + case OP_polymorphiccallassigned: + case OP_intrinsiccallassigned: + case OP_xintrinsiccallassigned: + case OP_intrinsiccallwithtypeassigned: { + const CallNode *callStmt = static_cast(baseNode); + MIRFunction *callee = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callStmt->GetPUIdx()); + MIRSymbol *symbol = callee->GetFuncSymbol(); + symbol->SetIsTmpUnused(false); + break; + } + default: { + break; + } + } + for (size_t i = 0; i < baseNode->NumOpnds(); ++i) { + MarkUsedSymbols(baseNode->Opnd(i)); + } +} + +// Unified interface to run inline module phase. +AnalysisResult *DoInline::Run(MIRModule *module, ModuleResultMgr *mgr) { + MemPool *memPool = memPoolCtrler.NewMemPool("inline mempool"); + KlassHierarchy *klassHierarchy = static_cast(mgr->GetAnalysisResult(MoPhase_CHA, module)); + CHECK_FATAL(klassHierarchy != nullptr, "Expecting a valid KlassHierarchy, found nullptr"); + CallGraph *cg = static_cast(mgr->GetAnalysisResult(MoPhase_CALLGRAPH_ANALYSIS, module)); + CHECK_FATAL(cg != nullptr, "Expecting a valid CallGraph, found nullptr"); + + MInline mInline(*module, memPool, klassHierarchy, cg); + mInline.Inline(); + mInline.CleanupInline(); + mgr->InvalidAnalysisResult(MoPhase_CALLGRAPH_ANALYSIS, module); + memPoolCtrler.DeleteMemPool(memPool); + if (module->firstInline) { + module->firstInline = false; + } + return nullptr; +} +} // namespace maple diff --git a/src/mapleall/maple_ipa/src/interleaved_manager.cpp b/src/mapleall/maple_ipa/src/interleaved_manager.cpp index 9d822ed8c148ff3fa82e147ec07e8a6affd1c6a9..0f335a7e718a318559bb1fd8f498d0c93817b31b 100644 --- a/src/mapleall/maple_ipa/src/interleaved_manager.cpp +++ b/src/mapleall/maple_ipa/src/interleaved_manager.cpp @@ -22,6 +22,11 @@ #include "mempool.h" #include "phase_manager.h" #include "mpl_timer.h" +#include "call_graph.h" +#include "ipa_escape_analysis.h" +#include "me_ssa_devirtual.h" +#include "me_func_opt.h" +#include "thread_env.h" namespace maple { std::vector> InterleavedManager::interleavedTimer; @@ -56,6 +61,129 @@ void InterleavedManager::AddPhases(const std::vector &phases, bool } } +void InterleavedManager::AddIPAPhases(std::vector &phases, bool timePhases, bool genMpl) { + ModuleResultMgr *mrm = nullptr; + if (!phaseManagers.empty()) { + // ModuleResult such class hierarchy needs to be carried on + PhaseManager *pm = phaseManagers.back(); + mrm = pm->GetModResultMgr(); + } + + auto *fpm = GetMemPool()->New(GetMemPool(), mirModule, mrm); + fpm->RegisterFuncPhases(); + if (genMpl) { + fpm->SetGenMeMpl(true); + } + if (timePhases) { + fpm->SetTimePhases(true); + } + fpm->AddPhasesNoDefault(phases); + phaseManagers.push_back(fpm); + fpm->SetIPA(true); +} + +void InterleavedManager::IPARun(MeFuncPhaseManager &fpm) { + uint64 rangeNum = 0; + CHECK_NULL_FATAL(fpm.GetModResultMgr()); + auto *pcg = static_cast(fpm.GetModResultMgr()->GetAnalysisResult(MoPhase_CALLGRAPH_ANALYSIS, + &mirModule)); + CHECK_NULL_FATAL(pcg); + + const MapleVector &sccTopVec = pcg->GetSCCTopVec(); + for (auto nodeIt = sccTopVec.rbegin(); nodeIt != sccTopVec.rend(); ++nodeIt) { + ++rangeNum; + SCCNode *curSCCNode = *nodeIt; + + if (IPAEscapeAnalysis::kDebug) { + LogInfo::MapleLogger() << "<<<<<<<<<<<<<<<<<< SCC BEGIN <<<<<<<<<<<<<<<<<<" << "\n"; + LogInfo::MapleLogger() << "[SCCCOUNT] " << rangeNum << ", [SIZE] " << curSCCNode->GetCGNodes().size() << "\n"; + curSCCNode->Dump(); + } + bool needConservation = false; + if (curSCCNode->GetCGNodes().size() > IPAEscapeAnalysis::kFuncInSCCLimit) { + if (IPAEscapeAnalysis::kDebug) { + LogInfo::MapleLogger() << "[kFuncInSCCLimit] [SCCCOUNT] " << rangeNum << ", [SIZE] " << + curSCCNode->GetCGNodes().size() << "\n"; + } + needConservation = true; + } + bool cgUpdated = true; + int iterationTime = 0; + do { + if (iterationTime == IPAEscapeAnalysis::kSCCConvergenceLimit) { + if (IPAEscapeAnalysis::kDebug) { + LogInfo::MapleLogger() << "[kSCCConvergenceLimit] [SCCCOUNT] " << rangeNum << ", [SIZE] " << + curSCCNode->GetCGNodes().size() << "\n"; + } + needConservation = true; + } + ++iterationTime; + if (IPAEscapeAnalysis::kDebug) { + LogInfo::MapleLogger() << "===========LOOP BEGIN============ " << iterationTime << "\n"; + } + + // At the loop beginning, we set cgUpdated to false, if any eaCG of the function in + // the scc changed, we set cgUpdated to true. + cgUpdated = false; + for (auto *node : curSCCNode->GetCGNodes()) { + MIRFunction *func = node->GetMIRFunction(); + if (func->GetBody() == nullptr) { + // No matter whether current node needs update or not, + // there is no need to run the following code, because the function has no body. + continue; + } + if (func->IsNative() || func->IsAbstract()) { + continue; + } + if (fpm.GetPhaseSequence()->empty()) { + continue; + } + mirModule.SetCurFunction(func); + if (func->GetEACG() != nullptr) { + func->GetEACG()->UnSetCGUpdateFlag(); + } + if (IPAEscapeAnalysis::kDebug) { + LogInfo::MapleLogger() << "[FUNC_IN_SCC] " << func->GetName() << " [SCCCOUNT] " << rangeNum << "\n"; + } + if (func->GetMeFunc() != nullptr) { + if (IPAEscapeAnalysis::kDebug) { + LogInfo::MapleLogger() << "[HANDLED_BEFORE] skip all phase but ipaea" << "\n"; + } + if (needConservation) { + ASSERT_NOT_NULL(func->GetEACG()); + func->GetEACG()->SetNeedConservation(); + } + fpm.RunFuncPhase(func->GetMeFunc(), static_cast(fpm.GetPhaseFromName("ipaea"))); + } else { + // lower, create BB and build cfg + fpm.Run(func, rangeNum, meInput); + } + cgUpdated = func->GetEACG()->CGHasUpdated(); + } + if (IPAEscapeAnalysis::kDebug) { + LogInfo::MapleLogger() << "===========LOOP END============ " << iterationTime << "\n"; + } + if (needConservation || !curSCCNode->HasRecursion()) { + break; + } + } while (cgUpdated); + + for (auto *node : curSCCNode->GetCGNodes()) { + MIRFunction *func = node->GetMIRFunction(); + mirModule.SetCurFunction(func); + if (func->GetEACG() != nullptr && func->GetBody() != nullptr && IPAEscapeAnalysis::kDebug) { + func->GetEACG()->CountObjEAStatus(); + } + if (func->GetMeFunc() != nullptr) { + memPoolCtrler.DeleteMemPool(func->GetMeFunc()->GetMemPool()); + } + } + fpm.GetAnalysisResultManager()->InvalidAllResults(); + if (IPAEscapeAnalysis::kDebug) { + LogInfo::MapleLogger() << ">>>>>>>>>>>>>>>>>> SCC END >>>>>>>>>>>>>>>>>>" << "\n\n"; + } + } +} void InterleavedManager::OptimizeFuncs(MeFuncPhaseManager &fpm, MapleVector &compList) { for (size_t i = 0; i < compList.size(); ++i) { diff --git a/src/mapleall/maple_ipa/src/ipa_escape_analysis.cpp b/src/mapleall/maple_ipa/src/ipa_escape_analysis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e4281ea0bff7380406b57755d34bc04410e1fe94 --- /dev/null +++ b/src/mapleall/maple_ipa/src/ipa_escape_analysis.cpp @@ -0,0 +1,1605 @@ +/* + * Copyright (c) [2019-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "ipa_escape_analysis.h" +#include + +namespace maple { +constexpr maple::uint32 kInvalid = 0xffffffff; +static bool IsExprRefOrPtr(const MeExpr &expr) { + return expr.GetPrimType() == PTY_ref || expr.GetPrimType() == PTY_ptr; +} + +static bool IsTypeRefOrPtr(PrimType type) { + return type == PTY_ref || type == PTY_ptr; +} + +static bool IsGlobal(const SSATab &ssaTab, const VarMeExpr &expr) { + const OriginalSt *symOst = ssaTab.GetOriginalStFromID(expr.GetOstIdx()); + if (symOst->GetMIRSymbol()->GetStIdx().IsGlobal()) { + return true; + } + return false; +} + +static bool IsGlobal(const SSATab &ssaTab, const AddrofMeExpr &expr) { + const OriginalSt *symOst = ssaTab.GetOriginalStFromID(expr.GetOstIdx()); + if (symOst->GetMIRSymbol()->GetStIdx().IsGlobal()) { + return true; + } + return false; +} + +static bool IsZeroConst(const VarMeExpr *expr) { + if (expr == nullptr) { + return false; + } + if (expr->GetDefBy() != kDefByStmt) { + return false; + } + MeStmt *stmt = expr->GetDefStmt(); + if (stmt->GetOp() != OP_dassign) { + return false; + } + DassignMeStmt *dasgn = static_cast(stmt); + if (dasgn->GetRHS()->GetMeOp() != kMeOpConst) { + return false; + } + ConstMeExpr *constExpr = static_cast(dasgn->GetRHS()); + if (constExpr->GetConstVal()->GetKind() == kConstInt && constExpr->GetConstVal()->IsZero()) { + return true; + } + return false; +} + +static bool StartWith(const std::string &str, const std::string &head) { + return str.compare(0, head.size(), head) == 0; +} + +static bool IsVirtualVar(const SSATab &ssaTab, const VarMeExpr &expr) { + const OriginalSt *ost = ssaTab.GetOriginalStFromID(expr.GetOstIdx()); + return ost->GetIndirectLev() > 0; +} + +static bool IsInWhiteList(const MIRFunction &func) { + std::vector whiteList = { + "MCC_Reflect_Check_Casting_Array", + "MCC_Reflect_Check_Casting_NoArray", + "MCC_ThrowStringIndexOutOfBoundsException", + "MCC_ArrayMap_String_Int_clear", + "MCC_ArrayMap_String_Int_put", + "MCC_ArrayMap_String_Int_getOrDefault", + "MCC_ArrayMap_String_Int_size", + "MCC_ThrowSecurityException", + "MCC_String_Equals_NotallCompress", + "memcmpMpl", + "Native_java_lang_String_compareTo__Ljava_lang_String_2", + "Native_java_lang_String_getCharsNoCheck__II_3CI", + "Native_java_lang_String_toCharArray__", + "Native_java_lang_System_arraycopyBooleanUnchecked___3ZI_3ZII", + "Native_java_lang_System_arraycopyByteUnchecked___3BI_3BII", + "Native_java_lang_System_arraycopyCharUnchecked___3CI_3CII", + "Native_java_lang_System_arraycopyDoubleUnchecked___3DI_3DII", + "Native_java_lang_System_arraycopyFloatUnchecked___3FI_3FII", + "Native_java_lang_System_arraycopyIntUnchecked___3II_3III", + "Native_java_lang_System_arraycopy__Ljava_lang_Object_2ILjava_lang_Object_2II", + "Native_java_lang_System_arraycopyLongUnchecked___3JI_3JII", + "Native_java_lang_System_arraycopyShortUnchecked___3SI_3SII", + "getpriority", + "setpriority" + }; + for (std::string name : whiteList) { + if (func.GetName() == name) { + // close all the whitelist + return false; + } + } + return false; +} + +static bool IsNoSideEffect(CallMeStmt &call) { + CallMeStmt &callAssign = utils::ToRef(&call); + MIRFunction &mirFunc = callAssign.GetTargetFunction(); + if (IsInWhiteList(mirFunc)) { + return true; + } + // Non-nullptr means it has return value + CHECK_FATAL(callAssign.GetMustDefList() != nullptr, "Impossible"); + if (callAssign.GetMustDefList()->size() == 1) { + if (callAssign.GetMustDefListItem(0).GetLHS()->GetMeOp() != kMeOpVar && + callAssign.GetMustDefListItem(0).GetLHS()->GetMeOp() != kMeOpReg) { + CHECK_FATAL(false, "NYI"); + } + if (IsExprRefOrPtr(*callAssign.GetMustDefListItem(0).GetLHS())) { + return false; + } + } + + const MapleVector &opnds = call.GetOpnds(); + const size_t size = opnds.size(); + for (size_t i = 0; i < size; ++i) { + if (IsExprRefOrPtr(*opnds[i])) { + return false; + } + } + return true; +} + +static bool IsRegAssignStmtForClassMeta(const RegassignMeStmt ®Assign) { + MeExpr &rhs = utils::ToRef(regAssign.GetRHS()); + if (rhs.GetOp() == OP_add) { + return true; + } + + if (instance_of(rhs)) { + IvarMeExpr &ivar = static_cast(rhs); + MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ivar.GetTyIdx()); + MIRPtrType &ptrType = utils::ToRef(safe_cast(type)); + if (ptrType.GetPointedType()->GetName() == "__class_meta__" || + (ptrType.GetPointedType()->GetName() == "Ljava_2Flang_2FObject_3B" && ivar.GetFieldID() == 1)) { + return true; + } + } + return false; +} + +TyIdx IPAEscapeAnalysis::GetAggElemType(const MIRType &aggregate) const { + switch (aggregate.GetKind()) { + case kTypePointer: { + const MIRPtrType *pointType = static_cast(&aggregate); + const MIRType *pointedType = pointType->GetPointedType(); + switch (pointedType->GetKind()) { + case kTypeClass: + case kTypeScalar: + return pointedType->GetTypeIndex(); + case kTypePointer: + case kTypeJArray: + return GetAggElemType(*pointedType); + default: + return TyIdx(0); + } + } + case kTypeJArray: { + const MIRJarrayType *arrType = static_cast(&aggregate); + const MIRType *elemType = arrType->GetElemType(); + CHECK_NULL_FATAL(elemType); + switch (elemType->GetKind()) { + case kTypeScalar: + return elemType->GetTypeIndex(); + case kTypePointer: + case kTypeJArray: + return GetAggElemType(*elemType); + default: // Not sure what type is + return TyIdx(0); + } + } + default: + CHECK_FATAL(false, "Should not reach here"); + return TyIdx(0); // to eliminate compilation warning + } +} + +// check whether the newly allocated object implements Runnable, Throwable, extends Reference or has a finalizer +bool IPAEscapeAnalysis::IsSpecialEscapedObj(const MeExpr &alloc) const { + if (alloc.GetOp() == OP_gcpermalloc || alloc.GetOp() == OP_gcpermallocjarray) { + return true; + } + TyIdx tyIdx; + const static TyIdx runnableInterface = kh->GetKlassFromLiteral("Ljava_2Flang_2FRunnable_3B")->GetTypeIdx(); + if (alloc.GetOp() == OP_gcmalloc) { + tyIdx = static_cast(&alloc)->GetTyIdx(); + } else { + CHECK_FATAL(alloc.GetOp() == OP_gcmallocjarray, "must be OP_gcmallocjarray"); + MIRType *arrType = + GlobalTables::GetTypeTable().GetTypeFromTyIdx(static_cast(&alloc)->GetTyIdx()); + tyIdx = GetAggElemType(*arrType); + if (tyIdx == TyIdx(0)) { + return true; // deal as escape + } + } + MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx); + if (type->GetKind() == kTypeScalar) { + return false; + } + Klass *klass = kh->GetKlassFromTyIdx(tyIdx); + CHECK_FATAL(klass, "impossible"); + for (Klass *inter : klass->GetImplInterfaces()) { + if (inter->GetTypeIdx() == runnableInterface) { + return true; + } + } + if (klass->HasFinalizer() || klass->IsExceptionKlass()) { + return true; + } + + // check subclass of Reference class, such as WeakReference, PhantomReference, SoftReference and Cleaner + static Klass *referenceKlass = kh->GetKlassFromLiteral("Ljava_2Flang_2Fref_2FReference_3B"); + if (kh->IsSuperKlass(referenceKlass, klass)) { + return true; + } + return false; +} + +EACGRefNode *IPAEscapeAnalysis::GetOrCreateCGRefNodeForReg(RegMeExpr ®, bool createObjNode) { + EACGBaseNode *node = eaCG->GetCGNodeFromExpr(®); + EACGRefNode *refNode = nullptr; + if (node == nullptr) { + refNode = eaCG->CreateReferenceNode(®, kNoEscape, false); + cgChangedInSCC = true; + } else { + refNode = static_cast(node); + } + if (node == nullptr && createObjNode) { + EACGObjectNode *objNode = GetOrCreateCGObjNode(nullptr, nullptr, refNode->GetEAStatus()); + refNode->AddOutNode(*objNode); + } + return refNode; +} + +EACGRefNode *IPAEscapeAnalysis::GetOrCreateCGRefNodeForAddrof(AddrofMeExpr &var, bool createObjNode) { + if (IsGlobal(*ssaTab, var)) { + eaCG->UpdateExprOfGlobalRef(&var); + return eaCG->GetGlobalReference(); + } + EACGBaseNode *node = eaCG->GetCGNodeFromExpr(&var); + EACGRefNode *refNode = nullptr; + if (node == nullptr) { + refNode = eaCG->CreateReferenceNode(&var, kNoEscape, false); + cgChangedInSCC = true; + } else { + refNode = static_cast(node); + } + if (node == nullptr && createObjNode) { + EACGObjectNode *objNode = GetOrCreateCGObjNode(nullptr, nullptr, refNode->GetEAStatus()); + refNode->AddOutNode(*objNode); + } + return refNode; +} + +EACGRefNode *IPAEscapeAnalysis::GetOrCreateCGRefNodeForVar(VarMeExpr &var, bool createObjNode) { + if (IsGlobal(*ssaTab, var)) { + eaCG->UpdateExprOfGlobalRef(&var); + return eaCG->GetGlobalReference(); + } + EACGBaseNode *node = eaCG->GetCGNodeFromExpr(&var); + EACGRefNode *refNode = nullptr; + if (node == nullptr) { + refNode = eaCG->CreateReferenceNode(&var, kNoEscape, false); + cgChangedInSCC = true; + } else { + refNode = static_cast(node); + } + if (node == nullptr && createObjNode) { + EACGObjectNode *objNode = GetOrCreateCGObjNode(nullptr, nullptr, refNode->GetEAStatus()); + refNode->AddOutNode(*objNode); + } + return refNode; +} + +EACGRefNode *IPAEscapeAnalysis::GetOrCreateCGRefNodeForVarOrReg(MeExpr &var, bool createObjNode) { + if (var.GetMeOp() == kMeOpVar) { + return GetOrCreateCGRefNodeForVar(static_cast(var), createObjNode); + } else if (var.GetMeOp() == kMeOpReg) { + return GetOrCreateCGRefNodeForReg(static_cast(var), createObjNode); + } + CHECK_FATAL(false, "Impossible"); + return nullptr; +} + +static FieldID GetBaseFieldId(const KlassHierarchy &kh, TyIdx tyIdx, FieldID fieldId) { + FieldID ret = fieldId; + Klass *klass = kh.GetKlassFromTyIdx(tyIdx); + CHECK_FATAL(klass != nullptr, "Impossible"); + Klass *super = klass->GetSuperKlass(); + if (super == nullptr) { + return ret; + } + MIRStructType *structType = super->GetMIRStructType(); + TyIdx typeIdx = structType->GetFieldTyIdx(fieldId - 1); + while (typeIdx != 0u) { + --ret; + klass = super; + super = klass->GetSuperKlass(); + if (super == nullptr) { + return ret; + } + structType = super->GetMIRStructType(); + typeIdx = structType->GetFieldTyIdx(ret - 1); + } + return ret; +} + +void IPAEscapeAnalysis::GetOrCreateCGFieldNodeForIvar(std::vector &fieldNodes, IvarMeExpr &ivar, + MeStmt &stmt, bool createObjNode) { + MeExpr *base = ivar.GetBase(); + FieldID fieldId = ivar.GetFieldID(); + std::vector baseNodes; + if (base->GetMeOp() == kMeOpReg && fieldId == 0) { + GetArrayBaseNodeForReg(baseNodes, static_cast(*base), stmt); + } else { + GetCGNodeForMeExpr(baseNodes, *base, stmt, true); + } + bool ifHandled = (eaCG->GetCGNodeFromExpr(&ivar) != nullptr); + if (ivar.GetFieldID() != 0) { + MIRPtrType *ptrType = static_cast(GlobalTables::GetTypeTable().GetTypeFromTyIdx(ivar.GetTyIdx())); + TyIdx tyIdx = ptrType->GetPointedTyIdx(); + fieldId = GetBaseFieldId(*kh, tyIdx, ivar.GetFieldID()); + } + for (const auto &baseNode : baseNodes) { + for (const auto &objNode : baseNode->GetPointsToSet()) { + EACGFieldNode *fieldNode = objNode->GetFieldNodeFromIdx(fieldId); + if (!ifHandled && fieldNode != nullptr) { + eaCG->UpdateExprOfNode(*fieldNode, &ivar); + } else if (!ifHandled && fieldNode == nullptr) { + fieldNode = eaCG->CreateFieldNode(&ivar, objNode->GetEAStatus(), fieldId, objNode, false); + cgChangedInSCC = true; + if (createObjNode) { + EACGObjectNode *phanObjNode = GetOrCreateCGObjNode(nullptr); + fieldNode->AddOutNode(*phanObjNode); + } + } + if (fieldNode != nullptr) { + fieldNodes.push_back(fieldNode); + } + } + } +} + +void IPAEscapeAnalysis::GetOrCreateCGFieldNodeForIAddrof(std::vector &fieldNodes, OpMeExpr &expr, + MeStmt &stmt, bool createObjNode) { + MeExpr *base = expr.GetOpnd(0); + FieldID fieldId = expr.GetFieldID(); + std::vector baseNodes; + if (base->GetMeOp() == kMeOpReg && fieldId == 0) { + GetArrayBaseNodeForReg(baseNodes, static_cast(*base), stmt); + } else { + GetCGNodeForMeExpr(baseNodes, *base, stmt, true); + } + bool ifHandled = (eaCG->GetCGNodeFromExpr(&expr) != nullptr); + if (expr.GetFieldID() != 0) { + MIRPtrType *ptrType = static_cast(GlobalTables::GetTypeTable().GetTypeFromTyIdx(expr.GetTyIdx())); + TyIdx tyIdx = ptrType->GetPointedTyIdx(); + fieldId = GetBaseFieldId(*kh, tyIdx, expr.GetFieldID()); + } + for (const auto &baseNode : baseNodes) { + for (const auto &objNode : baseNode->GetPointsToSet()) { + EACGFieldNode *fieldNode = objNode->GetFieldNodeFromIdx(fieldId); + if (!ifHandled && fieldNode != nullptr) { + eaCG->UpdateExprOfNode(*fieldNode, &expr); + } else if (!ifHandled && fieldNode == nullptr) { + fieldNode = eaCG->CreateFieldNode(&expr, objNode->GetEAStatus(), fieldId, objNode, false); + cgChangedInSCC = true; + if (createObjNode) { + EACGObjectNode *phanObjNode = GetOrCreateCGObjNode(nullptr); + fieldNode->AddOutNode(*phanObjNode); + } + } + if (fieldNode != nullptr) { + fieldNodes.push_back(fieldNode); + } + } + } +} + +EACGObjectNode *IPAEscapeAnalysis::GetOrCreateCGObjNode(MeExpr *expr, MeStmt *stmt, EAStatus easOfPhanObj) { + EAStatus eas = kNoEscape; + TyIdx tyIdx; + Location *location = nullptr; + bool isPhantom; + if (expr != nullptr) { + EACGBaseNode *cgNode = eaCG->GetCGNodeFromExpr(expr); + if (cgNode != nullptr) { + CHECK_FATAL(cgNode->IsObjectNode(), "should be object"); + EACGObjectNode *objNode = static_cast(cgNode); + return objNode; + } + if (expr->IsGcmalloc()) { + CHECK_FATAL(stmt != nullptr, "Impossible"); + location = mirModule->GetMemPool()->New(mirModule->GetFileName(), stmt->GetSrcPosition().FileNum(), + stmt->GetSrcPosition().LineNum()); + isPhantom = false; + if (IsSpecialEscapedObj(*expr)) { + eas = kGlobalEscape; + } + if (expr->GetOp() == OP_gcmalloc || expr->GetOp() == OP_gcpermalloc) { + tyIdx = static_cast(expr)->GetTyIdx(); + } else { + tyIdx = static_cast(expr)->GetTyIdx(); + } + } else { + isPhantom = true; + eas = easOfPhanObj; + tyIdx = kInitTyIdx; + } + } else { // null alloc means creating phantom object + isPhantom = true; + eas = easOfPhanObj; + tyIdx = kInitTyIdx; + } + if (eas == kGlobalEscape) { + eaCG->UpdateExprOfNode(*eaCG->GetGlobalObject(), expr); + return eaCG->GetGlobalObject(); + } + cgChangedInSCC = true; + EACGObjectNode *objectNode = eaCG->CreateObjectNode(expr, eas, isPhantom, tyIdx); + if (location != nullptr) { + objectNode->SetLocation(location); + } + return objectNode; +} + +void IPAEscapeAnalysis::CollectDefStmtForReg(std::set &visited, std::set &defStmts, + RegMeExpr ®Var) { + if (regVar.GetDefBy() == kDefByStmt) { + RegassignMeStmt *regAssignStmt = static_cast(regVar.GetDefStmt()); + (void)defStmts.insert(regAssignStmt); + } else if (regVar.GetDefBy() == kDefByPhi) { + if (visited.find(®Var) == visited.end()) { + (void)visited.insert(®Var); + MePhiNode ®PhiNode = regVar.GetDefPhi(); + for (auto ® : regPhiNode.GetOpnds()) { + CollectDefStmtForReg(visited, defStmts, static_cast(*reg)); + } + } + } else { + CHECK_FATAL(false, "not kDefByStmt or kDefByPhi"); + } +} + +void IPAEscapeAnalysis::GetArrayBaseNodeForReg(std::vector &nodes, RegMeExpr ®Var, MeStmt &stmt) { + std::set defStmts; + std::set visited; + CollectDefStmtForReg(visited, defStmts, regVar); + for (auto ®AssignStmt : defStmts) { + MeExpr *rhs = regAssignStmt->GetRHS(); + CHECK_FATAL(rhs != nullptr, "Impossible"); + CHECK_FATAL(rhs->GetOp() == OP_array, "Impossible, funcName: %s", func->GetName().c_str()); + NaryMeExpr *array = static_cast(rhs); + CHECK_FATAL(array->GetOpnds().size() > 0, "access array->GetOpnds() failed"); + MeExpr *base = array->GetOpnd(0); + std::vector baseNodes; + GetCGNodeForMeExpr(baseNodes, *base, stmt, true); + for (auto baseNode : baseNodes) { + nodes.push_back(baseNode); + } + } +} + +void IPAEscapeAnalysis::GetCGNodeForMeExpr(std::vector &nodes, MeExpr &expr, MeStmt &stmt, + bool createObjNode) { + if (expr.GetMeOp() == kMeOpVar) { + VarMeExpr *var = static_cast(&expr); + EACGRefNode *refNode = GetOrCreateCGRefNodeForVar(*var, createObjNode); + nodes.push_back(refNode); + } else if (expr.GetMeOp() == kMeOpIvar) { + IvarMeExpr *ivar = static_cast(&expr); + GetOrCreateCGFieldNodeForIvar(nodes, *ivar, stmt, createObjNode); + } else if (expr.IsGcmalloc()) { + EACGObjectNode *objNode = GetOrCreateCGObjNode(&expr, &stmt); + nodes.push_back(objNode); + } else if (expr.GetMeOp() == kMeOpReg) { + RegMeExpr *regVar = static_cast(&expr); + if (regVar->GetRegIdx() < 0) { + eaCG->UpdateExprOfNode(*eaCG->GetGlobalObject(), &expr); + EACGObjectNode *objNode = eaCG->GetGlobalObject(); + nodes.push_back(objNode); + } else { + if (regVar->GetDefBy() != kDefByStmt && regVar->GetDefBy() != kDefByMustDef) { + CHECK_FATAL(false, "impossible"); + } + EACGRefNode *refNode = GetOrCreateCGRefNodeForReg(*regVar, createObjNode); + nodes.push_back(refNode); + } + } else if (expr.GetMeOp() == kMeOpOp && (expr.GetOp() == OP_retype || expr.GetOp() == OP_cvt)) { + MeExpr *retypeRhs = (static_cast(&expr))->GetOpnd(0); + if (IsExprRefOrPtr(*retypeRhs)) { + GetCGNodeForMeExpr(nodes, *retypeRhs, stmt, createObjNode); + } else { + EACGObjectNode *objNode = nullptr; + VarMeExpr *var = static_cast(retypeRhs); + if (IsZeroConst(var)) { + objNode = GetOrCreateCGObjNode(&expr, nullptr, kNoEscape); + } else { + eaCG->UpdateExprOfNode(*eaCG->GetGlobalObject(), &expr); + objNode = eaCG->GetGlobalObject(); + } + nodes.push_back(objNode); + } + } else if (expr.GetMeOp() == kMeOpOp && expr.GetOp() == OP_select) { + OpMeExpr *opMeExpr = static_cast(&expr); + EACGBaseNode *refNode = eaCG->GetCGNodeFromExpr(opMeExpr); + if (refNode == nullptr) { + refNode = eaCG->CreateReferenceNode(opMeExpr, kNoEscape, false); + for (size_t i = 1; i < 3; ++i) { // OP_select expr has three operands. + std::vector opndNodes; + GetCGNodeForMeExpr(opndNodes, *opMeExpr->GetOpnd(i), stmt, true); + for (auto opndNode : opndNodes) { + refNode->AddOutNode(*opndNode); + } + } + } + nodes.push_back(refNode); + } else if (expr.GetMeOp() == kMeOpAddrof && expr.GetOp() == OP_addrof) { + AddrofMeExpr *var = static_cast(&expr); + EACGRefNode *refNode = GetOrCreateCGRefNodeForAddrof(*var, createObjNode); + nodes.push_back(refNode); + } else if (expr.GetMeOp() == kMeOpOp && expr.GetOp() == OP_iaddrof) { + OpMeExpr *opExpr = static_cast(&expr); + GetOrCreateCGFieldNodeForIAddrof(nodes, *opExpr, stmt, createObjNode); + } else if (expr.GetMeOp() == kMeOpNary && + (expr.GetOp() == OP_intrinsicopwithtype || expr.GetOp() == OP_intrinsicop)) { + NaryMeExpr *naryMeExpr = static_cast(&expr); + if (naryMeExpr->GetIntrinsic() == INTRN_JAVA_CONST_CLASS) { + // get some class's "Class", metadata + eaCG->UpdateExprOfNode(*eaCG->GetGlobalObject(), &expr); + EACGObjectNode *objNode = eaCG->GetGlobalObject(); + nodes.push_back(objNode); + } else if (naryMeExpr->GetIntrinsic() == INTRN_JAVA_MERGE) { + CHECK_FATAL(naryMeExpr->GetOpnds().size() == 1, "must have one opnd"); + MeExpr *opnd = naryMeExpr->GetOpnd(0); + if (IsExprRefOrPtr(*opnd)) { + GetCGNodeForMeExpr(nodes, *opnd, stmt, createObjNode); + } else { + eaCG->UpdateExprOfNode(*eaCG->GetGlobalObject(), &expr); + EACGObjectNode *objNode = eaCG->GetGlobalObject(); + nodes.push_back(objNode); + } + } else { + stmt.Dump(irMap); + CHECK_FATAL(false, "NYI"); + } + } else if (expr.GetMeOp() == kMeOpNary && expr.GetOp() == OP_array) { + NaryMeExpr *array = static_cast(&expr); + CHECK_FATAL(array->GetOpnds().size() > 0, "access array->GetOpnds() failed"); + MeExpr *arrayBase = array->GetOpnd(0); + GetCGNodeForMeExpr(nodes, *arrayBase, stmt, createObjNode); + } else if (expr.GetMeOp() == kMeOpConst) { + ConstMeExpr *constExpr = static_cast(&expr); + EACGObjectNode *objNode = nullptr; + if (constExpr->GetConstVal()->GetKind() == kConstInt && constExpr->IsZero()) { + objNode = GetOrCreateCGObjNode(&expr, nullptr, kNoEscape); + } else { + eaCG->UpdateExprOfNode(*eaCG->GetGlobalObject(), &expr); + objNode = eaCG->GetGlobalObject(); + } + nodes.push_back(objNode); + } else if (expr.GetMeOp() == kMeOpConststr) { + nodes.push_back(eaCG->GetGlobalReference()); + eaCG->UpdateExprOfGlobalRef(&expr); + } else { + stmt.Dump(irMap); + CHECK_FATAL(false, "NYI funcName: %s", func->GetName().c_str()); + } +} + +void IPAEscapeAnalysis::UpdateEscConnGraphWithStmt(MeStmt &stmt) { + switch (stmt.GetOp()) { + case OP_dassign: { + DassignMeStmt *dasgn = static_cast(&stmt); + if (!IsExprRefOrPtr(*dasgn->GetLHS())) { + break; + } + CHECK_FATAL(IsExprRefOrPtr(*dasgn->GetRHS()), "type mis-match"); + EACGRefNode *lhsNode = GetOrCreateCGRefNodeForVar(*dasgn->GetVarLHS(), false); + + std::vector rhsNodes; + GetCGNodeForMeExpr(rhsNodes, *dasgn->GetRHS(), stmt, true); + for (const auto &rhsNode : rhsNodes) { + cgChangedInSCC = (lhsNode->AddOutNode(*rhsNode) ? true : cgChangedInSCC); + } + break; + } + case OP_iassign: { + IassignMeStmt *iasgn = static_cast(&stmt); + if (!IsExprRefOrPtr(*iasgn->GetLHSVal())) { + break; + } + CHECK_FATAL(IsExprRefOrPtr(*iasgn->GetRHS()), "type mis-match"); + // get or create field nodes for lhs (may need to create a phantom object node) + std::vector lhsNodes; + GetOrCreateCGFieldNodeForIvar(lhsNodes, *iasgn->GetLHSVal(), stmt, false); + std::vector rhsNodes; + GetCGNodeForMeExpr(rhsNodes, *iasgn->GetRHS(), stmt, true); + for (const auto &lhsNode : lhsNodes) { + for (const auto &rhsNode : rhsNodes) { + cgChangedInSCC = (lhsNode->AddOutNode(*rhsNode) ? true : cgChangedInSCC); + } + } + break; + } + case OP_maydassign: { + MaydassignMeStmt *mdass = static_cast(&stmt); + CHECK_FATAL(mdass->GetChiList() != nullptr, "Impossible"); + if (mdass->GetChiList()->empty() || !IsExprRefOrPtr(*mdass->GetRHS())) { + break; + } + for (std::pair it : *mdass->GetChiList()) { + ChiMeNode *chi = it.second; + CHECK_FATAL(IsExprRefOrPtr(*chi->GetLHS()), "type mis-match"); + EACGRefNode *lhsNode = GetOrCreateCGRefNodeForVar(*chi->GetLHS(), false); + std::vector rhsNodes; + GetCGNodeForMeExpr(rhsNodes, *mdass->GetRHS(), stmt, true); + for (const auto &rhsNode : rhsNodes) { + cgChangedInSCC = (lhsNode->AddOutNode(*rhsNode) ? true : cgChangedInSCC); + } + } + break; + } + case OP_regassign: { + RegassignMeStmt *regasgn = static_cast(&stmt); + CHECK_FATAL(regasgn->GetLHS() != nullptr, "Impossible"); + CHECK_FATAL(regasgn->GetRegLHS() != nullptr, "Impossible"); + CHECK_FATAL(regasgn->GetRHS() != nullptr, "Impossible"); + if (!IsExprRefOrPtr(*regasgn->GetLHS())) { + break; + } + CHECK_FATAL(IsExprRefOrPtr(*regasgn->GetRHS()), "type mis-match"); + if (IsRegAssignStmtForClassMeta(*regasgn) || regasgn->GetRHS()->GetOp() == OP_array) { + break; + } + EACGRefNode *lhsNode = GetOrCreateCGRefNodeForReg(*regasgn->GetRegLHS(), false); + std::vector rhsNodes; + GetCGNodeForMeExpr(rhsNodes, *regasgn->GetRHS(), stmt, true); + for (const auto &rhsNode : rhsNodes) { + cgChangedInSCC = (lhsNode->AddOutNode(*rhsNode) ? true : cgChangedInSCC); + } + break; + } + case OP_throw: { + ThrowMeStmt *throwStmt = static_cast(&stmt); + std::vector nodes; + GetCGNodeForMeExpr(nodes, *throwStmt->GetOpnd(), stmt, true); + for (const auto &node : nodes) { + for (const auto &objNode : node->GetPointsToSet()) { + if (objNode->GetEAStatus() != kGlobalEscape) { + objNode->UpdateEAStatus(kGlobalEscape); + cgChangedInSCC = true; + } + } + } + break; + } + case OP_return: { + RetMeStmt *retMeStmt = static_cast(&stmt); + EACGActualNode *retNode = eaCG->GetReturnNode(); + MIRFunction *mirFunc = func->GetMirFunc(); + if (!IsTypeRefOrPtr(mirFunc->GetReturnType()->GetPrimType())) { + break; + } + if (retNode == nullptr && retMeStmt->GetOpnds().size() > 0) { + retNode = eaCG->CreateActualNode(kReturnEscape, true, true, + static_cast(mirFunc->GetFormalCount()), kInvalid); + cgChangedInSCC = true; + } + for (const auto &expr : retMeStmt->GetOpnds()) { + if (!IsExprRefOrPtr(*expr)) { + continue; + } + if (expr->GetMeOp() != kMeOpVar && expr->GetMeOp() != kMeOpReg) { + CHECK_FATAL(false, "should be"); + } + EACGRefNode *refNode = GetOrCreateCGRefNodeForVarOrReg(*expr, true); + cgChangedInSCC = (retNode->AddOutNode(*refNode) ? true : cgChangedInSCC); + } + break; + } + case OP_icall: + case OP_customcall: + case OP_polymorphiccall: + case OP_virtualcall: + case OP_virtualicall: + case OP_superclasscall: + case OP_interfacecall: + case OP_interfaceicall: + case OP_xintrinsiccall: + case OP_icallassigned: + case OP_customcallassigned: + case OP_polymorphiccallassigned: + case OP_xintrinsiccallassigned: { + CHECK_FATAL(false, "NYI"); + break; + } + case OP_intrinsiccall: { + IntrinsiccallMeStmt *intrn = static_cast(&stmt); + if (intrn->GetIntrinsic() != INTRN_MPL_CLEANUP_LOCALREFVARS && + intrn->GetIntrinsic() != INTRN_MPL_CLEANUP_LOCALREFVARS_SKIP && + intrn->GetIntrinsic() != INTRN_MCCSetPermanent && + intrn->GetIntrinsic() != INTRN_MCCIncRef && + intrn->GetIntrinsic() != INTRN_MCCDecRef && + intrn->GetIntrinsic() != INTRN_MCCIncDecRef && + intrn->GetIntrinsic() != INTRN_MCCDecRefReset && + intrn->GetIntrinsic() != INTRN_MCCIncDecRefReset && + intrn->GetIntrinsic() != INTRN_MCCWrite && + intrn->GetIntrinsic() != INTRN_MCCWriteNoDec && + intrn->GetIntrinsic() != INTRN_MCCWriteNoInc && + intrn->GetIntrinsic() != INTRN_MCCWriteNoRC && + intrn->GetIntrinsic() != INTRN_MCCWriteReferent && + intrn->GetIntrinsic() != INTRN_MCCWriteS && + intrn->GetIntrinsic() != INTRN_MCCWriteSNoInc && + intrn->GetIntrinsic() != INTRN_MCCWriteSNoDec && + intrn->GetIntrinsic() != INTRN_MCCWriteSNoRC && + intrn->GetIntrinsic() != INTRN_MCCWriteSVol && + intrn->GetIntrinsic() != INTRN_MCCWriteSVolNoInc && + intrn->GetIntrinsic() != INTRN_MCCWriteSVolNoDec && + intrn->GetIntrinsic() != INTRN_MCCWriteSVolNoRC && + intrn->GetIntrinsic() != INTRN_MCCWriteVol && + intrn->GetIntrinsic() != INTRN_MCCWriteVolNoInc && + intrn->GetIntrinsic() != INTRN_MCCWriteVolNoDec && + intrn->GetIntrinsic() != INTRN_MCCWriteVolNoRC && + intrn->GetIntrinsic() != INTRN_MCCWriteVolWeak && + intrn->GetIntrinsic() != INTRN_MCCWriteWeak && + intrn->GetIntrinsic() != INTRN_MCCDecRefResetPair) { + CHECK_FATAL(false, "intrnId: %d in function: %s", intrn->GetIntrinsic(), func->GetName().c_str()); + } + + if (intrn->GetIntrinsic() == INTRN_MPL_CLEANUP_LOCALREFVARS || + intrn->GetIntrinsic() == INTRN_MPL_CLEANUP_LOCALREFVARS_SKIP || + intrn->GetIntrinsic() == INTRN_MCCSetPermanent || + intrn->GetIntrinsic() == INTRN_MCCIncRef || + intrn->GetIntrinsic() == INTRN_MCCDecRef || + intrn->GetIntrinsic() == INTRN_MCCIncDecRef || + intrn->GetIntrinsic() == INTRN_MCCDecRefReset || + intrn->GetIntrinsic() == INTRN_MCCIncDecRefReset || + intrn->GetIntrinsic() == INTRN_MCCWriteReferent || + intrn->GetIntrinsic() == INTRN_MCCDecRefResetPair) { + break; + } + + CHECK_FATAL(intrn->GetOpnds().size() > 1, "must be"); + const size_t opndIdx = 2; + MeExpr *lhs = intrn->GetOpnd(intrn->NumMeStmtOpnds() - opndIdx); + MeExpr *rhs = intrn->GetOpnds().back(); + std::vector lhsNodes; + GetCGNodeForMeExpr(lhsNodes, *lhs, stmt, false); + std::vector rhsNodes; + GetCGNodeForMeExpr(rhsNodes, *rhs, stmt, true); + for (auto lhsNode : lhsNodes) { + for (auto rhsNode : rhsNodes) { + lhsNode->AddOutNode(*rhsNode); + } + } + break; + } + case OP_call: + case OP_callassigned: + case OP_superclasscallassigned: + case OP_interfaceicallassigned: + case OP_interfacecallassigned: + case OP_virtualicallassigned: + case OP_virtualcallassigned: { + CallMeStmt *callMeStmt = static_cast(&stmt); + MIRFunction &mirFunc = callMeStmt->GetTargetFunction(); + uint32 callInfo = callMeStmt->GetStmtID(); + if (callInfo == 0) { + if (mirFunc.GetName() != "MCC_SetObjectPermanent" && mirFunc.GetName() != "MCC_DecRef_NaiveRCFast") { + CHECK_FATAL(false, "funcName: %s", mirFunc.GetName().c_str()); + } + break; + } + eaCG->TouchCallSite(callInfo); + + // If a function has no reference parameter or return value, then skip it. + if (IsNoSideEffect(*callMeStmt)) { + HandleParaAtCallSite(callInfo, *callMeStmt); + break; + } + + HandleParaAtCallSite(callInfo, *callMeStmt); + if (stmt.GetOp() == OP_call || stmt.GetOp() == OP_callassigned || stmt.GetOp() == OP_superclasscallassigned) { + if (IPAEscapeAnalysis::kDebug) { + LogInfo::MapleLogger() << "[INVOKE] call func " << mirFunc.GetName() << "\n"; + } + HandleSingleCallee(*callMeStmt); + } else { + if (IPAEscapeAnalysis::kDebug) { + LogInfo::MapleLogger() << "[INVOKE] vcall func " << mirFunc.GetName() << "\n"; + } + HandleMultiCallees(*callMeStmt); + } + break; + } + // mainly for JAVA_CLINIT_CHECK + case OP_intrinsiccallwithtype: { + IntrinsiccallMeStmt *intrnMestmt = static_cast(&stmt); + if (intrnMestmt->GetIntrinsic() != INTRN_JAVA_CLINIT_CHECK && + intrnMestmt->GetIntrinsic() != INTRN_JAVA_CHECK_CAST) { + CHECK_FATAL(false, "intrnId: %d in function: %s", intrnMestmt->GetIntrinsic(), func->GetName().c_str()); + } + // 1. INTRN_JAVA_CLINIT_CHECK: Because all the operations in clinit are to initialize the static field + // of the Class, this will not affect the escape status of any reference or object node. + // 2. INTRN_JAVA_CHECK_CAST: When mephase precheckcast is enabled, this will happen, we only hava to solve + // the next dassign stmt. + break; + } + // mainly for JAVA_ARRAY_FILL and JAVA_POLYMORPHIC_CALL + case OP_intrinsiccallassigned: { + IntrinsiccallMeStmt *intrnMestmt = static_cast(&stmt); + if (intrnMestmt->GetIntrinsic() == INTRN_JAVA_POLYMORPHIC_CALL) { + // this intrinsiccall is MethodHandle.invoke, it is a native method. + const MapleVector &opnds = intrnMestmt->GetOpnds(); + const size_t size = opnds.size(); + for (size_t i = 0; i < size; ++i) { + MeExpr *var = opnds[i]; + // we only solve reference node. + if (!IsExprRefOrPtr(*var)) { + continue; + } + std::vector nodes; + GetCGNodeForMeExpr(nodes, *var, *intrnMestmt, true); + for (auto realArgNode : nodes) { + for (EACGObjectNode *obj : realArgNode->GetPointsToSet()) { + obj->UpdateEAStatus(kGlobalEscape); + } + } + } + CHECK_FATAL(intrnMestmt->GetMustDefList()->size() <= 1, "Impossible"); + if (intrnMestmt->GetMustDefList()->size() == 0) { + break; + } + if (intrnMestmt->GetMustDefListItem(0).GetLHS()->GetMeOp() != kMeOpVar && + intrnMestmt->GetMustDefListItem(0).GetLHS()->GetMeOp() != kMeOpReg) { + CHECK_FATAL(false, "impossible"); + } + if (!IsExprRefOrPtr(*intrnMestmt->GetMustDefListItem(0).GetLHS())) { + break; + } + EACGRefNode *realRetNode = GetOrCreateCGRefNodeForVarOrReg(*intrnMestmt->GetMustDefListItem(0).GetLHS(), true); + for (EACGObjectNode *obj : realRetNode->GetPointsToSet()) { + obj->UpdateEAStatus(kGlobalEscape); + } + break; + } else if (intrnMestmt->GetIntrinsic() == INTRN_JAVA_ARRAY_FILL) { + // JAVA_ARRAY_FILL can be skipped. + break; + } else { + if (intrnMestmt->GetIntrinsic() != INTRN_MCCIncRef && + intrnMestmt->GetIntrinsic() != INTRN_MCCLoadRef && + intrnMestmt->GetIntrinsic() != INTRN_MCCLoadRefS && + intrnMestmt->GetIntrinsic() != INTRN_MCCLoadRefSVol && + intrnMestmt->GetIntrinsic() != INTRN_MCCLoadRefVol && + intrnMestmt->GetIntrinsic() != INTRN_MCCLoadWeak && + intrnMestmt->GetIntrinsic() != INTRN_MCCLoadWeakVol) { + CHECK_FATAL(false, "intrnId: %d in function: %s", intrnMestmt->GetIntrinsic(), func->GetName().c_str()); + } + + CHECK_FATAL(intrnMestmt->GetMustDefList()->size() == 1, "Impossible"); + if (intrnMestmt->GetMustDefListItem(0).GetLHS()->GetMeOp() != kMeOpVar && + intrnMestmt->GetMustDefListItem(0).GetLHS()->GetMeOp() != kMeOpReg) { + CHECK_FATAL(false, "impossible"); + } + + if (!IsExprRefOrPtr(*intrnMestmt->GetMustDefListItem(0).GetLHS())) { + break; + } + EACGRefNode *retNode = GetOrCreateCGRefNodeForVarOrReg(*intrnMestmt->GetMustDefListItem(0).GetLHS(), false); + MeExpr *rhs = intrnMestmt->GetOpnds().back(); + std::vector rhsNodes; + GetCGNodeForMeExpr(rhsNodes, *rhs, stmt, true); + for (auto rhsNode : rhsNodes) { + retNode->AddOutNode(*rhsNode); + } + break; + } + } + // mainly for JAVA_CHECK_CAST and JAVA_FILL_NEW_ARRAY + case OP_intrinsiccallwithtypeassigned: { + IntrinsiccallMeStmt *intrnMestmt = static_cast(&stmt); + if (intrnMestmt->GetIntrinsic() == INTRN_JAVA_CHECK_CAST) { + // We regard this as dassign + CHECK_FATAL(intrnMestmt->GetMustDefList()->size() <= 1, "Impossible"); + if (intrnMestmt->GetMustDefList()->size() == 0) { + break; + } + CHECK_FATAL(intrnMestmt->GetMustDefListItem(0).GetLHS()->GetMeOp() == kMeOpVar, "must be kMeOpVar"); + VarMeExpr *lhs = static_cast(intrnMestmt->GetMustDefListItem(0).GetLHS()); + if (!IsExprRefOrPtr(*lhs)) { + break; + } + CHECK_FATAL(intrnMestmt->GetOpnds().size() == 1, "Impossible"); + CHECK_FATAL(intrnMestmt->GetOpnd(0)->GetMeOp() == kMeOpVar, "must be kMeOpVar"); + VarMeExpr *rhs = static_cast(intrnMestmt->GetOpnd(0)); + CHECK_FATAL(IsExprRefOrPtr(*rhs), "type mis-match"); + EACGRefNode *lhsNode = GetOrCreateCGRefNodeForVar(*lhs, false); + EACGRefNode *rhsNode = GetOrCreateCGRefNodeForVar(*rhs, true); + lhsNode->AddOutNode(*rhsNode); + } else if (intrnMestmt->GetIntrinsic() == INTRN_JAVA_FILL_NEW_ARRAY) { + CHECK_FATAL(intrnMestmt->GetMustDefList()->size() == 1, "Impossible"); + CHECK_FATAL(intrnMestmt->GetMustDefListItem(0).GetLHS()->GetMeOp() == kMeOpVar, "must be kMeOpVar"); + VarMeExpr *lhs = static_cast(intrnMestmt->GetMustDefListItem(0).GetLHS()); + if (!IsExprRefOrPtr(*lhs)) { + break; + } + EACGRefNode *lhsNode = GetOrCreateCGRefNodeForVar(*lhs, true); + CHECK_FATAL(intrnMestmt->GetOpnds().size() >= 1, "Impossible"); + for (MeExpr *expr : intrnMestmt->GetOpnds()) { + CHECK_FATAL(expr->GetMeOp() == kMeOpVar, "Impossible"); + VarMeExpr *rhs = static_cast(expr); + if (!IsExprRefOrPtr(*rhs)) { + continue; + } + EACGRefNode *rhsNode = GetOrCreateCGRefNodeForVar(*rhs, true); + for (const auto &objNode : lhsNode->GetPointsToSet()) { + // for array case, only one field node represents all elements + EACGFieldNode *fieldNode = objNode->GetFieldNodeFromIdx(0); + if (fieldNode == nullptr) { + fieldNode = eaCG->CreateFieldNode(nullptr, objNode->GetEAStatus(), 0, objNode, true); + } + fieldNode->AddOutNode(*rhsNode); + } + } + } else { + CHECK_FATAL(false, "intrnId: %d in function: %s", intrnMestmt->GetIntrinsic(), func->GetName().c_str()); + } + break; + } + + default: + break; + } +} + +EAConnectionGraph *IPAEscapeAnalysis::GetEAConnectionGraph(MIRFunction &function) const { + if (function.GetEACG() != nullptr) { + return function.GetEACG(); + } + const std::map &summaryMap = mirModule->GetEASummary(); + GStrIdx nameStrIdx = function.GetNameStrIdx(); + auto it = summaryMap.find(nameStrIdx); + if (it != summaryMap.end() && it->second != nullptr) { + return it->second; + } + return nullptr; +} + +void IPAEscapeAnalysis::HandleParaAtCallSite(uint32 callInfo, CallMeStmt &call) { + MapleVector *argVector = eaCG->GetCallSiteArgNodeVector(callInfo); + if (argVector != nullptr && argVector->size() > 0) { + // We have handled this callsite before, skip it. + return; + } + const MapleVector &opnds = call.GetOpnds(); + const uint32 size = opnds.size(); + + bool isOptIcall = (call.GetOp() == OP_interfaceicallassigned || call.GetOp() == OP_virtualicallassigned); + uint32 firstParmIdx = (isOptIcall ? 1 : 0); + + for (uint32 i = firstParmIdx; i < size; ++i) { + MeExpr *var = opnds[i]; + // we only solve reference node. + if (!IsExprRefOrPtr(*var) || var->GetOp() == OP_add) { + continue; + } + // for func(u, v), we assume that there exists assignment: a1 = u; a2 = v; + // a1, a2 are phantomArgNode and u, v are realArgNode, we add edge from a1 to u, etc. + EACGActualNode *phantomArgNode = + eaCG->CreateActualNode(kNoEscape, false, true, static_cast(i), callInfo); + // node for u, v. + std::vector nodes; + GetCGNodeForMeExpr(nodes, *var, call, true); + for (auto realArgNode : nodes) { + phantomArgNode->AddOutNode(*realArgNode); + } + } + // Non-nullptr means it has return value + CHECK_FATAL(call.GetMustDefList() != nullptr, "Impossible"); + if (call.GetMustDefList()->size() == 1) { + if (call.GetMustDefListItem(0).GetLHS()->GetMeOp() != kMeOpVar && + call.GetMustDefListItem(0).GetLHS()->GetMeOp() != kMeOpReg) { + CHECK_FATAL(false, "NYI"); + } + if (!IsExprRefOrPtr(*call.GetMustDefListItem(0).GetLHS())) { + return; + } + // for x = func(u, v), we assume that there exists assignment: r = x; + // r is a phantom return node, and x is the real return node, we add edge from r to x. + EACGActualNode *phantomRetNode = + eaCG->CreateActualNode(kNoEscape, true, true, static_cast(size), callInfo); + // node for x + EACGRefNode *realRetNode = GetOrCreateCGRefNodeForVarOrReg(*call.GetMustDefListItem(0).GetLHS(), true); + phantomRetNode->AddOutNode(*realRetNode); + } +} + +void IPAEscapeAnalysis::HandleSingleCallee(CallMeStmt &callMeStmt) { + uint32 callInfoId = callMeStmt.GetStmtID(); + MIRFunction &calleeCandidate = callMeStmt.GetTargetFunction(); + if (IPAEscapeAnalysis::kDebug) { + LogInfo::MapleLogger() << "[MERGECG] ready to merge func " << calleeCandidate.GetName() << "\n"; + } + if (calleeCandidate.IsAbstract()) { + CHECK_FATAL(false, "Impossible"); + if (IPAEscapeAnalysis::kDebug) { + LogInfo::MapleLogger() << "[MERGECG] skip to merge func because it is abstract." << "\n"; + } + return; + } + + EAConnectionGraph *calleeSummary = GetEAConnectionGraph(calleeCandidate); + + if (!mirModule->IsInIPA()) { + // This phase is in maplecomb, we need handle single callee differently + if (calleeSummary == nullptr) { + if (!calleeCandidate.IsNative() && !calleeCandidate.IsEmpty()) { + CHECK_FATAL(false, "Impossible"); + } + bool changedAfterMerge = eaCG->MergeCG(*eaCG->GetCallSiteArgNodeVector(callInfoId), nullptr); + if (changedAfterMerge) { + cgChangedInSCC = true; + } + } else { + MapleVector *caller = eaCG->GetCallSiteArgNodeVector(callInfoId); + const MapleVector *callee = calleeSummary->GetFuncArgNodeVector(); + bool changedAfterMerge = eaCG->MergeCG(*caller, callee); + if (changedAfterMerge) { + cgChangedInSCC = true; + } + } + return; + } + + CGNode *callerNode = pcg->GetCGNode(func->GetMirFunc()); + CHECK_FATAL(callerNode != nullptr, "Impossible, funcName: %s", func->GetName().c_str()); + CGNode *calleeNode = pcg->GetCGNode(&calleeCandidate); + CHECK_FATAL(calleeNode != nullptr, "Impossible, funcName: %s", calleeCandidate.GetName().c_str()); + if (calleeNode->GetSCCNode() == callerNode->GetSCCNode() && + (eaCG->GetNeedConservation() || + callerNode->GetSCCNode()->GetCGNodes().size() > IPAEscapeAnalysis::kFuncInSCCLimit)) { + bool changedAfterMerge = eaCG->MergeCG(*eaCG->GetCallSiteArgNodeVector(callInfoId), nullptr); + if (changedAfterMerge) { + cgChangedInSCC = true; + } + if (IPAEscapeAnalysis::kDebug) { + LogInfo::MapleLogger() << "[MERGECG] skip to merge func because NeedConservation." << "\n"; + } + return; + } + if (calleeSummary == nullptr && calleeCandidate.GetBody() != nullptr && !calleeCandidate.IsNative()) { + if (IPAEscapeAnalysis::kDebug) { + LogInfo::MapleLogger() << "[MERGECG] skip to merge func because this is first loop in scc." << "\n"; + } + return; + } + if (calleeSummary == nullptr) { + bool changedAfterMerge = eaCG->MergeCG(*eaCG->GetCallSiteArgNodeVector(callInfoId), nullptr); + if (changedAfterMerge) { + cgChangedInSCC = true; + } + } else { + MapleVector *caller = eaCG->GetCallSiteArgNodeVector(callInfoId); + const MapleVector *callee = calleeSummary->GetFuncArgNodeVector(); + bool changedAfterMerge = eaCG->MergeCG(*caller, callee); + if (changedAfterMerge) { + cgChangedInSCC = true; + } + } +} + +void IPAEscapeAnalysis::HandleMultiCallees(const CallMeStmt &callMeStmt) { + uint32 callInfoId = callMeStmt.GetStmtID(); + bool changedAfterMerge = eaCG->MergeCG(*eaCG->GetCallSiteArgNodeVector(callInfoId), nullptr); + if (changedAfterMerge) { + cgChangedInSCC = true; + } +} + +void IPAEscapeAnalysis::UpdateEscConnGraphWithPhi(const BB &bb) { + const MapleMap &mePhiList = bb.GetMePhiList(); + for (auto it = mePhiList.begin(); it != mePhiList.end(); ++it) { + MePhiNode *phiNode = it->second; + auto *lhs = phiNode->GetLHS(); + if (lhs->GetMeOp() != kMeOpVar) { + continue; + } + if (!IsExprRefOrPtr(*lhs) || phiNode->GetOpnds().empty() || + IsVirtualVar(*ssaTab, static_cast(*lhs))) { + continue; + } + EACGRefNode *lhsNode = GetOrCreateCGRefNodeForVar(static_cast(*lhs), false); + for (auto itt = phiNode->GetOpnds().begin(); itt != phiNode->GetOpnds().end(); ++itt) { + auto *var = static_cast(*itt); + EACGRefNode *rhsNode = GetOrCreateCGRefNodeForVar(*var, true); + cgChangedInSCC = (lhsNode->AddOutNode(*rhsNode) ? true : cgChangedInSCC); + } + } +} + +void IPAEscapeAnalysis::HandleParaAtFuncEntry() { + if (!mirModule->IsInIPA()) { + CHECK_FATAL(eaCG == nullptr, "Impossible"); + } + + if (eaCG != nullptr) { + return; + } + MIRFunction *mirFunc = func->GetMirFunc(); + eaCG = mirModule->GetMemPool()->New( + mirModule, &mirModule->GetMPAllocator(), mirFunc->GetNameStrIdx()); + eaCG->InitGlobalNode(); + OriginalStTable &ostTab = ssaTab->GetOriginalStTable(); + // create actual node for formal parameter + for (size_t i = 0; i < mirFunc->GetFormalCount(); ++i) { + MIRSymbol *mirSt = mirFunc->GetFormal(i); + OriginalSt *ost = ostTab.FindOrCreateSymbolOriginalSt(*mirSt, mirFunc->GetPuidx(), 0); + VarMeExpr *formal = irMap->GetOrCreateZeroVersionVarMeExpr(*ost); + if (IsExprRefOrPtr(*formal)) { + EACGActualNode *actualNode = + eaCG->CreateActualNode(kArgumentEscape, false, true, static_cast(i), kInvalid); + EACGObjectNode *objNode = eaCG->CreateObjectNode(nullptr, kNoEscape, true, kInitTyIdx); + actualNode->AddOutNode(*objNode); + EACGRefNode *formalNode = eaCG->CreateReferenceNode(formal, kNoEscape, false); + formalNode->AddOutNode(*actualNode); + } + } +} + +void IPAEscapeAnalysis::ConstructConnGraph() { + HandleParaAtFuncEntry(); + func->BuildSCC(); + const MapleVector &sccTopologicalVec = func->GetSccTopologicalVec(); + for (size_t i = 0; i < sccTopologicalVec.size(); ++i) { + SCCOfBBs *scc = sccTopologicalVec[i]; + CHECK_FATAL(scc != nullptr, "nullptr check"); + if (scc->GetBBs().size() > 1) { + func->BBTopologicalSort(*scc); + } + cgChangedInSCC = true; + bool analyzeAgain = true; + while (analyzeAgain) { + analyzeAgain = false; + cgChangedInSCC = false; + for (BB *bb : scc->GetBBs()) { + if (bb == func->GetCommonEntryBB() || bb == func->GetCommonExitBB()) { + continue; + } + UpdateEscConnGraphWithPhi(*bb); + for (MeStmt *stmt = to_ptr(bb->GetMeStmts().begin()); stmt != nullptr; stmt = stmt->GetNextMeStmt()) { + UpdateEscConnGraphWithStmt(*stmt); + } + } + if (scc->HasCycle() && cgChangedInSCC) { + analyzeAgain = true; + } + } + } + eaCG->PropogateEAStatus(); + func->GetMirFunc()->SetEACG(eaCG); +} + +void IPAEscapeAnalysis::DoOptimization() { + CountObjRCOperations(); + ProcessNoAndRetEscObj(); + ProcessRetStmt(); + DeleteRedundantRC(); +} + +VarMeExpr *IPAEscapeAnalysis::CreateEATempVarWithName(const std::string &name) { + const auto &strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name); + VarMeExpr *var = irMap->CreateNewVar(strIdx, PTY_ref, false); + return var; +} + +OriginalSt *IPAEscapeAnalysis::CreateEATempOst() { + std::string name = std::string("__EATemp__").append(std::to_string(++tempCount)); + return CreateEATempOstWithName(name); +} + +OriginalSt *IPAEscapeAnalysis::CreateEARetTempOst() { + std::string name = std::string("__EARetTemp__"); + return CreateEATempOstWithName(name); +} + +OriginalSt *IPAEscapeAnalysis::CreateEATempOstWithName(const std::string &name) { + MIRSymbol *symbol = func->GetMIRModule().GetMIRBuilder()->CreateLocalDecl(name, + *GlobalTables::GetTypeTable().GetRef()); + OriginalSt *ost = ssaTab->CreateSymbolOriginalSt(*symbol, func->GetMirFunc()->GetPuidx(), 0); + ost->SetZeroVersionIndex(irMap->GetVerst2MeExprTable().size()); + irMap->GetVerst2MeExprTable().push_back(nullptr); + ost->PushbackVersionsIndices(ost->GetZeroVersionIndex()); + return ost; +} + +VarMeExpr *IPAEscapeAnalysis::CreateEATempVarMeExpr(OriginalSt &ost) { + VarMeExpr *var = irMap->CreateVarMeExprVersion(&ost); + return var; +} + +VarMeExpr *IPAEscapeAnalysis::GetOrCreateEARetTempVarMeExpr(OriginalSt &ost) { + if (retVar != nullptr) { + return retVar; + } + retVar = CreateEATempVarMeExpr(ost); + return retVar; +} + +VarMeExpr *IPAEscapeAnalysis::CreateEATempVar() { + std::string name = std::string("__EATemp__").append(std::to_string(++tempCount)); + return CreateEATempVarWithName(name); +} + +VarMeExpr *IPAEscapeAnalysis::GetOrCreateEARetTempVar() { + if (retVar != nullptr) { + return retVar; + } + std::string name = std::string("__EARetTemp__"); + retVar = CreateEATempVarWithName(name); + return retVar; +} + +void IPAEscapeAnalysis::ProcessNoAndRetEscObj() { + for (BB *bb : func->GetAllBBs()) { + if (bb == func->GetCommonEntryBB() || bb == func->GetCommonExitBB() || bb == nullptr || + bb->GetAttributes(kBBAttrIsInLoopForEA)) { + continue; + } + + for (MeStmt *stmt = to_ptr(bb->GetMeStmts().begin()); stmt != nullptr; stmt = stmt->GetNextMeStmt()) { + if (stmt->GetOp() == OP_dassign || stmt->GetOp() == OP_regassign || stmt->GetOp() == OP_iassign || + stmt->GetOp() == OP_maydassign) { + MeExpr *rhs = stmt->GetRHS(); + CHECK_FATAL(rhs != nullptr, "nullptr check"); + if (!rhs->IsGcmalloc()) { + continue; + } + CHECK_FATAL(func->GetMirFunc()->GetEACG() != nullptr, "Impossible"); + EACGBaseNode *node = func->GetMirFunc()->GetEACG()->GetCGNodeFromExpr(rhs); + CHECK_FATAL(node != nullptr, "nullptr check"); + CHECK_FATAL(node->IsObjectNode(), "impossible"); + EAStatus eaStatus = node->GetEAStatus(); + if ((eaStatus == kNoEscape) && (!static_cast(node)->IsPointedByFieldNode()) && + (static_cast(node)->GetRCOperations() >= kRCOperLB)) { + static_cast(node)->SetIgnorRC(true); + gcStmts.push_back(stmt); + OriginalSt *ost = CreateEATempOst(); + noAndRetEscOst.push_back(ost); + } + } + } + } + if (noAndRetEscOst.size() == 0) { + return; + } + BB *firstBB = func->GetFirstBB(); + CHECK_FATAL(firstBB != nullptr, "Impossible"); + for (size_t i = 0; i < noAndRetEscOst.size(); ++i) { + OriginalSt *ost = noAndRetEscOst[i]; + MeStmt *stmt = gcStmts.at(i); + BB *curBB = stmt->GetBB(); + VarMeExpr *initVar = CreateEATempVarMeExpr(*ost); + MeExpr *zeroExpr = irMap->CreateIntConstMeExpr(0, PTY_ref); + DassignMeStmt *initStmt = irMap->CreateDassignMeStmt(*initVar, *zeroExpr, *firstBB); + firstBB->AddMeStmtFirst(initStmt); + + VarMeExpr *var = CreateEATempVarMeExpr(*ost); + noAndRetEscObj.push_back(var); + MeExpr *lhs = stmt->GetLHS(); + CHECK_FATAL(lhs != nullptr, "nullptr check"); + DassignMeStmt *newStmt = irMap->CreateDassignMeStmt(*var, *lhs, *curBB); + curBB->InsertMeStmtAfter(stmt, newStmt); + IntrinsiccallMeStmt *meStmt = irMap->NewInPool(OP_intrinsiccall, INTRN_MCCSetObjectPermanent); + meStmt->PushBackOpnd(var); + curBB->InsertMeStmtAfter(newStmt, meStmt); + } +} + +void IPAEscapeAnalysis::ProcessRetStmt() { + if (noAndRetEscObj.size() == 0) { + return; + } + + BB *firstBB = func->GetFirstBB(); + OriginalSt *ost = CreateEARetTempOst(); + VarMeExpr *initVar = CreateEATempVarMeExpr(*ost); + MeExpr *zeroExpr = irMap->CreateIntConstMeExpr(0, PTY_ref); + DassignMeStmt *newStmt = irMap->CreateDassignMeStmt(*initVar, *zeroExpr, *firstBB); + firstBB->AddMeStmtFirst(newStmt); + + for (BB *bb : func->GetAllBBs()) { + if (bb == func->GetCommonEntryBB() || bb == func->GetCommonExitBB() || bb == nullptr) { + continue; + } + for (MeStmt *stmt = to_ptr(bb->GetMeStmts().begin()); stmt != nullptr; stmt = stmt->GetNextMeStmt()) { + if (stmt->GetOp() == OP_return) { + RetMeStmt *retMeStmt = static_cast(stmt); + CHECK_FATAL(retMeStmt->GetOpnds().size() <= 1, "must less than one"); + VarMeExpr *var = GetOrCreateEARetTempVarMeExpr(*ost); + for (const auto &expr : retMeStmt->GetOpnds()) { + if (IsExprRefOrPtr(*expr)) { + DassignMeStmt *newStmtTmp = irMap->CreateDassignMeStmt(*var, *expr, *bb); + bb->InsertMeStmtBefore(stmt, newStmtTmp); + } + } + IntrinsiccallMeStmt *meStmt = irMap->NewInPool( + OP_intrinsiccall, INTRN_MPL_CLEANUP_NORETESCOBJS); + meStmt->PushBackOpnd(var); + for (auto opnd : noAndRetEscObj) { + meStmt->PushBackOpnd(opnd); + } + bb->InsertMeStmtBefore(stmt, meStmt); + } + } + } +} + +void IPAEscapeAnalysis::CountObjRCOperations() { + for (BB *bb : func->GetAllBBs()) { + if (bb == func->GetCommonEntryBB() || bb == func->GetCommonExitBB() || bb == nullptr) { + continue; + } + for (MeStmt *stmt = to_ptr(bb->GetMeStmts().begin()); stmt != nullptr; stmt = stmt->GetNextMeStmt()) { + switch (stmt->GetOp()) { + case OP_intrinsiccall: { + IntrinsiccallMeStmt *intrn = static_cast(stmt); + switch (intrn->GetIntrinsic()) { + case INTRN_MCCIncRef: + case INTRN_MCCIncDecRef: + case INTRN_MCCIncDecRefReset: { + CHECK_FATAL(eaCG->GetCGNodeFromExpr(intrn->GetOpnd(0)) != nullptr, "nullptr check"); + std::vector nodes; + GetCGNodeForMeExpr(nodes, *intrn->GetOpnd(0), *intrn, false); + for (auto refNode : nodes) { + for (auto objNode : refNode->GetPointsToSet()) { + objNode->IncresRCOperations(); + } + } + break; + } + case INTRN_MCCWrite: + case INTRN_MCCWriteNoDec: + case INTRN_MCCWriteS: + case INTRN_MCCWriteSNoDec: + case INTRN_MCCWriteSVol: + case INTRN_MCCWriteSVolNoDec: + case INTRN_MCCWriteVol: + case INTRN_MCCWriteVolNoDec: + case INTRN_MCCWriteVolWeak: + case INTRN_MCCWriteWeak: { + CHECK_FATAL(eaCG->GetCGNodeFromExpr(intrn->GetOpnds().back()) != nullptr, "nullptr check"); + std::vector nodes; + GetCGNodeForMeExpr(nodes, *intrn->GetOpnds().back(), *intrn, false); + for (auto refNode : nodes) { + for (auto objNode : refNode->GetPointsToSet()) { + objNode->IncresRCOperations(); + } + } + break; + } + default: + break; + } + break; + } + case OP_intrinsiccallassigned: { + IntrinsiccallMeStmt *intrn = static_cast(stmt); + switch (intrn->GetIntrinsic()) { + case INTRN_MCCIncRef: + case INTRN_MCCLoadRef: + case INTRN_MCCLoadRefS: + case INTRN_MCCLoadRefSVol: + case INTRN_MCCLoadRefVol: + case INTRN_MCCLoadWeak: + case INTRN_MCCLoadWeakVol: { + CHECK_FATAL(intrn->GetMustDefList()->size() == 1, "Impossible"); + if (intrn->GetMustDefListItem(0).GetLHS()->GetMeOp() != kMeOpVar && + intrn->GetMustDefListItem(0).GetLHS()->GetMeOp() != kMeOpReg) { + CHECK_FATAL(false, "must be kMeOpVar or kMeOpReg"); + } + + if (!IsExprRefOrPtr(*intrn->GetMustDefListItem(0).GetLHS())) { + break; + } + EACGBaseNode *refNode = eaCG->GetCGNodeFromExpr(intrn->GetMustDefListItem(0).GetLHS()); + CHECK_FATAL(refNode != nullptr, "nullptr check"); + for (auto objNode : refNode->GetPointsToSet()) { + objNode->IncresRCOperations(); + } + break; + } + default: + break; + } + break; + } + case OP_call: + case OP_callassigned: + case OP_superclasscallassigned: { + CallMeStmt *callMeStmt = static_cast(stmt); + + // If a function has no reference parameter or return value, then skip it. + if (IsNoSideEffect(*callMeStmt)) { + break; + } + MIRFunction &calleeCandidate = callMeStmt->GetTargetFunction(); + std::string fName = calleeCandidate.GetName(); + if (fName == "MCC_GetOrInsertLiteral" || + fName == "MCC_GetCurrentClassLoader" || + fName == "Native_Thread_currentThread" || + fName == "Native_java_lang_StringFactory_newStringFromBytes___3BIII" || + fName == "Native_java_lang_StringFactory_newStringFromChars__II_3C" || + fName == "Native_java_lang_StringFactory_newStringFromString__Ljava_lang_String_2" || + fName == "Native_java_lang_String_intern__" || + fName == "MCC_StringAppend" || + fName == "MCC_StringAppend_StringInt" || + fName == "MCC_StringAppend_StringJcharString" || + fName == "MCC_StringAppend_StringString") { + break; + } + const MapleVector &opnds = callMeStmt->GetOpnds(); + const size_t size = opnds.size(); + + bool isOptIcall = + (callMeStmt->GetOp() == OP_interfaceicallassigned || callMeStmt->GetOp() == OP_virtualicallassigned); + size_t firstParmIdx = (isOptIcall ? 1 : 0); + + bool isSpecialCall = false; + if (fName == "Native_java_lang_Object_clone_Ljava_lang_Object__" || + fName == "Native_java_lang_String_concat__Ljava_lang_String_2" || + fName == + "Ljava_2Flang_2FAbstractStringBuilder_3B_7CappendCLONEDignoreret_7C_28Ljava_2Flang_2FString_3B_29V" || + StartWith(fName, "Ljava_2Flang_2FAbstractStringBuilder_3B_7Cappend_7C") || + StartWith(fName, "Ljava_2Flang_2FStringBuilder_3B_7Cappend_7C")) { + CallMeStmt *call = static_cast(callMeStmt); + CHECK_FATAL(call->GetMustDefList() != nullptr, "funcName: %s", fName.c_str()); + CHECK_FATAL(call->GetMustDefList()->size() <= 1, "funcName: %s", fName.c_str()); + if (call->GetMustDefList() != nullptr && call->GetMustDefList()->size() == 0) { + break; + } + isSpecialCall = true; + } + + for (size_t i = firstParmIdx; i < size; ++i) { + MeExpr *var = opnds[i]; + // we only solve reference node. + if (!IsExprRefOrPtr(*var) || var->GetOp() == OP_add) { + continue; + } + CHECK_NULL_FATAL(eaCG->GetCGNodeFromExpr(var)); + std::vector nodes; + GetCGNodeForMeExpr(nodes, *var, *callMeStmt, false); + CHECK_FATAL(nodes.size() > 0, "the size must not be zero"); + for (EACGBaseNode *refNode : nodes) { + for (auto objNode : refNode->GetPointsToSet()) { + objNode->IncresRCOperations(); + } + } + if (isSpecialCall) { + break; + } + } + break; + } + case OP_intrinsiccallwithtypeassigned: { + CHECK_FATAL(false, "must not be OP_intrinsiccallwithtypeassigned"); + break; + } + default: + break; + } + } + } + + for (EACGBaseNode *node : eaCG->GetNodes()) { + if (node == nullptr || !node->IsObjectNode()) { + continue; + } + EACGObjectNode *obj = static_cast(node); + if (obj->IsPhantom()) { + continue; + } + if (obj->IsPointedByFieldNode()) { + obj->IncresRCOperations(kRCOperLB); + } + } +} + +void IPAEscapeAnalysis::DeleteRedundantRC() { + for (BB *bb : func->GetAllBBs()) { + if (bb == func->GetCommonEntryBB() || bb == func->GetCommonExitBB() || bb == nullptr) { + continue; + } + for (MeStmt *stmt = to_ptr(bb->GetMeStmts().begin()); stmt != nullptr; stmt = stmt->GetNextMeStmt()) { + if (stmt->GetOp() == OP_intrinsiccall) { + IntrinsiccallMeStmt *intrn = static_cast(stmt); + switch (intrn->GetIntrinsic()) { + case INTRN_MCCIncRef: + case INTRN_MCCDecRef: + case INTRN_MCCIncDecRef: { + bool canRemoveStmt = true; + for (auto expr : intrn->GetOpnds()) { + if (eaCG->GetCGNodeFromExpr(expr) == nullptr) { + canRemoveStmt = false; + break; + } + std::vector nodes; + GetCGNodeForMeExpr(nodes, *expr, *intrn, false); + for (auto node : nodes) { + if (!node->CanIgnoreRC()) { + canRemoveStmt = false; + break; + } + } + if (!canRemoveStmt) { + break; + } + } + if (canRemoveStmt) { + bb->RemoveMeStmt(stmt); + } + break; + } + case INTRN_MCCIncDecRefReset: + case INTRN_MCCDecRefReset: { + bool canRemoveStmt = true; + for (auto expr : intrn->GetOpnds()) { + if (expr->GetMeOp() != kMeOpAddrof) { + if (eaCG->GetCGNodeFromExpr(expr) == nullptr) { + canRemoveStmt = false; + break; + } + std::vector nodes; + GetCGNodeForMeExpr(nodes, *expr, *intrn, false); + for (auto node : nodes) { + if (!node->CanIgnoreRC()) { + canRemoveStmt = false; + break; + } + } + if (!canRemoveStmt) { + break; + } + } else { + AddrofMeExpr *addrof = static_cast(expr); + const OriginalSt *ost = ssaTab->GetOriginalStFromID(addrof->GetOstIdx()); + for (auto index : ost->GetVersionsIndices()) { + if (ost->IsFormal()) { + canRemoveStmt = false; + break; + } + if (index == ost->GetZeroVersionIndex()) { + continue; + } + MeExpr *var = irMap->GetMeExprByVerID(index); + if (var == nullptr) { + continue; + } + if (eaCG->GetCGNodeFromExpr(var) == nullptr) { + canRemoveStmt = false; + break; + } + std::vector nodes; + GetCGNodeForMeExpr(nodes, *var, *intrn, false); + for (auto node : nodes) { + if (!node->CanIgnoreRC()) { + canRemoveStmt = false; + break; + } + } + } + if (!canRemoveStmt) { + break; + } + } + } + if (canRemoveStmt) { + bb->RemoveMeStmt(stmt); + } + break; + } + default: + break; + } + } + } + } +} +} diff --git a/src/mapleall/maple_ipa/src/ipa_option.cpp b/src/mapleall/maple_ipa/src/ipa_option.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ada6efc5e28bd3d9046b0a9524cdbec8842b3f8a --- /dev/null +++ b/src/mapleall/maple_ipa/src/ipa_option.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "ipa_option.h" +#include "driver_option_common.h" +#include "mpl_logging.h" + +namespace maple { +using namespace mapleOption; +enum OptionIndex { + kIpaHelp = kCommonOptionEnd + 1, + kIpaOptL1, + kIpaOptL2, + kIpaEffectIPA, + kIpaInlineHint, + kIpaQuiet, +}; + +const Descriptor kUsage[] = { + { kIpaHelp, + 0, + "h", + "help", + kBuildTypeAll, + kArgCheckPolicyOptional, + " -h --help \tPrint usage and exit.Available command names:\n" + " \tmplipa\n", + "mplipa", + {} }, + { kIpaOptL1, + 0, + "", + "O1", + kBuildTypeAll, + kArgCheckPolicyNone, + " --O1 \tEnable basic inlining\n", + "mplipa", + {} }, + { kIpaOptL2, + 0, + "", + "O2", + kBuildTypeAll, + kArgCheckPolicyNone, + " --O2 \tEnable greedy inlining\n", + "mplipa", + {} }, + { kIpaEffectIPA, + 0, + "", + "effectipa", + kBuildTypeProduct, + kArgCheckPolicyNone, + " --effectipa \tEnable method side effect for ipa\n", + "mplipa", + {} }, + { kIpaInlineHint, + 0, + "", + "inlinefunclist", + kBuildTypeProduct, + kArgCheckPolicyNone, + " --inlinefunclist= \tInlining related configuration\n", + "mplipa", + {} }, + { kIpaQuiet, + 0, + "", + "quiet", + kBuildTypeProduct, + kArgCheckPolicyNone, + " --quiet \tDisable out debug info\n", + "mplipa", + {} }, + { kUnknown, + 0, + "", + "", + kBuildTypeAll, + kArgCheckPolicyNone, + "", + "mplipa", + {} } +}; + +IpaOption &IpaOption::GetInstance() { + static IpaOption instance; + return instance; +} + +IpaOption::IpaOption() { + CreateUsages(kUsage); +} + +bool PrintHelpAndExit(const OptionParser &optionParser) { + optionParser.PrintUsage("mplipa"); + return false; +} + +bool IpaOption::SolveOptions(const mapleOption::OptionParser &optionParser) const { + bool result = true; + for (const mapleOption::Option &opt : optionParser.GetOptions()) { + switch (opt.Index()) { + case kIpaHelp: { + if (opt.Args().empty()) { + result = PrintHelpAndExit(optionParser); + } + break; + } + case kIpaOptL1: + break; + case kIpaOptL2: + break; + case kIpaEffectIPA: + break; + case kIpaQuiet: + MeOption::quiet = true; + Options::quiet = true; + break; + case kIpaInlineHint: + MeOption::inlineFuncList = opt.Args(); + break; + default: + LogInfo::MapleLogger() << "unhandled case in ParseCmdline\n"; + result = false; + } + } + return result; +} + +bool IpaOption::ParseCmdline(int argc, char **argv, std::vector &fileNames) { + OptionParser optionParser; + optionParser.RegisteUsages(DriverOptionCommon::GetInstance()); + optionParser.RegisteUsages(IpaOption::GetInstance()); + int ret = optionParser.Parse(argc, argv, "mplipa"); + if (ret != kErrorNoError) { + return false; + } + bool result = SolveOptions(optionParser); + if (!result) { + return result; + } + for (std::string optionArg : optionParser.GetNonOptions()) { + fileNames.push_back(optionArg); + } + return true; +} +} // namespace maple + diff --git a/src/mapleall/maple_ipa/src/method_replace.cpp b/src/mapleall/maple_ipa/src/method_replace.cpp new file mode 100644 index 0000000000000000000000000000000000000000..836dd2f9e8317aef9f20ffcb8d233c325edced17 --- /dev/null +++ b/src/mapleall/maple_ipa/src/method_replace.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) [2019] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "method_replace.h" +#include + +// Replace some method with new method call, signature and return value not changed +// def format (caller origCallee newCallee). +namespace maple { +void MethodReplace::InsertRecord(const std::string &caller, const std::string &origCallee, + const std::string &newCallee) { + auto callerIt = replaceMethodMap.find(caller); + if (callerIt == replaceMethodMap.end()) { + replaceMethodMap[caller] = { { origCallee, newCallee } }; + return; + } + std::unordered_map &calleeMap = callerIt->second; + calleeMap[origCallee] = newCallee; +} + +void MethodReplace::Init() { +#define ORIFUNC(CALLER, ORIGINAL, NEWFUNC) InsertRecord(#CALLER, #ORIGINAL, #NEWFUNC); + +#include "tobe_replaced_funcs.def" + +#undef ORIFUNC +} + +void MethodReplace::FindCalleeAndReplace(MIRFunction &callerFunc, StrStrMap &calleeMap) const { + // iterate get callassignstmt to original callee, exclude virtual call interface call + StmtNode *stmt = callerFunc.GetBody()->GetFirst(); + while (stmt != nullptr) { + Opcode op = stmt->op; + if (op != OP_callassigned) { + stmt = stmt->GetNext(); + continue; + } + CallNode *callNode = static_cast(stmt); + MIRFunction *calleeFunc = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callNode->GetPUIdx()); + std::string calleeName = calleeFunc->GetName(); + auto it = calleeMap.find(calleeName); + if (it == calleeMap.end()) { + stmt = stmt->GetNext(); + continue; + } + std::string &newCalleeName = it->second; + MIRFunction *newCalleeFunc = mBuilder.GetOrCreateFunction(newCalleeName, TyIdx(PTY_void)); + callNode->SetPUIdx(newCalleeFunc->GetPuidx()); + stmt = stmt->GetNext(); + } +} + +// iterate callers in ReplaceMethod, find callee and replace +void MethodReplace::DoMethodReplace() { + for (auto it = replaceMethodMap.begin(); it != replaceMethodMap.end(); ++it) { + const std::string &callerName = it->first; + MIRSymbol *symbol = GlobalTables::GetGsymTable().GetSymbolFromStrIdx( + GlobalTables::GetStrTable().GetStrIdxFromName(callerName)); + if (symbol == nullptr || symbol->GetSKind() != kStFunc) { + continue; + } + MIRFunction *callerFunc = symbol->GetValue().mirFunc; + if (callerFunc == nullptr || callerFunc->GetBody() == nullptr) { + continue; + } + mirModule->SetCurFunction(callerFunc); + FindCalleeAndReplace(*callerFunc, it->second); + } +} + +AnalysisResult *DoMethodReplace::Run(MIRModule *module, ModuleResultMgr*) { + MemPool *mp = memPoolCtrler.NewMemPool(PhaseName()); + maple::MIRBuilder builder(module); + MethodReplace methodReplace(module, mp, builder); + methodReplace.Init(); + methodReplace.DoMethodReplace(); + memPoolCtrler.DeleteMemPool(mp); + return nullptr; +} +} // namespace maple + diff --git a/src/mapleall/maple_ipa/src/module_phase_manager.cpp b/src/mapleall/maple_ipa/src/module_phase_manager.cpp index 8aba38e7ff0ebdc1cda1cc39e9cdca99164df1a4..1875bbe94f7a5f29aabaaf83f31441371ec3bdc5 100644 --- a/src/mapleall/maple_ipa/src/module_phase_manager.cpp +++ b/src/mapleall/maple_ipa/src/module_phase_manager.cpp @@ -22,6 +22,8 @@ #include "call_graph.h" #include "verification.h" #include "verify_mark.h" +#include "inline.h" +#include "method_replace.h" #if MIR_JAVA #include "native_stub_func.h" #include "vtable_analysis.h" @@ -30,11 +32,11 @@ #include "vtable_impl.h" #include "java_intrn_lowering.h" #include "java_eh_lower.h" -#include "native_stub_func.h" #include "muid_replacement.h" #include "gen_check_cast.h" #include "coderelayout.h" #include "constantfold.h" +#include "barrierinsertion.h" #endif // ~MIR_JAVA namespace { diff --git a/src/mapleall/maple_ir/include/bin_mpl_export.h b/src/mapleall/maple_ir/include/bin_mpl_export.h index 8bddf675d6ea40cbe41313fba68b53968e69e184..36bbb967febcca9ee959301e3216a96959b0a23b 100644 --- a/src/mapleall/maple_ir/include/bin_mpl_export.h +++ b/src/mapleall/maple_ir/include/bin_mpl_export.h @@ -20,6 +20,8 @@ #include "mir_preg.h" #include "parser_opt.h" #include "module_phase.h" +#include "ea_connection_graph.h" +#include "call_graph.h" namespace maple { enum : uint8 { diff --git a/src/mapleall/maple_ir/include/bin_mpl_import.h b/src/mapleall/maple_ir/include/bin_mpl_import.h index dbee4494cfe5fed8cbc5b6719436dc79c941a6a1..43bb2fb77d5a8a19dc4e2ac8eac9d53c0479074a 100644 --- a/src/mapleall/maple_ir/include/bin_mpl_import.h +++ b/src/mapleall/maple_ir/include/bin_mpl_import.h @@ -19,6 +19,7 @@ #include "mir_preg.h" #include "parser_opt.h" #include "mir_builder.h" +#include "ea_connection_graph.h" namespace maple { class BinaryMplImport { public: @@ -69,6 +70,18 @@ class BinaryMplImport { void ReadContentField(); void ReadStrField(); void ReadTypeField(); + void ReadCgField(); + EAConnectionGraph *ReadEaCgField(); + void ReadEaField(); + EACGBaseNode &InEaCgNode(EAConnectionGraph &newEaCg); + void InEaCgBaseNode(EACGBaseNode &base, EAConnectionGraph &newEaCg, bool firstPart); + void InEaCgActNode(EACGActualNode &actual); + void InEaCgFieldNode(EACGFieldNode &field, EAConnectionGraph &newEaCg); + void InEaCgObjNode(EACGObjectNode &obj, EAConnectionGraph &newEaCg); + void InEaCgRefNode(EACGRefNode &ref); + CallInfo *ImportCallInfo(); + void MergeDuplicated(PUIdx methodPuidx, std::vector &targetSet, std::vector &newSet); + void ReadSeField(); void Jump2NextField(); void Reset(); void SkipTotalSize(); @@ -77,6 +90,7 @@ class BinaryMplImport { void InsertInHashTable(MIRType &ptype); void SetupEHRootType(); void UpdateMethodSymbols(); + void UpdateDebugInfo(); void ImportConstBase(MIRConstKind &kind, MIRTypePtr &type, uint32 &fieldID); MIRConst *ImportConst(MIRFunction *func); GStrIdx ImportStr(); @@ -111,6 +125,8 @@ class BinaryMplImport { void ReadAsciiStr(std::string &str); int32 GetIPAFileIndex(std::string &name); + bool inCG = false; + bool inIPA = false; bool imported = true; // used only by irbuild to convert to ascii uint64 bufI = 0; std::vector buf; @@ -125,6 +141,8 @@ class BinaryMplImport { std::vector typTab; std::vector funcTab; std::vector symTab; + std::vector callInfoTab; + std::vector eaCgTab; std::vector methodSymbols; std::map typeDefIdxMap; // map previous declared tyIdx std::vector definedLabels; diff --git a/src/mapleall/maple_ir/include/cmpl.h b/src/mapleall/maple_ir/include/cmpl.h index eb7f868d72fe48eeaaee5d555e494a73b9761f18..417dda0fcb9aba82d992618162a048fdda6b69e7 100644 --- a/src/mapleall/maple_ir/include/cmpl.h +++ b/src/mapleall/maple_ir/include/cmpl.h @@ -176,6 +176,29 @@ struct BaseNodeT { // 4B return numOpnds; } + uint8 GetNumOpnds() const { + return numOpnds; + } + void SetNumOpnds(uint8 num) { + numOpnds = num; + } + + Opcode GetOpCode() const { + return op; + } + + void SetOpCode(Opcode o) { + op = o; + } + + PrimType GetPrimType() const { + return ptyp; + } + + void SetPrimType(PrimType type) { + ptyp = type; + } + BaseNodeT() : op(OP_undef), ptyp(kPtyInvalid), typeFlag(0), numOpnds(0) {} virtual ~BaseNodeT() = default; diff --git a/src/mapleall/maple_ir/include/global_tables.h b/src/mapleall/maple_ir/include/global_tables.h index 5f0e19fdb946d7f68ace2b4dc6699f21012112a0..769b83389645ec01a2cfa0005d1ddbca3ee4d1cf 100644 --- a/src/mapleall/maple_ir/include/global_tables.h +++ b/src/mapleall/maple_ir/include/global_tables.h @@ -17,6 +17,9 @@ #include #include #include +#include +#include +#include "thread_env.h" #include "mempool.h" #include "mempool_allocator.h" #include "types_def.h" @@ -31,7 +34,7 @@ using TyIdxFieldAttrPair = std::pair; using FieldPair = std::pair; using FieldVector = std::vector; -class BinaryMplImport; +class BinaryMplImport; // circular dependency exists, no other choice // to facilitate the use of unordered_map class TyIdxHash { @@ -118,7 +121,6 @@ class TypeTable { } void SetTypeWithTyIdx(const TyIdx &tyIdx, MIRType &type); - MIRType *GetOrCreateMIRTypeNode(MIRType &ptype); TyIdx GetOrCreateMIRType(MIRType *pType) { @@ -341,6 +343,7 @@ class TypeTable { void PushIntoFieldVector(FieldVector &fields, const std::string &name, MIRType &type); void AddFieldToStructType(MIRStructType &structType, const std::string &fieldName, MIRType &fieldType); + TyIdx lastDefaultTyIdx; private: using MIRTypePtr = MIRType*; struct Hash { @@ -375,8 +378,7 @@ class TypeTable { std::unordered_map ptrTypeMap; std::unordered_map refTypeMap; std::vector typeTable; - public: - TyIdx lastDefaultTyIdx; + mutable std::shared_timed_mutex mtx; }; class StrPtrHash { @@ -424,6 +426,14 @@ class StringTable { } U GetStrIdxFromName(const T &str) const { + if (ThreadEnv::IsMeParallel()) { + std::shared_lock lock(mtx); + auto it = stringTableMap.find(&str); + if (it == stringTableMap.end()) { + return U(0); + } + return it->second; + } auto it = stringTableMap.find(&str); if (it == stringTableMap.end()) { return U(0); @@ -434,6 +444,14 @@ class StringTable { U GetOrCreateStrIdxFromName(const T &str) { U strIdx = GetStrIdxFromName(str); if (strIdx == 0u) { + if (ThreadEnv::IsMeParallel()) { + std::unique_lock lock(mtx); + strIdx.reset(stringTable.size()); + T *newStr = new T(str); + stringTable.push_back(newStr); + stringTableMap[newStr] = strIdx; + return strIdx; + } strIdx.reset(stringTable.size()); T *newStr = new T(str); stringTable.push_back(newStr); @@ -443,10 +461,19 @@ class StringTable { } size_t StringTableSize() const { + if (ThreadEnv::IsMeParallel()) { + std::shared_lock lock(mtx); + return stringTable.size(); + } return stringTable.size(); } const T &GetStringFromStrIdx(U strIdx) const { + if (ThreadEnv::IsMeParallel()) { + std::shared_lock lock(mtx); + ASSERT(strIdx < stringTable.size(), "array index out of range"); + return *stringTable[strIdx]; + } ASSERT(strIdx < stringTable.size(), "array index out of range"); return *stringTable[strIdx]; } @@ -454,6 +481,7 @@ class StringTable { private: std::vector stringTable; // index is uint32 std::unordered_map stringTableMap; + mutable std::shared_timed_mutex mtx; }; class FPConstTable { @@ -476,6 +504,10 @@ class FPConstTable { void PostInit(); MIRFloatConst *DoGetOrCreateFloatConst(float); MIRDoubleConst *DoGetOrCreateDoubleConst(double); + MIRFloatConst *DoGetOrCreateFloatConstThreadSafe(float); + MIRDoubleConst *DoGetOrCreateDoubleConstThreadSafe(double); + std::shared_timed_mutex floatMtx; + std::shared_timed_mutex doubleMtx; std::unordered_map floatConstTable; // map float const value to the table; std::unordered_map doubleConstTable; // map double const value to the table; MIRFloatConst *nanFloatConst = nullptr; @@ -504,6 +536,8 @@ class IntConstTable { private: IntConstTable() = default; MIRIntConst *DoGetOrCreateIntConst(int64 val, MIRType &type, uint32 fieldID); + MIRIntConst *DoGetOrCreateIntConstTreadSafe(int64 val, MIRType &type, uint32 fieldID); + std::shared_timed_mutex mtx; std::unordered_map intConstTable; }; diff --git a/src/mapleall/maple_ir/include/mir_builder.h b/src/mapleall/maple_ir/include/mir_builder.h index 6ad62502876c90a4bdb793614430b42ae04de19a..be6e53c06e1be2351c7251979f30d4cad3b8e474 100644 --- a/src/mapleall/maple_ir/include/mir_builder.h +++ b/src/mapleall/maple_ir/include/mir_builder.h @@ -286,6 +286,8 @@ class MIRBuilder { virtual MemPool *GetCurrentFuncCodeMp(); virtual MapleAllocator *GetCurrentFuncCodeMpAllocator(); + virtual void GlobalLock() {} + virtual void GlobalUnlock() {} private: MIRSymbol *GetOrCreateGlobalDecl(const std::string &str, TyIdx tyIdx, bool &created) const; @@ -303,5 +305,27 @@ class MIRBuilder { unsigned int lineNum = 0; }; +class MIRBuilderExt : public MIRBuilder { + public: + explicit MIRBuilderExt(MIRModule *module, pthread_mutex_t *mutex = nullptr); + virtual ~MIRBuilderExt() = default; + + void SetCurrentFunction(MIRFunction &func) override { + curFunction = &func; + } + + MIRFunction *GetCurrentFunction() const override { + return curFunction; + } + + MemPool *GetCurrentFuncCodeMp() override; + MapleAllocator *GetCurrentFuncCodeMpAllocator() override; + void GlobalLock() override; + void GlobalUnlock() override; + + private: + MIRFunction *curFunction = nullptr; + pthread_mutex_t *mutex = nullptr; +}; } // namespace maple #endif // MAPLE_IR_INCLUDE_MIR_BUILDER_H diff --git a/src/mapleall/maple_ir/include/mir_config.h b/src/mapleall/maple_ir/include/mir_config.h index 084a8dd1878e3a39eee8bde9b23fce3d34f34cc3..7e753473baf5325cecb344cf0f87bc2db2c0e35e 100644 --- a/src/mapleall/maple_ir/include/mir_config.h +++ b/src/mapleall/maple_ir/include/mir_config.h @@ -21,6 +21,23 @@ #if !defined(MIR_FEATURE_FULL) #define MIR_FEATURE_FULL 1 // default to full feature building, for debugging #endif // MIR_FEATURE_FULL define + +// MIR_DEBUG = 0 : for release building. +// MIR_DEBUG = 1 : for debug building. +#ifndef MIR_DEBUG +#define MIR_DEBUG 0 // currently default to none. turn it on explicitly +#endif // MIR_DEBUG + +// MIR_DEBUG_LEVEL = 0: no debuging information at all. +// 1: with error information. +// 2: with severe warning information +// 3: with normal warning information +// 4: with normal information +// 5: with everything +// +#ifndef MIR_DEBUG_LEVEL +#define MIR_DEBUG_LEVEL 0 +#endif // MIR_DEBUG_LEVEL // assertion #if !MIR_FEATURE_FULL #define MIR_ASSERT(...) \ @@ -81,10 +98,21 @@ namespace maple { #define MIR_INFO(...) printf(__VA_ARGS__) #define MIR_CAST_TO(var, totype) static_cast(var) #endif // !MIR_FEATURE_FULL +#if MIR_DEBUG +#else +#endif // MIR_DEBUG // MIR specific configurations. // Note: fix size definition cannot handle arbitary long MIR lines, such // as those array initialization lines. constexpr int kMirMaxLineSize = 3072; // a max of 3K characters per line initially +// LIBRARY API availability +#if MIR_FEATURE_FULL +#define HAVE_STRTOD 1 // strtod +#define HAVE_MALLOC 1 // malloc/free +#else // compact VM +#define HAVE_STRTOD 1 // strtod in current libc +#define HAVE_MALLOC 0 // no malloc/free in current libc +#endif // MIR_FEATURE_FULL } // namespace maple #endif // MAPLE_IR_INCLUDE_MIR_CONFIG_H diff --git a/src/mapleall/maple_ir/include/mir_lower.h b/src/mapleall/maple_ir/include/mir_lower.h index 666510d79862b12a0882c74d70d196508db4638e..2f90d5c4ac8aad7b887ffa73a1ee385bee5b462b 100644 --- a/src/mapleall/maple_ir/include/mir_lower.h +++ b/src/mapleall/maple_ir/include/mir_lower.h @@ -24,13 +24,15 @@ enum MirLowerPhase : uint8 { kLowerMe, kLowerExpandArray, kLowerBe, - kLowerCG + kLowerCG, + kLowerLNO }; constexpr uint32 kShiftLowerMe = 1U << kLowerMe; constexpr uint32 kShiftLowerExpandArray = 1U << kLowerExpandArray; constexpr uint32 kShiftLowerBe = 1U << kLowerBe; constexpr uint32 kShiftLowerCG = 1U << kLowerCG; +constexpr uint32 kShiftLowerLNO = 1U << kLowerLNO; // check if a block node ends with an unconditional jump inline bool OpCodeNoFallThrough(Opcode opCode) { return opCode == OP_goto || opCode == OP_return || opCode == OP_switch || opCode == OP_throw || opCode == OP_gosub || @@ -75,6 +77,10 @@ class MIRLower { lowerPhase |= kShiftLowerMe; } + void SetLowerLNO() { + lowerPhase |= kShiftLowerLNO; + } + void SetLowerExpandArray() { lowerPhase |= kShiftLowerExpandArray; } @@ -91,6 +97,10 @@ class MIRLower { return lowerPhase & kShiftLowerMe; } + bool IsLowerLNO() const { + return lowerPhase & kShiftLowerLNO; + } + bool IsLowerExpandArray() const { return lowerPhase & kShiftLowerExpandArray; } diff --git a/src/mapleall/maple_ir/include/mir_module.h b/src/mapleall/maple_ir/include/mir_module.h index 090e71455d360125a8d549ec0d2b491d27baa90a..093f9bb989de53687e39730b5b04e7a03138b5fc 100644 --- a/src/mapleall/maple_ir/include/mir_module.h +++ b/src/mapleall/maple_ir/include/mir_module.h @@ -25,6 +25,10 @@ #include #include #include +#include +#include +#include +#include "thread_env.h" #include "mempool.h" #include "mempool_allocator.h" #include "maple_string.h" @@ -56,6 +60,7 @@ enum MIRSrcLang { kSrcLangCPlusPlus, kSrcLangJava, kSrcLangJbc, + kSrcLangChar, // SrcLangSwift : when clang adds support for Swift. }; @@ -194,6 +199,12 @@ class MIRModule { void RemoveClass(TyIdx tyIdx); void SetCurFunction(MIRFunction *f) { + if (ThreadEnv::IsMeParallel()) { + std::lock_guard guard(curFunctionMutex); + auto tid = std::this_thread::get_id(); + curFunctionMap[tid] = f; + return; // DO NOT delete the return statement + } curFunction = f; } @@ -214,6 +225,12 @@ class MIRModule { } MIRFunction *CurFunction() const { + if (ThreadEnv::IsMeParallel()) { + std::lock_guard guard(curFunctionMutex); + auto tid = std::this_thread::get_id(); + auto pair = curFunctionMap.find(tid); + return pair->second; + } return curFunction; } @@ -236,6 +253,7 @@ class MIRModule { const std::string &GetFileNameFromFileNum(uint32 fileNum) const; void DumpToHeaderFile(bool binaryMplt, const std::string &outputName = ""); + void DumpToCxxHeaderFile(std::set &leafClasses, const std::string &pathToOutf) const; void DumpClassToFile(const std::string &path) const; void DumpFunctionList(bool skipBody = false) const; void DumpGlobalArraySymbol() const; @@ -274,7 +292,7 @@ class MIRModule { } bool IsCharModule() const { - return false; + return srcLang == kSrcLangChar; } void addSuperCall(const std::string &func) { @@ -285,6 +303,15 @@ class MIRModule { return superCallSet.find(func) != superCallSet.end(); } + void ReleaseCurFuncMemPoolTmp(); + void SetUseFuncCodeMemPoolTmp() { + useFuncCodeMemPoolTmp = true; + } + + void ResetUseFuncCodeMemPoolTmp() { + useFuncCodeMemPoolTmp = false; + } + void SetFuncInfoPrinted() const; size_t GetOptFuncsSize() const { return optimizedFuncs.size(); @@ -314,6 +341,13 @@ class MIRModule { return realCaller; } + const MapleSet &GetInlineGlobals() const { + return inliningGlobals; + } + void InsertInlineGlobal(uint32_t global) { + (void)inliningGlobals.insert(global); + } + const MapleSet *GetPUIdxFieldInitializedMapItem(PUIdx key) const { std::shared_lock lock(fieldMapMutex); auto it = puIdxFieldInitializedMap.find(key); @@ -503,6 +537,8 @@ class MIRModule { } private: + void DumpTypeTreeToCxxHeaderFile(MIRType &ty, std::unordered_set &dumpedClasses) const; + MemPool *memPool; MemPool *pragmaMemPool; MapleAllocator memPoolAllocator; @@ -558,8 +594,12 @@ class MIRModule { std::map> method2TargetHash; std::map eaSummary; + bool useFuncCodeMemPoolTmp = false; MIRFunction *entryFunc = nullptr; uint32 floatNum = 0; + // curFunction for single thread, curFunctionMap for multiple threads + std::map curFunctionMap; + mutable std::mutex curFunctionMutex; MIRFunction *curFunction; MapleVector optimizedFuncs; // Add the field for decouple optimization @@ -572,6 +612,7 @@ class MIRModule { MapleMap*> puIdxFieldInitializedMap; mutable std::shared_timed_mutex fieldMapMutex; std::map, GStrIdx> realCaller; + MapleSet inliningGlobals; // global symbols accessed, used for inlining }; #endif // MIR_FEATURE_FULL } // namespace maple diff --git a/src/mapleall/maple_ir/include/mir_symbol.h b/src/mapleall/maple_ir/include/mir_symbol.h index 9a7df9db5a5130b441fab28e37eca31fa8e95f74..cac9f5f996aa853f2d8a993a4c32bf10617aa059 100644 --- a/src/mapleall/maple_ir/include/mir_symbol.h +++ b/src/mapleall/maple_ir/include/mir_symbol.h @@ -531,6 +531,19 @@ class MIRSymbolTable { symbolTable.clear(); } + MIRSymbol *CloneLocalSymbol(const MIRSymbol &oldSym) const { + auto *memPool = mAllocator.GetMemPool(); + auto *newSym = memPool->New(oldSym); + if (oldSym.GetSKind() == kStConst) { + newSym->SetKonst(oldSym.GetKonst()->Clone(*memPool)); + } else if (oldSym.GetSKind() == kStPreg) { + newSym->SetPreg(memPool->New(*oldSym.GetPreg())); + } else if (oldSym.GetSKind() == kStFunc) { + CHECK_FATAL(false, "%s has unexpected local func symbol", oldSym.GetName().c_str()); + } + return newSym; + } + private: MapleAllocator mAllocator; // hash table mapping string index to st index diff --git a/src/mapleall/maple_ir/src/bin_mpl_import.cpp b/src/mapleall/maple_ir/src/bin_mpl_import.cpp index 1d84307d67f8b74feb455dd73528a9bec227f9a2..3efc116928f2bbabb8e7e29d97efb809ed602dd3 100644 --- a/src/mapleall/maple_ir/src/bin_mpl_import.cpp +++ b/src/mapleall/maple_ir/src/bin_mpl_import.cpp @@ -430,16 +430,20 @@ void BinaryMplImport::ImportClassTypeData(MIRClassType &type) { } ImportInterfacesOfClassType(type.GetInterfaceImplemented()); ImportInfoIsStringOfStructType(type); - ImportInfoOfStructType(type); - ImportPragmaOfStructType(type); + if (!inIPA) { + ImportInfoOfStructType(type); + ImportPragmaOfStructType(type); + } SetClassTyidxOfMethods(type); } void BinaryMplImport::ImportInterfaceTypeData(MIRInterfaceType &type) { ImportInterfacesOfClassType(type.GetParentsTyIdx()); ImportInfoIsStringOfStructType(type); - ImportInfoOfStructType(type); - ImportPragmaOfStructType(type); + if (!inIPA) { + ImportInfoOfStructType(type); + ImportPragmaOfStructType(type); + } SetClassTyidxOfMethods(type); } @@ -744,6 +748,10 @@ MIRType &BinaryMplImport::InsertInTypeTables(MIRType &type) { return *resultTypePtr; } +void BinaryMplImport::UpdateDebugInfo() { +} + + void BinaryMplImport::SetupEHRootType() { // setup eh root type with most recent Ljava_2Flang_2FObject_3B GStrIdx gStrIdx = GlobalTables::GetStrTable().GetStrIdxFromName(namemangler::kJavaLangObjectStr); diff --git a/src/mapleall/maple_ir/src/global_tables.cpp b/src/mapleall/maple_ir/src/global_tables.cpp index 5e66e8bf0c8951a0c160d798f14a1d450f606345..254cd7fd0cd761fc023b6156739d3a2daa5c6810 100644 --- a/src/mapleall/maple_ir/src/global_tables.cpp +++ b/src/mapleall/maple_ir/src/global_tables.cpp @@ -32,7 +32,7 @@ TypeTable::TypeTable() { typeTable.push_back(static_cast(nullptr)); ASSERT(typeTable.size() == static_cast(PTY_void), "use PTY_void as the first index to type table"); uint32 primTypeIdx; - for (primTypeIdx = static_cast(PTY_begin)+1; primTypeIdx <= static_cast(PTY_end); ++primTypeIdx) { + for (primTypeIdx = static_cast(PTY_begin) + 1; primTypeIdx <= static_cast(PTY_end); ++primTypeIdx) { MIRType *type = CreateMirType(primTypeIdx); type->SetTypeIndex(TyIdx{ primTypeIdx }); typeTable.push_back(type); @@ -94,11 +94,13 @@ MIRType* TypeTable::GetOrCreateMIRTypeNode(MIRType &pType) { auto *pMap = (type.GetPrimType() == PTY_ptr ? &ptrTypeMap : &refTypeMap); auto *otherPMap = (type.GetPrimType() == PTY_ref ? &ptrTypeMap : &refTypeMap); { + std::shared_lock lock(mtx); const auto it = pMap->find(type.GetPointedTyIdx()); if (it != pMap->end()) { return GetTypeFromTyIdx(it->second); } } + std::unique_lock lock(mtx); CHECK_FATAL(!(type.GetPointedTyIdx().GetIdx() >= kPtyDerived && type.GetPrimType() == PTY_ref && otherPMap->find(type.GetPointedTyIdx()) != otherPMap->end()), "GetOrCreateMIRType: ref pointed-to type %d has previous ptr occurrence", @@ -107,11 +109,13 @@ MIRType* TypeTable::GetOrCreateMIRTypeNode(MIRType &pType) { } } { + std::shared_lock lock(mtx); const auto it = typeHashTable.find(&pType); if (it != typeHashTable.end()) { return *it; } } + std::unique_lock lock(mtx); return CreateAndUpdateMirTypeNode(pType); } @@ -253,6 +257,9 @@ void FPConstTable::PostInit() { } MIRIntConst *IntConstTable::GetOrCreateIntConst(int64 val, MIRType &type, uint32 fieldID) { + if (ThreadEnv::IsMeParallel()) { + return DoGetOrCreateIntConstTreadSafe(val, type, fieldID); + } return DoGetOrCreateIntConst(val, type, fieldID); } @@ -266,6 +273,20 @@ MIRIntConst *IntConstTable::DoGetOrCreateIntConst(int64 val, MIRType &type, uint return intConstTable[key]; } +MIRIntConst *IntConstTable::DoGetOrCreateIntConstTreadSafe(int64 val, MIRType &type, uint32 fieldID) { + uint64 idid = static_cast(type.GetTypeIndex()) + (static_cast(fieldID) << 32); // shift bit is 32 + IntConstKey key(val, idid); + { + std::shared_lock lock(mtx); + if (intConstTable.find(key) != intConstTable.end()) { + return intConstTable[key]; + } + } + std::unique_lock lock(mtx); + intConstTable[key] = new MIRIntConst(val, type, fieldID); + return intConstTable[key]; +} + IntConstTable::~IntConstTable() { for (auto pair : intConstTable) { delete pair.second; @@ -282,6 +303,9 @@ MIRFloatConst *FPConstTable::GetOrCreateFloatConst(float floatVal) { if (floatVal == 0.0 && std::signbit(floatVal)) { return minusZeroFloatConst; } + if (ThreadEnv::IsMeParallel()) { + return DoGetOrCreateFloatConstThreadSafe(floatVal); + } return DoGetOrCreateFloatConst(floatVal); } @@ -296,6 +320,21 @@ MIRFloatConst *FPConstTable::DoGetOrCreateFloatConst(float floatVal) { return floatConst; } +MIRFloatConst *FPConstTable::DoGetOrCreateFloatConstThreadSafe(float floatVal) { + { + std::shared_lock lock(floatMtx); + const auto it = floatConstTable.find(floatVal); + if (it != floatConstTable.cend()) { + return it->second; + } + } + // create a new one + std::unique_lock lock(floatMtx); + auto *floatConst = new MIRFloatConst(floatVal, *GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx{ PTY_f32 })); + floatConstTable[floatVal] = floatConst; + return floatConst; +} + MIRDoubleConst *FPConstTable::GetOrCreateDoubleConst(double doubleVal) { if (std::isnan(doubleVal)) { return nanDoubleConst; @@ -306,6 +345,9 @@ MIRDoubleConst *FPConstTable::GetOrCreateDoubleConst(double doubleVal) { if (doubleVal == 0.0 && std::signbit(doubleVal)) { return minusZeroDoubleConst; } + if (ThreadEnv::IsMeParallel()) { + return DoGetOrCreateDoubleConstThreadSafe(doubleVal); + } return DoGetOrCreateDoubleConst(doubleVal); } @@ -321,6 +363,22 @@ MIRDoubleConst *FPConstTable::DoGetOrCreateDoubleConst(double doubleVal) { return doubleConst; } +MIRDoubleConst *FPConstTable::DoGetOrCreateDoubleConstThreadSafe(double doubleVal) { + { + std::shared_lock lock(doubleMtx); + const auto it = doubleConstTable.find(doubleVal); + if (it != doubleConstTable.cend()) { + return it->second; + } + } + // create a new one + std::unique_lock lock(doubleMtx); + auto *doubleConst = new MIRDoubleConst(doubleVal, + *GlobalTables::GetTypeTable().GetTypeFromTyIdx((TyIdx)PTY_f64)); + doubleConstTable[doubleVal] = doubleConst; + return doubleConst; +} + FPConstTable::~FPConstTable() { delete nanFloatConst; delete infFloatConst; diff --git a/src/mapleall/maple_ir/src/lexer.cpp b/src/mapleall/maple_ir/src/lexer.cpp index 1f47fc7d4c787626bf9ca1c4422943b972dfbb04..6d4c31b33a3c9268a2b655216afee1f3e231b08d 100644 --- a/src/mapleall/maple_ir/src/lexer.cpp +++ b/src/mapleall/maple_ir/src/lexer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * Copyright (c) [2019-2021] Huawei Technologies Co.,Ltd.All rights reserved. * * OpenArkCompiler is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. diff --git a/src/mapleall/maple_ir/src/mir_builder.cpp b/src/mapleall/maple_ir/src/mir_builder.cpp index ff8584e942e512366f86ff8fd1ea96241ad7b6be..b6f232a3a4261cae95954c2b7255edb951b6f203 100644 --- a/src/mapleall/maple_ir/src/mir_builder.cpp +++ b/src/mapleall/maple_ir/src/mir_builder.cpp @@ -29,7 +29,7 @@ void MIRBuilder::AddAddrofFieldConst(const MIRStructType &structType, MIRAggCons const MIRSymbol &fieldSymbol) { AddrofNode *fieldExpr = CreateExprAddrof(0, fieldSymbol, mirModule->GetMemPool()); auto *fieldConst = mirModule->GetMemPool()->New(fieldExpr->GetStIdx(), fieldExpr->GetFieldID(), - *structType.GetElemType(fieldID - 1)); + *structType.GetElemType(fieldID - 1)); fieldConst->SetFieldID(fieldID); newConst.PushBack(fieldConst); } @@ -1018,4 +1018,27 @@ MapleAllocator *MIRBuilder::GetCurrentFuncCodeMpAllocator() { return mirModule->CurFuncCodeMemPoolAllocator(); } +MIRBuilderExt::MIRBuilderExt(MIRModule *module, pthread_mutex_t *mutex) : MIRBuilder(module), mutex(mutex) {} + +MemPool *MIRBuilderExt::GetCurrentFuncCodeMp() { + ASSERT(curFunction, "curFunction is null"); + return curFunction->GetCodeMemPool(); +} + +MapleAllocator *MIRBuilderExt::GetCurrentFuncCodeMpAllocator() { + ASSERT(curFunction, "curFunction is null"); + return &curFunction->GetCodeMemPoolAllocator(); +} + +void MIRBuilderExt::GlobalLock() { + if (mutex) { + ASSERT(pthread_mutex_lock(mutex) == 0, "lock failed"); + } +} + +void MIRBuilderExt::GlobalUnlock() { + if (mutex) { + ASSERT(pthread_mutex_unlock(mutex) == 0, "unlock failed"); + } +} } // namespace maple diff --git a/src/mapleall/maple_ir/src/mir_module.cpp b/src/mapleall/maple_ir/src/mir_module.cpp index 4efa53ac49a61231c910e6cdd522d49f0f41dbc6..a0549b16a9680dae84deace8871b9f4114acde68 100644 --- a/src/mapleall/maple_ir/src/mir_module.cpp +++ b/src/mapleall/maple_ir/src/mir_module.cpp @@ -50,7 +50,8 @@ MIRModule::MIRModule(const std::string &fn) importPaths(memPoolAllocator.Adapter()), classList(memPoolAllocator.Adapter()), optimizedFuncs(memPoolAllocator.Adapter()), - puIdxFieldInitializedMap(std::less(), memPoolAllocator.Adapter()) { + puIdxFieldInitializedMap(std::less(), memPoolAllocator.Adapter()), + inliningGlobals(memPoolAllocator.Adapter()) { GlobalTables::GetGsymTable().SetModule(this); typeNameTab = memPool->New(memPoolAllocator); mirBuilder = memPool->New(this); @@ -63,7 +64,10 @@ MIRModule::~MIRModule() { } MemPool *MIRModule::CurFuncCodeMemPool() const { - return CurFunction()->GetCodeMempool(); + if (useFuncCodeMemPoolTmp) { + return CurFunction()->GetCodeMemPoolTmp(); + } + return CurFunction()->GetCodeMemPool(); } MapleAllocator *MIRModule::CurFuncCodeMemPoolAllocator() const { @@ -359,6 +363,33 @@ void MIRModule::DumpInlineCandidateToFile(const std::string &fileNameStr) const std::streambuf *backup = LogInfo::MapleLogger().rdbuf(); LogInfo::MapleLogger().rdbuf(file.rdbuf()); file.open(fileNameStr, std::ios::trunc); + // dump global variables needed for inlining file + for (auto symbolIdx : inliningGlobals) { + MIRSymbol *s = GlobalTables::GetGsymTable().GetSymbolFromStidx(symbolIdx); + if (s->GetStorageClass() == kScFstatic) { + if (s->IsNeedForwDecl()) { + // const string, including initialization + s->Dump(false, 0, false); + } + } + } + for (auto symbolIdx : inliningGlobals) { + MIRSymbol *s = GlobalTables::GetGsymTable().GetSymbolFromStidx(symbolIdx); + MIRStorageClass sc = s->GetStorageClass(); + if (s->GetStorageClass() == kScFstatic) { + if (!s->IsNeedForwDecl()) { + // const string, including initialization + s->Dump(false, 0, false); + } + } else if (s->GetSKind() == kStFunc) { + s->GetFunction()->Dump(true); + } else { + // static fields as extern + s->SetStorageClass(kScExtern); + s->Dump(false, 0, true); + } + s->SetStorageClass(sc); + } for (auto *func : optimizedFuncs) { func->SetWithLocInfo(false); func->Dump(); @@ -421,6 +452,115 @@ void MIRModule::DumpToHeaderFile(bool binaryMplt, const std::string &outputName) } } +/* + We use MIRStructType (kTypeStruct) to represent C/C++ structs + as well as C++ classes. + + We use MIRClassType (kTypeClass) to represent Java classes, specifically. + MIRClassType has parents which encode Java class's parent (exploiting + the fact Java classes have at most one parent class. + */ +void MIRModule::DumpTypeTreeToCxxHeaderFile(MIRType &ty, std::unordered_set &dumpedClasses) const { + if (dumpedClasses.find(&ty) != dumpedClasses.end()) { + return; + } + // first, insert ty to the dumped_classes to prevent infinite recursion + (void)dumpedClasses.insert(&ty); + ASSERT(ty.GetKind() == kTypeClass || ty.GetKind() == kTypeStruct || ty.GetKind() == kTypeUnion || + ty.GetKind() == kTypeInterface, + "Unexpected MIRType."); + /* No need to emit interfaces; because "interface variables are + final and static by default and methods are public and abstract" + */ + if (ty.GetKind() == kTypeInterface) { + return; + } + // dump all of its parents + if (srcLang == kSrcLangDex) { + ASSERT(ty.GetKind() != kTypeStruct, "type is not supposed to be struct"); + ASSERT(ty.GetKind() != kTypeUnion, "type is not supposed to be union"); + ASSERT(ty.GetKind() != kTypeInterface, "type is not supposed to be interface"); + } else if (srcLang == kSrcLangC || srcLang == kSrcLangCPlusPlus) { + ASSERT((ty.GetKind() == kTypeStruct || ty.GetKind() == kTypeUnion), "type should be either struct or union"); + } else { + ASSERT(false, "source languages other than DEX/C/C++ are not supported yet"); + } + const std::string &name = GlobalTables::GetStrTable().GetStringFromStrIdx(ty.GetNameStrIdx()); + if (srcLang == kSrcLangDex) { + // Java class has at most one parent + auto &classType = static_cast(ty); + MIRClassType *parentType = nullptr; + // find parent and generate its type as well as those of its ancestors + if (classType.GetParentTyIdx() != 0u /* invalid type idx */) { + parentType = static_cast( + GlobalTables::GetTypeTable().GetTypeFromTyIdx(classType.GetParentTyIdx())); + CHECK_FATAL(parentType != nullptr, "nullptr check"); + DumpTypeTreeToCxxHeaderFile(*parentType, dumpedClasses); + } + LogInfo::MapleLogger() << "struct " << name << " "; + if (parentType != nullptr) { + LogInfo::MapleLogger() << ": " << parentType->GetName() << " "; + } + if (!classType.IsIncomplete()) { + /* dump class type; it will dump as '{ ... }' */ + classType.DumpAsCxx(1); + LogInfo::MapleLogger() << ";\n"; + } else { + LogInfo::MapleLogger() << " /* incomplete type */\n"; + } + } else if (srcLang == kSrcLangC || srcLang == kSrcLangCPlusPlus) { + // how to access parent fields???? + ASSERT(false, "not yet implemented"); + } +} + +void MIRModule::DumpToCxxHeaderFile(std::set &leafClasses, const std::string &pathToOutf) const { + std::ofstream mpltFile; + mpltFile.open(pathToOutf, std::ios::trunc); + std::streambuf *backup = LogInfo::MapleLogger().rdbuf(); + LogInfo::MapleLogger().rdbuf(mpltFile.rdbuf()); // change cout's buffer to that of file + char *headerGuard = strdup(pathToOutf.c_str()); + CHECK_FATAL(headerGuard != nullptr, "strdup failed"); + for (char *p = headerGuard; *p; ++p) { + if (!isalnum(*p)) { + *p = '_'; + } else if (isalpha(*p) && islower(*p)) { + *p = toupper(*p); + } + } + // define a hash table + std::unordered_set dumpedClasses; + const char *prefix = "__SRCLANG_UNKNOWN_"; + if (srcLang == kSrcLangDex) { + prefix = "__SRCLANG_DEX_"; + } else if (srcLang == kSrcLangC || srcLang == kSrcLangCPlusPlus) { + prefix = "__SRCLANG_CXX_"; + } + LogInfo::MapleLogger() << "#ifndef " << prefix << headerGuard << "__\n"; + LogInfo::MapleLogger() << "#define " << prefix << headerGuard << "__\n"; + LogInfo::MapleLogger() << "/* this file is compiler-generated; do not edit */\n\n"; + LogInfo::MapleLogger() << "#include \n"; + LogInfo::MapleLogger() << "#include \n"; + for (auto &s : leafClasses) { + CHECK_FATAL(!s.empty(), "string is null"); + GStrIdx strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(s); + TyIdx tyIdx = typeNameTab->GetTyIdxFromGStrIdx(strIdx); + MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx); + if (ty == nullptr) { + continue; + } + ASSERT(ty->GetKind() == kTypeClass || ty->GetKind() == kTypeStruct || ty->GetKind() == kTypeUnion || + ty->GetKind() == kTypeInterface, + ""); + DumpTypeTreeToCxxHeaderFile(*ty, dumpedClasses); + } + LogInfo::MapleLogger() << "#endif /* " << prefix << headerGuard << "__ */\n"; + /* restore cout */ + LogInfo::MapleLogger().rdbuf(backup); + free(headerGuard); + headerGuard = nullptr; + mpltFile.close(); +} void MIRModule::DumpClassToFile(const std::string &path) const { std::string strPath(path); @@ -531,6 +671,10 @@ void MIRModule::RemoveClass(TyIdx tyIdx) { } #endif // MIR_FEATURE_FULL +void MIRModule::ReleaseCurFuncMemPoolTmp() { + CurFunction()->ReleaseMemory(); +} + void MIRModule::SetFuncInfoPrinted() const { CurFunction()->SetInfoPrinted(); } diff --git a/src/mapleall/maple_ir/src/parser.cpp b/src/mapleall/maple_ir/src/parser.cpp index 914a499b6800f9f6dbebb7eb8924a1dddaa7fa0a..6a05b3207f3e3f8e523f4fe6ecafb22e9d847114 100644 --- a/src/mapleall/maple_ir/src/parser.cpp +++ b/src/mapleall/maple_ir/src/parser.cpp @@ -1458,7 +1458,6 @@ bool MIRParser::ParseTypedef() { const std::string &name = lexer.GetName(); GStrIdx strIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name); TyIdx prevTyIdx; - MIRStructType *prevStructType = nullptr; TyIdx tyIdx(0); // dbginfo class/interface init if (tokenKind == TK_gname) { @@ -1472,8 +1471,7 @@ bool MIRParser::ParseTypedef() { if (!mod.IsCModule()) { CHECK_FATAL(prevType->IsStructType(), "type error"); } - prevStructType = dynamic_cast(prevType); - if ((prevType->GetKind() != kTypeByName) && (prevStructType && !prevStructType->IsIncomplete())) { + if ((prevType->GetKind() != kTypeByName) && !prevType->IsIncomplete()) { // allow duplicated type def if kKeepFirst is set which is the default if (options & kKeepFirst) { lexer.NextToken(); @@ -1497,8 +1495,7 @@ bool MIRParser::ParseTypedef() { prevTyIdx = mod.CurFunction()->GetTyIdxFromGStrIdx(strIdx); if (prevTyIdx != 0u) { MIRType *prevType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(prevTyIdx); - prevStructType = dynamic_cast(prevType); - if ((prevType->GetKind() != kTypeByName) && (prevStructType && !prevStructType->IsIncomplete())) { + if ((prevType->GetKind() != kTypeByName) && !prevType->IsIncomplete()) { Error("redefined local type name "); return false; } @@ -2115,7 +2112,7 @@ bool MIRParser::ParseInitValue(MIRConstPtr &theConst, TyIdx tyIdx, bool allowEmp Error("expect = after field ID in struct initialization but get "); return false; } - FieldPair thepair = static_cast(type).GetFields()[theFieldIdx-1]; + FieldPair thepair = static_cast(type).GetFields()[theFieldIdx - 1]; fieldTyIdx = thepair.second.first; if (fieldTyIdx == 0u) { Error("field ID out of range at struct initialization at "); diff --git a/src/mapleall/maple_me/BUILD.gn b/src/mapleall/maple_me/BUILD.gn index 0da1be1738743a90b68d69378aff5d43acb97480..5678a1aaeb88b0d119c3f58f3f68e407af18956e 100755 --- a/src/mapleall/maple_me/BUILD.gn +++ b/src/mapleall/maple_me/BUILD.gn @@ -47,6 +47,8 @@ src_libmplme = [ "src/me_irmap_build.cpp", "src/me_analyzector.cpp", "src/me_loop_canon.cpp", + "src/me_scalar_analysis.cpp", + "src/me_loop_unrolling.cpp", "src/me_option.cpp", "src/me_phase_manager.cpp", "src/me_prop.cpp", @@ -74,6 +76,16 @@ src_libmplme = [ "src/me_inequality_graph.cpp", "src/me_abco.cpp", "src/me_ssi.cpp", + "src/me_cfg_opt.cpp", + "src/me_predict.cpp", + "src/me_check_cast.cpp", + "src/ipa_side_effect.cpp", + "src/me_bb_analyze.cpp", + "src/meconstprop.cpp", + "src/sync_select.cpp", + "src/me_gc_lowering.cpp", + "src/me_gc_write_barrier_opt.cpp", + "src/me_subsum_rc.cpp", ] src_libmplmewpo = [ diff --git a/src/mapleall/maple_me/include/alias_class.h b/src/mapleall/maple_me/include/alias_class.h index 9a845e335cb2d18762d935ce5d38d8265670eab8..8adc18b3e80ef62515981257fc48040847d251f4 100644 --- a/src/mapleall/maple_me/include/alias_class.h +++ b/src/mapleall/maple_me/include/alias_class.h @@ -145,6 +145,7 @@ class AliasClass : public AnalysisResult { void ApplyUnionForPointedTos(); void CollectRootIDOfNextLevelNodes(const OriginalSt &ost, std::set &rootIDOfNADSs); void UnionForNotAllDefsSeen(); + void UnionForAggAndFields(); void CollectAliasGroups(std::map> &aliasGroups); bool AliasAccordingToType(TyIdx tyIdxA, TyIdx tyIdxB); bool AliasAccordingToFieldID(const OriginalSt &ostA, const OriginalSt &ostB); diff --git a/src/mapleall/maple_me/include/ipa_side_effect.h b/src/mapleall/maple_me/include/ipa_side_effect.h new file mode 100644 index 0000000000000000000000000000000000000000..13fb0dd44ddd0cdbfa4256656225e18a19f62e9a --- /dev/null +++ b/src/mapleall/maple_me/include/ipa_side_effect.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_IPASIDEEFFECT_H +#define MAPLE_ME_INCLUDE_IPASIDEEFFECT_H +#include "me_phase.h" +#include "call_graph.h" +#include "mir_nodes.h" +#include "mir_builder.h" +#include "me_ir.h" +#include "dominance.h" +#include "me_function.h" + +namespace maple { +class BB; +class VersionSt; +// Sideeffect summary +class FuncWithSideEffect { + public: + FuncWithSideEffect(bool pureArg, bool def, bool defArg, bool retGlobalArg, + bool exceptionArg, bool ret, bool privateDefArg, const std::string &name) + : funcName(name), pure(pureArg), defArg(def), def(defArg), retGlobal(retGlobalArg), + exception(exceptionArg), retArg(ret), privateDef(privateDefArg) {} + + std::string GetFuncName() const { + return funcName; + } + + virtual ~FuncWithSideEffect() = default; + bool GetPure() const { + return pure; + } + + bool GetDefArg() const { + return defArg; + } + + bool GetDef() const { + return def; + } + + bool GetRetGlobal() const { + return retGlobal; + } + + bool GetException() const { + return exception; + } + + bool GetRetArg() const { + return retArg; + } + + bool GetPrivateDef() const { + return privateDef; + } + + private: + std::string funcName; + bool pure; + bool defArg; + bool def; + bool retGlobal; + bool exception; + bool retArg; + bool privateDef; +}; + +// SCC side effects mask position +enum SCCEffectPosition : uint8 { + kHasThrow = 0x01, + kHasRetGlobal = 0x02, + kHasDef = 0x04, + kHasDefArg = 0x08, + kPure = 0x10, + kNotPure = kPure, // Same position as kPure, depending on usage. + kHasRetArg = 0x20, + kHasPrivateDef = 0x40 +}; + +class IpaSideEffect { + public: + IpaSideEffect(MeFunction&, MemPool*, CallGraph&, Dominance&); + virtual ~IpaSideEffect() = default; + void DoAnalysis(); + + private: + bool IsIgnoreMethod(const MIRFunction &func); + void AnalyzeUseThrowEhExpr(MeExpr &expr); + bool AnalyzeReturnAllocObj(MeExpr &expr, const std::vector&); + void SideEffectAnalyzeBB(BB&, std::vector&); + void GetEffectFromAllCallees(MIRFunction &baseFunc); + bool AnalyzeReturnAllocObjVst(MeExpr&, const std::vector&); + bool MatchPuidxAndSetSideEffects(PUIdx idx); + void ReadSummary(); + void SetEffectsTrue(); + void CopySccSideEffectToAllFunctions(SCCNode&, uint8); + void GetEffectFromCallee(MIRFunction &callee, const MIRFunction &caller); + void DumpFuncInfo(const std::string &msg, const std::string &name); + uint32 GetOrSetSCCNodeId(MIRFunction &func); + bool IsCallingIntoSCC(uint32 sccID) const; + void UpdateExternalFuncSideEffects(MIRFunction &externCaller); + bool AnalyzeDefExpr(VersionSt&, std::vector&); + bool MEAnalyzeDefExpr(MeExpr&, std::vector&); + bool UpdateSideEffectWithStmt(MeStmt&, std::set&, std::set&, + std::set&, std::set&); + void AnalyzeExpr(MeExpr&, std::set&, std::set&, std::set&, std::set&); + bool IsPureFromSummary(const MIRFunction&) const; + + void SetHasDef() { + hasDef = true; + } + + bool isSeen; // This module is compiled and the effects are valid + bool notPure; // Does module produce result purely based on the inputs + bool hasDefArg; + bool hasDef; // Has a definition of a field of any pre-existing object + bool hasRetGlobal; // Returns freshly allocated object + bool hasThrException; // throws an exception + bool hasRetArg; // access field is use and private + bool hasPrivateDef; // access field is def and private + bool isGlobal; + bool isArg; + MeFunction &meFunc; + MapleAllocator alloc; + CallGraph &callGraph; + uint32 sccId; + Dominance &dominance; +}; + +class DoIpaSideEffect : public MeFuncPhase { + public: + explicit DoIpaSideEffect(MePhaseID id) : MeFuncPhase(id) {} + + virtual ~DoIpaSideEffect() = default; + AnalysisResult *Run(MeFunction *func, MeFuncResultMgr *mfrm, ModuleResultMgr *mrm) override; + + std::string PhaseName() const override { + return "sideeffect"; + } +}; +} // namespace maple +#endif // MAPLE_ME_INCLUDE_IPASIDEEFFECT_H diff --git a/src/mapleall/maple_me/include/me_bb_analyze.h b/src/mapleall/maple_me/include/me_bb_analyze.h new file mode 100644 index 0000000000000000000000000000000000000000..2dc903342aa734be447dd93f6bd25fc4af6ed4f6 --- /dev/null +++ b/src/mapleall/maple_me/include/me_bb_analyze.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_ME_ANALYZE_H +#define MAPLE_ME_INCLUDE_ME_ANALYZE_H +#include +#include "bb.h" +#include "me_function.h" +#include "me_phase.h" +#include "me_option.h" + +namespace maple { +const uint32 kPrecision = 100; +class BBAnalyze : public AnalysisResult { + public: + BBAnalyze(MemPool &memPool, MeFunction &f) : AnalysisResult(&memPool), meBBAlloc(&memPool), func(f) {} + + virtual ~BBAnalyze() = default; + + void SetHotAndColdBBCountThreshold(); + bool CheckBBHot(const BBId bbId); + bool CheckBBCold(const BBId bbId); + uint32 getHotBBCountThreshold() const; + uint32 getColdBBCountThreshold() const; + + private: + MapleAllocator meBBAlloc; + MeFunction &func; + uint32 hotBBCountThreshold = 0; + uint32 coldBBCountThreshold = 0; +}; + +class MeDoBBAnalyze : public MeFuncPhase { + public: + explicit MeDoBBAnalyze(MePhaseID id) : MeFuncPhase(id) {} + + virtual ~MeDoBBAnalyze() = default; + AnalysisResult *Run(MeFunction *func, MeFuncResultMgr *funcResMgr, ModuleResultMgr *moduleResMgr) override; + std::string PhaseName() const override { + return "bbanalyze"; + } +}; +} // namespace maple +#endif // MAPLE_ME_INCLUDE_ME_ANALYZE_H \ No newline at end of file diff --git a/src/mapleall/maple_me/include/me_cfg_opt.h b/src/mapleall/maple_me/include/me_cfg_opt.h new file mode 100644 index 0000000000000000000000000000000000000000..39050ae11c6a35c6a95ed207565754df5891429f --- /dev/null +++ b/src/mapleall/maple_me/include/me_cfg_opt.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MAPLEME_INCLUDE_ME_CFGOPT +#define MAPLEME_INCLUDE_ME_CFGOPT +#include "me_function.h" +#include "me_phase.h" + +namespace maple { +class MeCfgOpt { + public: + explicit MeCfgOpt(MeIRMap *irMap) : meIrMap(irMap), isCfgChanged(false) {} + + ~MeCfgOpt() = default; + bool Run(MeFunction &func); + bool IsCfgChanged() const { + return isCfgChanged; + } + + void SetCfgChanged() { + isCfgChanged = true; + } + + private: + bool PreCheck(const MeFunction &func) const; + bool IsOk2Select(const MeExpr &expr0, const MeExpr &expr1) const; + // collect expensive ops and if there is reference, return true + static bool IsExpensiveOp(Opcode op); + bool CollectExpensiveOps(const MeExpr &meExpr, std::set &exprSet) const { + if (IsExpensiveOp(meExpr.GetOp())) { + (void)exprSet.insert(meExpr.GetExprID()); + } + PrimType primType = meExpr.GetPrimType(); + bool isRef = (primType == PTY_ref || primType == PTY_f64 || primType == PTY_f32); + if (isRef) { + return true; + } + for (size_t i = 0; i < meExpr.GetNumOpnds(); ++i) { + if (!CollectExpensiveOps(*meExpr.GetOpnd(i), exprSet)) { + isRef = false; + } + } + return isRef; + } + + bool HasFloatCmp(const MeExpr &meExpr) const; + const MeStmt *GetCondBrStmtFromBB(const BB &bb) const; + MeStmt *GetTheOnlyMeStmtFromBB(BB &bb) const; + MeStmt *GetTheOnlyMeStmtWithGotoFromBB(BB &bb) const; + MeIRMap *meIrMap; + bool isCfgChanged; +}; + +class MeDoCfgOpt : public MeFuncPhase { + public: + explicit MeDoCfgOpt(MePhaseID id) : MeFuncPhase(id) {} + + virtual ~MeDoCfgOpt() = default; + AnalysisResult *Run(MeFunction *func, MeFuncResultMgr *m, ModuleResultMgr *mrm) override; + std::string PhaseName() const override { + return "cfgopt"; + } + + bool FindLocalRefVarUses(const MeIRMap &irMap, const MeExpr &expr, const MeStmt &meStmt, const VarMeExpr &var) const; + void EmitMapleIr(MeFunction &func, MeFuncResultMgr &m); +}; +} // namespace maple +#endif // MAPLEME_INCLUDE_ME_CFGOPT diff --git a/src/mapleall/maple_me/include/me_check_cast.h b/src/mapleall/maple_me/include/me_check_cast.h new file mode 100644 index 0000000000000000000000000000000000000000..aebeaa2b6c7d5cf9893ff1e1292528e89d3c44bc --- /dev/null +++ b/src/mapleall/maple_me/include/me_check_cast.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MAPLEME_INCLUDE_MECHECKCAST_H +#define MAPLEME_INCLUDE_MECHECKCAST_H +#include "me_function.h" +#include "me_phase.h" +#include "me_irmap.h" +#include "me_ssi.h" +#include "annotation_analysis.h" + +namespace maple { +struct GenericNode { + AnnotationType *aType = nullptr; + GenericNode *next = nullptr; + bool multiOutput = false; +}; + +enum ProveRes { + kT, + kF, + kIgnore, +}; + +class CheckCast { + public: + CheckCast(MeFunction &func, KlassHierarchy &kh, MeSSI &ms) + : func(&func), klassh(&kh), meSSI(&ms) {} + ~CheckCast() = default; + + void DoCheckCastOpt(); + void FindRedundantChecks(); + void DeleteRedundants(); + private: + void RemoveRedundantCheckCast(MeStmt &stmt, BB &bb); + bool ProvedByAnnotationInfo(const IntrinsiccallMeStmt &callNode); + void TryToResolveCall(MeStmt &meStmt); + bool TryToResolveVar(VarMeExpr &var, MIRStructType *callStruct = nullptr, bool checkFirst = false); + void TryToResolveDassign(MeStmt &meStmt); + GenericNode *GetOrCreateGenericNode(AnnotationType *at); + void BuildGenericGraph(AnnotationType *annoType); + MIRType *TryToResolveType(GenericNode &retNode); + bool TryToResolveStaticVar(const VarMeExpr &var); + void TryToResolveIvar(IvarMeExpr &ivar, MIRStructType *callStruct = nullptr); + void TryToResolveFuncArg(MeExpr &expr, AnnotationType &at); + void TryToResolveFuncGeneric(MIRFunction &callee, const CallMeStmt &callMeStmt, size_t thisIdx); + void AddClassInheritanceInfo(MIRType &mirType); + bool NeedChangeVarType(MIRStructType *varStruct, MIRStructType *callStruct); + bool ExactlyMatch(MIRStructType &varStruct, MIRStructType &callStruct); + AnnotationType *CloneNewAnnotationType(AnnotationType *at, MIRStructType *callStruct); + void AddNextNode(GenericNode &from, GenericNode &to) const; + bool RetIsGenericRelative(MIRFunction &callee); + void DumpGenericGraph(); + void DumpGenericNode(GenericNode &node, std::ostream &out); + + bool ProvedBySSI(const IntrinsiccallMeStmt &callNode); + ProveRes TraverseBackProve(MeExpr &expr, MIRType &targetType, std::set &visitedPhi); + std::map created; + std::set visited; + MeFunction *func; + KlassHierarchy *klassh; + MeSSI *meSSI; + MemPool *graphTempMem { memPoolCtrler.NewMemPool("graph mempool tmp") }; + MapleAllocator graphTempAllocator { graphTempMem }; + MIRType *curCheckCastType { nullptr }; + std::vector redundantChecks; +}; + +class MeDoCheckCastOpt : public MeFuncPhase { + public: + explicit MeDoCheckCastOpt(MePhaseID id) : MeFuncPhase(id) {} + + virtual ~MeDoCheckCastOpt() = default; + + AnalysisResult *Run(MeFunction*, MeFuncResultMgr*, ModuleResultMgr*) override; + + std::string PhaseName() const override { + return "checkcastopt"; + } +}; +} // namespace maple +#endif // MAPLEME_INCLUDE_MECONDBASEDNPC_H diff --git a/src/mapleall/maple_me/include/me_dse.h b/src/mapleall/maple_me/include/me_dse.h index 05c8d7b189d5a5debb6b9f221a2c8d9022d932e4..d12543049c8dbab12f1e75e4e17f5123c451dfc9 100644 --- a/src/mapleall/maple_me/include/me_dse.h +++ b/src/mapleall/maple_me/include/me_dse.h @@ -29,7 +29,7 @@ class MeDSE : public DSE { MeDSE(MeFunction &func, Dominance *dom, bool enabledDebug) : DSE(std::vector(func.GetAllBBs().begin(), func.GetAllBBs().end()), *func.GetCommonEntryBB(), *func.GetCommonExitBB(), *func.GetMeSSATab(), - *dom, enabledDebug), + *dom, enabledDebug, MeOption::decoupleStatic), func(func) {} virtual ~MeDSE() = default; diff --git a/src/mapleall/maple_me/include/me_func_opt.h b/src/mapleall/maple_me/include/me_func_opt.h new file mode 100644 index 0000000000000000000000000000000000000000..a4f7a60e934a6fd30f21a2bb3dd3ac000eca9b4f --- /dev/null +++ b/src/mapleall/maple_me/include/me_func_opt.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_ME_FUNC_OPT_H +#define MAPLE_ME_INCLUDE_ME_FUNC_OPT_H +#include +#include "mpl_scheduler.h" +#include "me_phase_manager.h" + +namespace maple { +class MeFuncOptTask : public MplTask { + public: + MeFuncOptTask(MIRModule &mod, MIRFunction &func, size_t rangeNum, const std::string &meInput) + : module(mod), mirFunc(func), rangeNum(rangeNum), meInput(meInput) {} + ~MeFuncOptTask() override = default; + int RunImpl(MplTaskParam *param) override; + + private: + MIRModule &module; + MIRFunction &mirFunc; + size_t rangeNum; + const std::string &meInput; +}; + +class MeFuncOptExecutor : public MplTaskParam { + public: + MeFuncOptExecutor(std::unique_ptr mpCtrler, MeFuncPhaseManager &fpm) + : mpCtrler(std::move(mpCtrler)), fpm(fpm) {} + + ~MeFuncOptExecutor() = default; + + std::unique_ptr Clone() const; + void ProcessRun(MIRFunction &mirFunc, size_t rangeNum, const std::string &meInput); + + private: + std::unique_ptr mpCtrler; + MeFuncPhaseManager &fpm; +}; + +class MeFuncOptScheduler : public MplScheduler { + public: + MeFuncOptScheduler(const std::string &name, std::unique_ptr funcOpt) + : MplScheduler(name), funcOpt(std::move(funcOpt)) {} + + ~MeFuncOptScheduler() override {} + + void CallbackThreadMainStart() override; + void CallbackThreadMainEnd() override; + void AddFuncOptTask(MIRModule &module, MIRFunction &mirFunc, size_t rangeNum, const std::string &meInput); + + protected: + MplTaskParam *CallbackGetTaskRunParam() const override; + MplTaskParam *CallbackGetTaskFinishParam() const override; + + private: + thread_local static std::unique_ptr funcOptLocal; + std::unique_ptr funcOpt; + std::vector> tasksUniquePtr; +}; +} // namespace maple +#endif // MAPLE_ME_INCLUDE_ME_FUNC_OPT_H diff --git a/src/mapleall/maple_me/include/me_gc_lowering.h b/src/mapleall/maple_me/include/me_gc_lowering.h new file mode 100644 index 0000000000000000000000000000000000000000..e8667c134a767a44547f7dc5d0b0b2a44a335656 --- /dev/null +++ b/src/mapleall/maple_me/include/me_gc_lowering.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_ME_GC_LOWERING_H +#define MAPLE_ME_INCLUDE_ME_GC_LOWERING_H +#include "me_function.h" +#include "me_irmap.h" +#include "me_phase.h" +#include "mir_builder.h" + +namespace maple { +class GCLowering { + public: + GCLowering(MeFunction &f, bool enabledDebug) + : func(f), + mirModule(f.GetMIRModule()), + irMap(*f.GetIRMap()), + ssaTab(*f.GetMeSSATab()), + enabledDebug(enabledDebug) {} + + ~GCLowering() = default; + + void Prepare(); + void GCLower(); + void Finish(); + + private: + void GCLower(BB&); + void HandleAssignMeStmt(MeStmt&); + void HandleVarAssignMeStmt(MeStmt&); + void HandleIvarAssignMeStmt(MeStmt&); + MeExpr *GetBase(IvarMeExpr &ivar); + MIRIntrinsicID SelectWriteBarrier(MeStmt&); + MIRIntrinsicID PrepareVolatileCall(MeStmt&, MIRIntrinsicID); + void HandleWriteReferent(IassignMeStmt&); + void CheckRefs(); + void ParseCheckFlag(); + void CheckFormals(); + void CheckRefsInAssignStmt(BB &bb); + void CheckRefReturn(BB &bb); + + MeFunction &func; + MIRModule &mirModule; + IRMap &irMap; + SSATab &ssaTab; + bool isReferent = false; + bool enabledDebug; + bool checkRefFormal = false; + bool checkRefAssign = false; + bool checkRefReturn = false; +}; + +class MeDoGCLowering : public MeFuncPhase { + public: + explicit MeDoGCLowering(MePhaseID id) : MeFuncPhase(id) {} + + virtual ~MeDoGCLowering() = default; + AnalysisResult *Run(MeFunction*, MeFuncResultMgr*, ModuleResultMgr*) override; + std::string PhaseName() const override { + return "gclowering"; + } +}; +} // namespace maple +#endif // MAPLE_ME_INCLUDE_ME_GC_LOWERING_H diff --git a/src/mapleall/maple_me/include/me_gc_write_barrier_opt.h b/src/mapleall/maple_me/include/me_gc_write_barrier_opt.h new file mode 100644 index 0000000000000000000000000000000000000000..3d8ec9fe0419191b939640a12bfa2581ea8d68b0 --- /dev/null +++ b/src/mapleall/maple_me/include/me_gc_write_barrier_opt.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_ME_GC_WRITE_BARRIER_OPT_H +#define MAPLE_ME_INCLUDE_ME_GC_WRITE_BARRIER_OPT_H +#include "me_function.h" +#include "me_irmap.h" + +namespace maple { +class GCWriteBarrierOpt { + public: + GCWriteBarrierOpt(MeFunction &f, Dominance &dom, bool enabledDebug) + : func(f), + mirModule(f.GetMIRModule()), + irMap(*f.GetIRMap()), + ssaTab(*f.GetMeSSATab()), + dominance(dom), + callBBs(f.GetAllBBs().size(), false), + visited(f.GetAllBBs().size(), false), + enabledDebug(enabledDebug) {} + + ~GCWriteBarrierOpt() = default; + + void Prepare(); + void GCLower(BB&, std::map>&); + void Finish(); + + private: + bool IsWriteBarrier(const MeStmt&); + void ResetMeStmt(IntrinsiccallMeStmt&); + OStIdx GetOStIdx(MeExpr&); + bool IsCall(const MeStmt&); + bool HasYieldPoint(const MeStmt&, const MeStmt&); + bool HasCallAfterStmt(const MeStmt&); + bool HasCallBeforeStmt(const MeStmt&); + bool HasCallBetweenStmt(const MeStmt&, const MeStmt&); + bool IsBackEdgeDest(const BB&); + bool HasCallInBB(const BB&); + + MeFunction &func; + MIRModule &mirModule; + IRMap &irMap; + SSATab &ssaTab; + Dominance &dominance; + std::vector callBBs; + std::vector visited; + bool enabledDebug; +}; + +class MeDoGCWriteBarrierOpt : public MeFuncPhase { + public: + explicit MeDoGCWriteBarrierOpt(MePhaseID id) : MeFuncPhase(id) {} + + virtual ~MeDoGCWriteBarrierOpt() = default; + AnalysisResult *Run(MeFunction*, MeFuncResultMgr*, ModuleResultMgr*) override; + std::string PhaseName() const override { + return "GCWriteBarrierOpt"; + } +}; +} // namespace maple +#endif // MAPLE_ME_INCLUDE_ME_GC_WRITE_BARRIER_OPT_H diff --git a/src/mapleall/maple_me/include/me_loop_unrolling.h b/src/mapleall/maple_me/include/me_loop_unrolling.h new file mode 100644 index 0000000000000000000000000000000000000000..ad9bf43ea12839efcc1e94476730664b57cfaba1 --- /dev/null +++ b/src/mapleall/maple_me/include/me_loop_unrolling.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_LOOP_UNROLLING_H +#define MAPLE_ME_INCLUDE_LOOP_UNROLLING_H +#include "me_scalar_analysis.h" +#include "me_function.h" +#include "me_irmap.h" +#include "me_phase.h" +#include "me_ir.h" +#include "me_ssa_update.h" +#include "me_dominance.h" +#include "me_loop_analysis.h" +#include "profile.h" + +namespace maple { +constexpr uint32 kMaxCost = 100; +constexpr uint8 unrollTimes[3] = { 8, 4, 2 }; // unrollTimes +class LoopUnrolling { + public: + LoopUnrolling(MeFunction &f, MeFuncResultMgr &m, LoopDesc &l, MeIRMap &map, MemPool &pool, Dominance *d) + : func(&f), mgr(&m), loop(&l), irMap(&map), memPool(&pool), mpAllocator(&pool), dom(d), + cands((std::less(), mpAllocator.Adapter())), lastNew2OldBB(mpAllocator.Adapter()), + profValid(func->IsIRProfValid()) {} + ~LoopUnrolling() = default; + bool LoopFullyUnroll(int64 tripCount); + bool LoopPartialUnrollWithConst(uint32 tripCount); + void LoopPartialUnrollWithVar(CR &cr, CRNode &varNode, uint32 i); + + private: + VarMeExpr *CreateIndVarOrTripCountWithName(const std::string &name); + void RemoveCondGoto(); + void BuildChiList(const BB &bb, MeStmt &newStmt, const MapleMap &oldChilist, + MapleMap &newChiList); + void BuildMustDefList(const BB &bb, MeStmt &newStmt, const MapleVector &oldMustDef, + MapleVector &newMustDef); + void CopyDassignStmt(const MeStmt &stmt, BB &bb); + void CopyIassignStmt(MeStmt &stmt, BB &bb); + void CopyIntrinsiccallStmt(MeStmt &stmt, BB &bb); + void CopyCallStmt(MeStmt &stmt, BB &bb); + void SetLabelWithCondGotoOrGotoBB(BB &bb, std::unordered_map &old2NewBB, const BB &exitBB, + LabelIdx oldlabIdx); + void ResetOldLabel2NewLabel(std::unordered_map &old2NewBB, BB &bb, + const BB &exitBB, BB &newHeadBB); + void ResetOldLabel2NewLabel2(std::unordered_map &old2NewBB, BB &bb, + const BB &exitBB, BB &newHeadBB); + void CopyLoopBody(BB &newHeadBB, std::unordered_map &old2NewBB, + std::set &labelBBs, const BB &exitBB, bool copyAllLoop); + void CopyLoopBodyForProfile(BB &newHeadBB, std::unordered_map &old2NewBB, + std::set &labelBBs, const BB &exitBB, bool copyAllLoop); + void UpdateCondGotoBB(BB &bb, VarMeExpr &indVar, MeExpr &tripCount, MeExpr &unrollTimeExpr); + void UpdateCondGotoStmt(BB &bb, VarMeExpr &indVar, MeExpr &tripCount, MeExpr &unrollTimeExpr, uint32 offset); + void CreateIndVarAndCondGotoStmt(CR &cr, CRNode &varNode, BB &preCondGoto, uint32 unrollTime, uint32 i); + void CopyLoopForPartial(BB &partialCondGoto, BB &exitedBB, BB &exitingBB); + void CopyLoopForPartial(CR &cr, CRNode &varNode, uint32 j, uint32 unrollTime); + void AddPreHeader(BB *oldPreHeader, BB *head); + MeExpr *CreateExprWithCRNode(CRNode &crNode); + void InsertCondGotoBB(); + void ResetFrequency(BB &bb); + void ResetFrequency(BB &newCondGotoBB, BB &exitingBB, const BB &exitedBB, uint32 headFreq); + void ResetFrequency(); + void ResetFrequency(const BB &curBB, const BB &succ, const BB &exitBB, BB &curCopyBB, bool copyAllLoop); + BB *CopyBB(BB &bb, bool isInLoop); + void CopyLoopForPartialAndPre(BB *&newHead, BB *&newExiting); + void CopyAndInsertBB(bool isPartial); + void CopyAndInsertStmt(BB &bb, std::vector &meStmts); + void InsertCandsForSSAUpdate(OStIdx ostIdx, const BB &bb); + void ComputeCodeSize(const MeStmt &meStmt, uint32 &cost); + bool DetermineUnrollTimes(uint32 &index, bool isConst); + void CreateLableAndInsertLabelBB(BB &newHeadBB, std::set &labelBBs); + void AddEdgeForExitBBLastNew2OldBBEmpty(BB &exitBB, std::unordered_map &old2NewBB, BB &newHeadBB); + void AddEdgeForExitBB(BB &exitBB, std::unordered_map &old2NewBB, BB &newHeadBB); + void ExchangeSucc(BB &partialExit); + + bool canUnroll = true; + MeFunction *func; + MeFuncResultMgr *mgr; + LoopDesc *loop; + MeIRMap *irMap; + MemPool *memPool; + MapleAllocator mpAllocator; + Dominance *dom; + MapleMap*> cands; + MapleMap lastNew2OldBB; + BB *partialSuccHead = nullptr; + uint64 replicatedLoopNum = 0; + uint64 partialCount = 0; + bool needUpdateInitLoopFreq = true; + bool profValid; + bool resetFreqForAfterInsertGoto = false; + bool firstResetForAfterInsertGoto = true; + bool resetFreqForUnrollWithVar = false; + bool isUnrollWithVar = false; +}; + +class MeDoLoopUnrolling : public MeFuncPhase { + public: + static bool enableDebug; + static bool enableDump; + explicit MeDoLoopUnrolling(MePhaseID id) : MeFuncPhase(id) {} + ~MeDoLoopUnrolling() = default; + + AnalysisResult *Run(MeFunction *func, MeFuncResultMgr *m, ModuleResultMgr*) override; + std::string PhaseName() const override { + return "loopunrolling"; + } + + private: + std::map> parentLoop; + void SetNestedLoop(const IdentifyLoops &meloop); + void ExecuteLoopUnrolling(MeFunction &func, MeFuncResultMgr &m, MeIRMap &irMap); + void VerifyCondGotoBB(BB &exitBB) const; + bool IsDoWhileLoop(MeFunction &func, LoopDesc &loop) const; + bool PredIsOutOfLoopBB(MeFunction &func, LoopDesc &loop) const; + bool IsCanonicalAndOnlyOneExitLoop(MeFunction &func, LoopDesc &loop) const; + void ExcuteLoopUnrollingWithConst(uint32 tripCount, MeFunction &func, MeIRMap &irMap, + LoopUnrolling &loopUnrolling); +}; +} // namespace maple +#endif // MAPLE_ME_INCLUDE_LOOP_UNROLLING_H \ No newline at end of file diff --git a/src/mapleall/maple_me/include/me_phases.def b/src/mapleall/maple_me/include/me_phases.def index a471fb26f26e0a14c221bd14fc864254933243cc..ff881179ef024fcc3112abb181d9efbdf24c072d 100644 --- a/src/mapleall/maple_me/include/me_phases.def +++ b/src/mapleall/maple_me/include/me_phases.def @@ -32,12 +32,29 @@ FUNCTPHASE(MeFuncPhase_DSE, MeDoDSE) FUNCTPHASE(MeFuncPhase_HPROP, MeDoMeProp) FUNCTPHASE(MeFuncPhase_HDSE, MeDoHDSE) FUNCTPHASE(MeFuncPhase_SSADEVIRT, MeDoSSADevirtual) +FUNCAPHASE(MeFuncPhase_LOOPUNROLLING, MeDoLoopUnrolling) +FUNCTPHASE(MeFuncPhase_CFGOPT, MeDoCfgOpt) +FUNCAPHASE(MeFuncPhase_PREDICT, MeDoPredict) +FUNCAPHASE(MeFuncPhase_CHECKCASTOPT, MeDoCheckCastOpt) +FUNCAPHASE(MeFuncPhase_IPAEA, DoIpaEA) +FUNCTPHASE(MeFuncPhase_IPAEAOPT, DoIpaEAOpt) +FUNCTPHASE(MeFuncPhase_IPASIDEEFFECT, DoIpaSideEffect) +FUNCAPHASE(MeFuncPhase_BBANALYZE, MeDoBBAnalyze) FUNCTPHASE(MeFuncPhase_SSAEPRE, MeDoSSAEPre) FUNCTPHASE(MeFuncPhase_SSALPRE, MeDoSSALPre) FUNCTPHASE(MeFuncPhase_STOREPRE, MeDoStorePre) FUNCTPHASE(MeFuncPhase_STMTPRE, MeDoStmtPre) FUNCTPHASE(MeFuncPhase_SSARENAME2PREG, MeDoSSARename2Preg) FUNCTPHASE(MeFuncPhase_PREGRENAMER, MeDoPregRename) +FUNCTPHASE(MeFuncPhase_INTRACONSTPROP, MeDoIntraConstProp) +FUNCTPHASE(MeFuncPhase_INTERCONSTPROP, MeDoInterConstProp) +#if MIR_JAVA +FUNCTPHASE(MeFuncPhase_SYNCSELECT, MeDoSyncSelect) +#endif +FUNCTPHASE(MeFuncPhase_GCLOWERING, MeDoGCLowering) +FUNCAPHASE(MeFuncPhase_GCWRITEBARRIEROPT, MeDoGCWriteBarrierOpt) +FUNCTPHASE(MeFuncPhase_PLACEMENTRC, MeDoPlacementRC) +FUNCAPHASE(MeFuncPhase_SUBSUMRC, MeDoSubsumRC) FUNCTPHASE(MeFuncPhase_ANALYZERC, MeDoAnalyzeRC) FUNCAPHASE(MeFuncPhase_DELEGATERC, MeDoDelegateRC) FUNCAPHASE(MeFuncPhase_CONDBASEDRC, MeDoCondBasedRC) diff --git a/src/mapleall/maple_me/include/me_predict.def b/src/mapleall/maple_me/include/me_predict.def new file mode 100644 index 0000000000000000000000000000000000000000..3b52605af7f49f574f4760430c15c34df53be4ce --- /dev/null +++ b/src/mapleall/maple_me/include/me_predict.def @@ -0,0 +1,51 @@ +/* + * Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ + +// (id, name, probability) + +// A value used as final outcome of all heuristics. +DEF_PREDICTOR (kPredCombined, "combined", kProbAlways) + +// No heuristic applying. +DEF_PREDICTOR (kPredNoPrediction, "no prediction", kProbAlways) + +// Branch causing function to terminate is probably not taken. +DEF_PREDICTOR (kPredEarlyReturn, "early return", HITRATE (66)) + +// Edge causing loop to terminate is probably not taken. +DEF_PREDICTOR (kPredLoopExit, "loop exit", HITRATE (89)) + +// Pointers are usually not nullptr. +DEF_PREDICTOR (kPredPointer, "pointer", HITRATE (70)) + +// NE is probable, EQ not etc... +DEF_PREDICTOR (kPredOpcodePositive, "opcode values positive", HITRATE (59)) +DEF_PREDICTOR (kPredOpcodeNonEqual, "opcode values nonequal", HITRATE (66)) +DEF_PREDICTOR (kPredFPOpcode, "fp_opcode", HITRATE (90)) + +// Branch containing call is probably taken. +DEF_PREDICTOR (kPredCall, "call", HITRATE (67)) + +// Branch ending with return constant is probably not taken. +DEF_PREDICTOR (kPredConstReturn, "const return", HITRATE (65)) + +// Branch ending with return negative constant is probably not taken. +DEF_PREDICTOR (kPredNegativeReturn, "negative return", HITRATE (98)) + +// Branch ending with return null is probably not taken +DEF_PREDICTOR (kPredNullReturn, "null return", HITRATE (71)) + +// Java try fallthru is almost taken +DEF_PREDICTOR (kPredTry, "try start label", HITRATE (98)) diff --git a/src/mapleall/maple_me/include/me_predict.h b/src/mapleall/maple_me/include/me_predict.h new file mode 100644 index 0000000000000000000000000000000000000000..07b99b9df526c018390a64cda06a70514b7cc52e --- /dev/null +++ b/src/mapleall/maple_me/include/me_predict.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_MEPREDICT_H +#define MAPLE_ME_INCLUDE_MEPREDICT_H +#include "me_function.h" +#include "bb.h" +#include "me_phase.h" +#include "dominance.h" +#include "me_loop_analysis.h" + +namespace maple { +// Information about each branch predictor. +struct PredictorInfo { + const char *name; // Name used in the debugging dumps. + const int hitRate; // Expected hitrate used by PredictDef call. +}; + +#define DEF_PREDICTOR(ENUM, NAME, HITRATE) ENUM, +enum Predictor { +#include "me_predict.def" + kEndPrediction +}; +#undef DEF_PREDICTOR +enum Prediction { kNotTaken, kTaken }; + +// Indicate the edge from src to dest. +struct Edge { + const BB &src; + const BB &dest; + Edge *next = nullptr; // the edge with the same src + uint32 probability = 0; + uint32 frequency = 0; + Edge(const BB &bb1, const BB &bb2) : src(bb1), dest(bb2) {} +}; + +// Represents predictions on edge. +struct EdgePrediction { + Edge &epEdge; + EdgePrediction *epNext = nullptr; + Predictor epPredictor = kPredNoPrediction; + int32 epProbability = -1; + explicit EdgePrediction(Edge &edge) : epEdge(edge) {} +}; + +// Emistimate frequency for MeFunction. +class MePrediction : public AnalysisResult { + public: + static const PredictorInfo predictorInfo[kEndPrediction + 1]; + MePrediction(MemPool &memPool, MemPool &tmpPool, MeFunction &mf, Dominance &dom, IdentifyLoops &loops, + MeIRMap &map) + : AnalysisResult(&memPool), + mePredAlloc(&memPool), + tmpAlloc(&tmpPool), + func(&mf), + dom(&dom), + meLoop(&loops), + hMap(&map), + bbPredictions(tmpAlloc.Adapter()), + edges(tmpAlloc.Adapter()), + backEdgeProb(tmpAlloc.Adapter()), + bbVisited(tmpAlloc.Adapter()), + backEdges(tmpAlloc.Adapter()), + predictDebug(false) {} + + virtual ~MePrediction() = default; + Edge *FindEdge(const BB &src, const BB &dest) const; + bool IsBackEdge(const Edge &edge) const; + Predictor ReturnPrediction(const MeExpr *meExpr, Prediction &prediction) const; + void PredictEdge(Edge &edge, Predictor predictor, int probability); + void PredEdgeDef(Edge &edge, Predictor predictor, Prediction taken); + void BBLevelPredictions(); + void Init(); + bool PredictedByLoopHeuristic(const BB &bb) const; + void SortLoops(); + void PredictLoops(); + void PredictByOpcode(const BB *bb); + void EstimateBBProb(const BB &bb); + void ClearBBPredictions(const BB &bb); + void CombinePredForBB(const BB &bb); + void PropagateFreq(BB &head, BB &bb); + void EstimateLoops(); + void EstimateBBFrequencies(); + void EstimateProbability(); + void SetPredictDebug(bool val); + + protected: + MapleAllocator mePredAlloc; + MapleAllocator tmpAlloc; + MeFunction *func; + Dominance *dom; + IdentifyLoops *meLoop; + MeIRMap *hMap; + MapleVector bbPredictions; + MapleVector edges; + MapleMap backEdgeProb; // used in EstimateBBFrequency + MapleVector bbVisited; + MapleVector backEdges; // all backedges of loops + bool predictDebug; +}; + +class MeDoPredict : public MeFuncPhase { + public: + explicit MeDoPredict(MePhaseID id) : MeFuncPhase(id) {} + + virtual ~MeDoPredict() = default; + AnalysisResult *Run(MeFunction *func, MeFuncResultMgr *m, ModuleResultMgr *mrm) override; + std::string PhaseName() const override { + return "mepredict"; + } +}; +} // namespace maple +#endif // MAPLE_ME_INCLUDE_MEPREDICT_H diff --git a/src/mapleall/maple_me/include/me_rc_lowering.h b/src/mapleall/maple_me/include/me_rc_lowering.h index fedd249a410838c32954daa3c5fd43eb593b93fd..dfcdaff43f2271c31187129cb030b06da53cc3ef 100644 --- a/src/mapleall/maple_me/include/me_rc_lowering.h +++ b/src/mapleall/maple_me/include/me_rc_lowering.h @@ -23,11 +23,12 @@ namespace maple { class RCLowering { public: - RCLowering(MeFunction &f, bool enabledDebug) + RCLowering(MeFunction &f, KlassHierarchy &kh, bool enabledDebug) : func(f), mirModule(f.GetMIRModule()), irMap(*f.GetIRMap()), ssaTab(*f.GetMeSSATab()), + klassHierarchy(kh), enabledDebug(enabledDebug) {} virtual ~RCLowering() = default; @@ -37,6 +38,10 @@ class RCLowering { void RCLower(); void PostRCLower(); void Finish(); + void FastBBLower(BB &bb); + void SetDominance(Dominance &domin) { + dominance = &domin; + } bool GetIsAnalyzed() const { return isAnalyzed; } @@ -44,6 +49,12 @@ class RCLowering { private: void MarkLocalRefVar(); void MarkAllRefOpnds(); + void UpdateRefVarVersions(BB &bb); + void RecordVarPhiVersions(std::map &savedStackSize, const BB &bb); + void TraverseAllStmts(BB &bb); + void RestoreVersionRecords(std::map &savedStackSize); + void UnmarkNotNeedDecRefOpnds(); + void EpreFixup(BB &bb); void BBLower(BB &bb); void CreateCleanupIntrinsics(); void HandleArguments(); @@ -88,17 +99,36 @@ class RCLowering { void HandleReturnNeedBackup(); void HandleReturnStmt(); void HandleAssignMeStmt(MeStmt &stmt, MeExpr *pendingDec); + void HandlePerManent(MeStmt &stmt); + bool HasCallOrBranch(const MeStmt &from, const MeStmt &to); MIRIntrinsicID SelectWriteBarrier(const MeStmt &stmt); MIRType *GetArrayNodeType(const VarMeExpr &var); void CheckArrayStore(const IntrinsiccallMeStmt &writeRefCall); + void FastLowerThrowStmt(MeStmt &stmt, MapleMap &exceptionAllocsites); + void FastLowerRetStmt(MeStmt &stmt); + void FastLowerRetVar(RetMeStmt &stmt); + void FastLowerRetIvar(RetMeStmt &stmt); + void FastLowerRetReg(RetMeStmt &stmt); + void FastLowerAssignToVar(MeStmt &stmt, MapleMap &exceptionAllocsites); + void FastLowerAssignToIvar(MeStmt &stmt); + void FastLowerCallAssignedStmt(MeStmt &stmt); + void CheckRefs(); + void ParseCheckFlag(); + void CheckFormals(); + void CheckRefsInAssignStmt(BB &bb); + void CheckRefReturn(BB &bb); MeFunction &func; MIRModule &mirModule; IRMap &irMap; SSATab &ssaTab; + KlassHierarchy &klassHierarchy; std::vector rets{}; // std::vector of return statement unsigned int tmpCount = 0; + uint32_t checkRCIndex = 0; bool needSpecialHandleException = false; bool isAnalyzed = false; + bool rcCheckReferent = false; + Dominance *dominance = nullptr; std::set assignedPtrSym; std::set tmpLocalRefVars; std::set gcMallocObjects{}; @@ -106,6 +136,11 @@ class RCLowering { std::map varOStMap{}; // used to store initialized map, help to optimize dec ref in first assignment std::unordered_map> initializedFields{}; + std::map decOpnds{}; + std::map> varVersions{}; + bool checkRefFormal = false; + bool checkRefAssign = false; + bool checkRefReturn = false; bool enabledDebug; }; diff --git a/src/mapleall/maple_me/include/me_scalar_analysis.h b/src/mapleall/maple_me/include/me_scalar_analysis.h new file mode 100644 index 0000000000000000000000000000000000000000..830455725352c5799536162275b91e589526751a --- /dev/null +++ b/src/mapleall/maple_me/include/me_scalar_analysis.h @@ -0,0 +1,280 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_SCALAR_ANALYSIS_H +#define MAPLE_ME_INCLUDE_SCALAR_ANALYSIS_H +#include "me_function.h" +#include "me_irmap.h" +#include "me_phase.h" +#include "me_loop_analysis.h" +#include "me_ir.h" + +namespace maple { +class LoopScalarAnalysisResult; + +enum CRNodeType { + kCRConstNode, + kCRVarNode, + kCRAddNode, + kCRMulNode, + kCRDivNode, + kCRNode, + kCRUnKnown +}; + +class CRNode { + public: + CRNode(MeExpr *e, CRNodeType t) : expr(e), crType(t) {} + virtual ~CRNode() = default; + + CRNodeType GetCRType() const { + return crType; + } + + MeExpr *GetExpr() { + return expr; + } + + const MeExpr *GetExpr() const { + return expr; + } + + private: + MeExpr *expr; + CRNodeType crType; +}; + +class CRUnKnownNode : public CRNode { + public: + explicit CRUnKnownNode(MeExpr *e) : CRNode(e, kCRUnKnown) {} + ~CRUnKnownNode() = default; +}; + +class CRConstNode : public CRNode { + public: + CRConstNode(MeExpr *e, int v) : CRNode(e, kCRConstNode), value(v) {} + ~CRConstNode() = default; + + int32 GetConstValue() const { + return value; + } + + private: + int32 value; +}; + +class CRVarNode : public CRNode { + public: + explicit CRVarNode(MeExpr *e) : CRNode(e, kCRVarNode) {} + ~CRVarNode() = default; +}; + +class CRAddNode : public CRNode { + public: + explicit CRAddNode(MeExpr *e) : CRNode(e, kCRAddNode) {} + ~CRAddNode() = default; + + void SetOpnds(std::vector &o) { + opnds = o; + } + + CRNode *GetOpnd(size_t i) const { + return opnds.at(i); + } + + std::vector &GetOpnds() { + return opnds; + } + + const std::vector &GetOpnds() const { + return opnds; + } + + size_t GetOpndsSize() const { + return opnds.size(); + } + + private: + std::vector opnds; +}; + +class CRMulNode : public CRNode { + public: + explicit CRMulNode(MeExpr *e) : CRNode(e, kCRMulNode) {} + ~CRMulNode() = default; + + const CRNode *GetOpnd(size_t i) const { + return opnds.at(i); + } + + CRNode *GetOpnd(size_t i) { + return opnds.at(i); + } + + size_t GetOpndsSize() const { + return opnds.size(); + } + + void SetOpnds(std::vector &o) { + opnds = o; + } + + std::vector &GetOpnds() { + return opnds; + } + + private: + std::vector opnds; +}; + +class CRDivNode : public CRNode { + public: + CRDivNode(MeExpr *e, CRNode &l, CRNode &r) : CRNode(e, kCRDivNode), lhs(&l), rhs(&r) {} + ~CRDivNode() = default; + + const CRNode *GetLHS() const { + return lhs; + } + + CRNode *GetLHS() { + return lhs; + } + + const CRNode *GetRHS() const { + return rhs; + } + + CRNode *GetRHS() { + return rhs; + } + + private: + CRNode *lhs; + CRNode *rhs; +}; + +class CR : public CRNode { + public: + explicit CR(MeExpr *e) : CRNode(e, kCRNode) {} + ~CR() = default; + + void SetOpnds(std::vector &o) { + opnds = o; + } + + const CRNode *GetOpnd(size_t i) const { + return opnds.at(i); + } + + CRNode *GetOpnd(size_t i) { + return opnds.at(i); + } + + void PushOpnds(CRNode &crNode) { + opnds.push_back(&crNode); + } + + void InsertOpnds(const std::vector::iterator begin, const std::vector::iterator end) { + (void)opnds.insert(opnds.end(), begin, end); + } + + size_t GetOpndsSize() const { + return opnds.size(); + } + + const std::vector &GetOpnds() const { + return opnds; + } + + std::vector &GetOpnds() { + return opnds; + } + + CRNode *GetPolynomialsValueAtITerm(CRNode &iterCRNode, size_t num, LoopScalarAnalysisResult &scalarAnalysis) const; + CRNode *ComputeValueAtIteration(uint32 i, LoopScalarAnalysisResult &scalarAnalysis) const; + + private: + std::vector opnds; +}; + +struct CompareCRNode { + bool operator()(const CRNode *a, const CRNode *b) const { + return a->GetCRType() < b->GetCRType(); + } +}; + +enum TripCountType { + kConstCR, + kVarCR, + kVarCondition, + kCouldNotUnroll, + kCouldNotComputeCR +}; + +class LoopScalarAnalysisResult { + public: + static bool enableDebug; + LoopScalarAnalysisResult(MeIRMap &map, LoopDesc &l) : irMap(&map), loop(&l) {} + ~LoopScalarAnalysisResult() = default; + + bool IsAnalysised(MeExpr &expr) const { + return expr2CR.find(&expr) != expr2CR.end(); + } + + CRNode *GetExpr2CR(MeExpr &expr) { + CHECK_FATAL(expr2CR.find(&expr) != expr2CR.end(), "computedCR must exit"); + return expr2CR[&expr]; + } + + void InsertExpr2CR(MeExpr &expr, CRNode *cr) { + if ((expr2CR.find(&expr) != expr2CR.end()) && (expr2CR[&expr]->GetCRType() != kCRUnKnown)) { + CHECK_FATAL(false, "computedCR must not exit or kCRUnKnown"); + } + expr2CR[&expr] = cr; + } + + void Dump(const CRNode &crNode); + void VerifyCR(const CRNode &crNode); + bool HasUnknownCRNode(CRNode &crNode, CRNode *&result); + CR *AddCRWithCR(CR &lhsCR, CR &rhsCR); + CR *MulCRWithCR(const CR &lhsCR, const CR &rhsCR) const; + MeExpr *TryToResolveVar(MeExpr &expr, std::set &visitedPhi, MeExpr &dummyExpr); + CRNode *GetCRAddNode(MeExpr *expr, std::vector &crAddOpnds); + CRNode *GetCRMulNode(MeExpr *expr, std::vector &crMulOpnds); + CRNode *GetOrCreateCR(MeExpr &expr, CRNode &start, CRNode &stride); + CRNode *GetOrCreateCR(MeExpr *expr, std::vector &crNodes); + CRNode *GetOrCreateLoopInvariantCR(MeExpr &expr); + CRNode *ChangeNegative2MulCRNode(CRNode &crNode); + CRNode *GetOrCreateCRConstNode(MeExpr *expr, int32 value); + CRNode *GetOrCreateCRVarNode(MeExpr &expr); + CRNode *GetOrCreateCRAddNode(MeExpr *expr, std::vector &crAddNodes); + CRNode *GetOrCreateCRMulNode(MeExpr *expr, std::vector &crMulNodes); + CRNode *GetOrCreateCRDivNode(MeExpr *expr, CRNode &lhsCRNode, CRNode &rhsCRNode); + CRNode *ComputeCRNodeWithOperator(MeExpr &expr, CRNode &lhsCRNode, CRNode &rhsCRNode, Opcode op); + CRNode *CreateSimpleCRForPhi(MePhiNode &phiNode, VarMeExpr &startExpr, const VarMeExpr &backEdgeExpr); + CRNode *CreateCRForPhi(MePhiNode &phiNode); + CRNode *GetOrCreateCRNode(MeExpr &expr); + TripCountType ComputeTripCount(MeFunction &func, uint32 &tripCountResult, CRNode *&conditionCRNode, CR *&itCR); + + private: + MeIRMap *irMap; + LoopDesc *loop; + std::map expr2CR; + std::set> allCRNodes; + void DumpTripCount(const CR &cr, int32 value, const MeExpr *expr); + uint32 ComputeTripCountWithCR(const CR &cr, const OpMeExpr &opMeExpr, int32 value); + uint32 ComputeTripCountWithSimpleConstCR(const OpMeExpr &opMeExpr, int32 value, int32 start, int32 stride) const; +}; +} // namespace maple +#endif // MAPLE_ME_INCLUDE_SCALAR_ANALYSIS_H \ No newline at end of file diff --git a/src/mapleall/maple_me/include/me_subsum_rc.h b/src/mapleall/maple_me/include/me_subsum_rc.h new file mode 100644 index 0000000000000000000000000000000000000000..2e3d9e969b4b41bc6e26034ebe52f187f3e5b5f6 --- /dev/null +++ b/src/mapleall/maple_me/include/me_subsum_rc.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_ME_SUBSUM_RC_H +#define MAPLE_ME_INCLUDE_ME_SUBSUM_RC_H +#include "me_ssu_pre.h" + +namespace maple { +class DassignStmtPtrComparator { + public: + bool operator()(const DassignMeStmt *stmtA, const DassignMeStmt *stmtB) const { + ASSERT_NOT_NULL(stmtA); + ASSERT_NOT_NULL(stmtB); + ASSERT_NOT_NULL(stmtA->GetLHS()); + ASSERT_NOT_NULL(stmtB->GetLHS()); + return static_cast(stmtA->GetLHS())->GetVstIdx() < + static_cast(stmtB->GetLHS())->GetVstIdx(); + } +}; + +class SubsumRC : public MeSSUPre { + public: + SubsumRC(MeFunction &f, Dominance &dom, MemPool &mp, bool enabledDebug) + : MeSSUPre(f, dom, mp, kSubsumePre, enabledDebug), + candMap(spreAllocator.Adapter()), + bbVisited(f.GetAllBBs().size(), false, spreAllocator.Adapter()), + verstCantSubsum(f.GetIRMap()->GetVerst2MeExprTable().size(), false, spreAllocator.Adapter()) {} + + virtual ~SubsumRC() = default; + void RunSSUPre(); + + protected: + MapleMap candMap; + MapleVector bbVisited; + MapleVector verstCantSubsum; + + private: + void SetCantSubsum(); + // step 6 methods + void ReplaceExpr(BB &bb, const MeExpr &var, MeExpr ®); + void SubsumeRC(MeStmt &stmt); + // step 0 methods + void CreateRealOcc(VarMeExpr &varX, DassignMeStmt &meStmt, MeStmt &decRef); + void BuildRealOccs(MeStmt &stmt, BB &bb); + void BuildWorkListBB(BB *bb) override; + void PerCandInit() override {} + void CodeMotion() override {} + bool IsRhsPostDominateLhs(const SOcc &rhsOcc, const VarMeExpr &lhs) const; +}; + +class MeDoSubsumRC : public MeFuncPhase { + public: + explicit MeDoSubsumRC(MePhaseID id) : MeFuncPhase(id) {} + virtual ~MeDoSubsumRC() = default; + AnalysisResult *Run(MeFunction*, MeFuncResultMgr*, ModuleResultMgr*) override; + std::string PhaseName() const override { + return "subsumrc"; + } +}; +} // namespace maple +#endif // MAPLE_ME_INCLUDE_ME_SUBSUM_RC_H diff --git a/src/mapleall/maple_me/include/meconstprop.h b/src/mapleall/maple_me/include/meconstprop.h new file mode 100644 index 0000000000000000000000000000000000000000..7025ae8f0e43ce6b0dc1dc2139cb09d912694a4a --- /dev/null +++ b/src/mapleall/maple_me/include/meconstprop.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) [2019] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_MECONSTPROP_H +#define MAPLE_ME_INCLUDE_MECONSTPROP_H +#include "me_ir.h" +#include "me_phase.h" + +namespace maple { +class MeConstProp { + public: + MeConstProp() = default; + + virtual ~MeConstProp() = default; + void IntraConstProp() const; + void InterConstProp() const; +}; + +class MeDoIntraConstProp : public MeFuncPhase { + public: + explicit MeDoIntraConstProp(MePhaseID id) : MeFuncPhase(id) {} + + virtual ~MeDoIntraConstProp() = default; + AnalysisResult *Run(MeFunction *func, MeFuncResultMgr *frm, ModuleResultMgr *mrm) override; + std::string PhaseName() const override { + return "intraconstantpropagation"; + } +}; + +class MeDoInterConstProp : public MeFuncPhase { + public: + explicit MeDoInterConstProp(MePhaseID id) : MeFuncPhase(id) {} + + virtual ~MeDoInterConstProp() = default; + AnalysisResult *Run(MeFunction *func, MeFuncResultMgr *frm, ModuleResultMgr *mrm) override; + std::string PhaseName() const override { + return "interconstantpropagation"; + } +}; +} // namespace maple +#endif // MAPLE_ME_INCLUDE_MECONSTPROP_H diff --git a/src/mapleall/maple_me/include/ssa_epre.h b/src/mapleall/maple_me/include/ssa_epre.h index d3f730cddb78e11c58be4522823ac46a8dc11fcb..4596a4822da937efe2156c981a20116cbd1818b6 100644 --- a/src/mapleall/maple_me/include/ssa_epre.h +++ b/src/mapleall/maple_me/include/ssa_epre.h @@ -28,6 +28,7 @@ class SSAEPre : public SSAPre { private: void GenerateSaveLHSRealocc(MeRealOcc &realOcc, MeExpr ®OrVar); void GenerateSaveRealOcc(MeRealOcc &realOcc); + bool ReserveCalFuncAddrForDecouple(MeExpr &meExpr) const; void GenerateReloadRealOcc(MeRealOcc &realOcc); MeExpr *PhiOpndFromRes(MeRealOcc &realZ, size_t j) const; void ComputeVarAndDfPhis(); diff --git a/src/mapleall/maple_me/include/sync_select.h b/src/mapleall/maple_me/include/sync_select.h new file mode 100644 index 0000000000000000000000000000000000000000..e452b0a6a4f84c092256e06c1d9230e2b0e291c5 --- /dev/null +++ b/src/mapleall/maple_me/include/sync_select.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MAPLE_ME_INCLUDE_SYNCSELECT_H +#define MAPLE_ME_INCLUDE_SYNCSELECT_H +#include "me_function.h" +#include "mir_module.h" +#include "me_phase.h" + +namespace maple { +class MeDoSyncSelect : public MeFuncPhase { + public: + explicit MeDoSyncSelect(MePhaseID id) : MeFuncPhase(id) {} + + virtual ~MeDoSyncSelect() = default; + AnalysisResult *Run(MeFunction *func, MeFuncResultMgr *frm, ModuleResultMgr *mrm) override; + std::string PhaseName() const override { + return "syncselect"; + } +}; +} // namespace maple +#endif // MAPLE_ME_INCLUDE_SYNCSELECT_H diff --git a/src/mapleall/maple_me/src/alias_class.cpp b/src/mapleall/maple_me/src/alias_class.cpp index a103cf3c0cabc614ff0449287fe0806f9f8e4d32..fb280d72c2f3ce68e12094445a6a4de048fe0cfa 100644 --- a/src/mapleall/maple_me/src/alias_class.cpp +++ b/src/mapleall/maple_me/src/alias_class.cpp @@ -22,6 +22,9 @@ namespace { using namespace maple; +const std::set kNoSideEffectWhiteList { + "Landroid_2Fos_2FParcel_24ReadWriteHelper_3B_7CwriteString_7C_28Landroid_2Fos_2FParcel_3BLjava_2Flang_2FString_3B_29V", +}; inline bool IsReadOnlyOst(const OriginalSt &ost) { return ost.GetMIRSymbol()->HasAddrOfValues(); @@ -46,6 +49,10 @@ bool AliasClass::CallHasNoSideEffectOrPrivateDefEffect(const CallNode &stmt, Fun hasAttr = (attrKind == FUNCATTR_nosideeffect) ? (callee->IsNoDefEffect() && callee->IsNoDefArgEffect()) : callee->IsNoPrivateDefEffect(); } + if (!hasAttr && attrKind == FUNCATTR_nosideeffect) { + const std::string &funcName = callee->GetName(); + hasAttr = kNoSideEffectWhiteList.find(funcName) != kNoSideEffectWhiteList.end(); + } return hasAttr; } @@ -418,6 +425,32 @@ void AliasClass::UnionForNotAllDefsSeen() { } } +void AliasClass::UnionForAggAndFields() { + // key: index of MIRSymbol; value: id of alias element. + std::map> symbol2AEs; + + // collect alias elements with same MIRSymbol, and the ost is zero level. + for (auto *aliasElem : id2Elem) { + OriginalSt &ost = aliasElem->GetOriginalSt(); + if (ost.GetIndirectLev() == 0) { + (void)symbol2AEs[ost.GetMIRSymbol()->GetStIndex()].insert(aliasElem->GetClassID()); + } + } + + // union alias elements of Agg(fieldID == 0) and fields(fieldID > 0). + for (auto &sym2AE : symbol2AEs) { + auto &aesWithSameSymbol = sym2AE.second; + for (auto idA : aesWithSameSymbol) { + if (id2Elem[idA]->GetOriginalSt().GetFieldID() == 0 && aesWithSameSymbol.size() > 1) { + (void)aesWithSameSymbol.erase(idA); + for (auto idB : aesWithSameSymbol) { + unionFind.Union(idA, idB); + } + break; + } + } + } +} // fabricate the imaginary not_all_def_seen AliasElem AliasElem *AliasClass::FindOrCreateDummyNADSAe() { diff --git a/src/mapleall/maple_me/src/ipa_side_effect.cpp b/src/mapleall/maple_me/src/ipa_side_effect.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8095e1a6aa4715248702105c8425d44bea2af65b --- /dev/null +++ b/src/mapleall/maple_me/src/ipa_side_effect.cpp @@ -0,0 +1,1132 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "ipa_side_effect.h" +#include "me_function.h" +#include "ver_symbol.h" +#include "dominance.h" +#include "me_ir.h" +#include "me_phase.h" +#include "me_irmap.h" +#include "dominance.h" + +// IPA sideeffect analysis +// Default value: +// Mirfunc->attribute: not Pure, defArg, def, return Global, throw eh, return Arg, def private +// ipasideeffect.cpp: pure, no defArg, no Def, no Return Global, no throw eh, no return Arg, no def private +// For a close environment which consists of many modules: +// 1. Focus on Pure, DefGlobal, DefArg, ThrowException +// 2. Build SCC in one function, propgate Arg or Global attribute +// For a open environment with decouple and dynamic class load: +using namespace maple; +namespace { +const FuncWithSideEffect kMrtList[] { +#include "mrt_info.def" +}; +size_t mrtListSz = 0; +std::map mrtPuIdx; +// keep track of union of all side effects in a SCC +std::map sccSe; +const SCCNode *currSccNode = nullptr; +uint32 cgNodeCount = 0; +} + +namespace maple { +IpaSideEffect::IpaSideEffect(MeFunction &mf, MemPool *memPool, CallGraph &callGraph, Dominance &dom) + : isSeen(false), + notPure(false), + hasDefArg(false), + hasDef(false), + hasRetGlobal(false), + hasThrException(false), + hasRetArg(false), + hasPrivateDef(false), + isGlobal(false), + isArg(false), + meFunc(mf), + alloc(memPool), + callGraph(callGraph), + sccId(0), + dominance(dom) {} + +void IpaSideEffect::SetEffectsTrue() { + notPure = true; + hasDefArg = true; + hasDef = true; + hasRetGlobal = true; + hasThrException = true; + hasRetArg = true; + hasPrivateDef = true; +} + +bool IpaSideEffect::IsIgnoreMethod(const MIRFunction &func) { + // Ignore if virtual or no method + if (func.IsAbstract()) { + return true; + } + Klass *klass = callGraph.GetKlassh()->GetKlassFromFunc(&func); + if (klass == nullptr) { + // An array, must have method, but has all effects + SetEffectsTrue(); + return true; + } + const auto &methods = klass->GetMethods(); + return std::find(methods.begin(), methods.end(), &func) == methods.end(); +} + +void IpaSideEffect::CopySccSideEffectToAllFunctions(SCCNode &scc, uint8 seMask) { + // For all members of the SCC, copy the sum of the side effect of SCC to each member func. + for (auto &sccIt : scc.GetCGNodes()) { + CGNode *cgNode = sccIt; + MIRFunction *func = cgNode->GetMIRFunction(); + if (mrtPuIdx.find(func->GetPuidx()) != mrtPuIdx.end()) { + CHECK_FATAL(false, "Pay attention, manual defined func in a SCC. %s", func->GetName().c_str()); + } + CHECK_FATAL(func->IsIpaSeen(), "Must have been processed."); + CHECK_FATAL(func->IsPure() || (seMask & kNotPure) == kNotPure, "Must be true."); + CHECK_FATAL(func->IsNoDefEffect() || (seMask & kHasDef) == kHasDef, "Must be true."); + CHECK_FATAL(func->IsNoThrowException() || (seMask & kHasThrow) == kHasThrow, "Must be true."); + CHECK_FATAL(func->IsNoPrivateDefEffect() || (seMask & kHasPrivateDef) == kHasPrivateDef, "Must be true."); + if (seMask & kNotPure) { + func->UnsetPure(); + } + if (seMask & kHasDef) { + func->UnsetNoDefEffect(); + } + if (seMask & kHasThrow) { + func->UnsetNoThrowException(); + } + if (seMask & kHasPrivateDef) { + func->UnsetNoPrivateDefEffect(); + } + } +} + +void IpaSideEffect::GetEffectFromCallee(MIRFunction &callee, const MIRFunction &caller) { + uint32 calleeScc = GetOrSetSCCNodeId(callee); + if (IsCallingIntoSCC(calleeScc)) { + // Call graph ensures that all methods in SCC are visited before a call into the SCC. + auto it = sccSe.find(calleeScc); + CHECK_FATAL(it != sccSe.end(), "Sideeffect of scc must have been set."); + uint8 mask = it->second; + + hasDefArg = hasDefArg || (mask & kHasDefArg); + hasDef = hasDef || (mask & kHasDef); + hasThrException = hasThrException || (mask & kHasThrow); + hasRetArg = hasRetArg || (mask & kHasRetArg); + hasPrivateDef = hasPrivateDef || (mask & kHasPrivateDef); + } else if (callee.IsIpaSeen()) { + notPure = notPure || !callee.IsPure(); + hasDefArg = hasDefArg || !callee.IsNoDefArgEffect(); + hasDef = hasDef || !callee.IsNoDefEffect(); + hasRetGlobal = hasRetGlobal || !callee.IsNoRetGlobal(); + hasThrException = hasThrException || !callee.IsNoThrowException(); + hasRetArg = hasRetArg || !callee.IsNoRetArg(); + hasPrivateDef = hasPrivateDef || !callee.IsNoPrivateDefEffect(); + } else if (MatchPuidxAndSetSideEffects(callee.GetPuidx()) == false) { + // function was not compiled before and it is not one of the predetermined + // sideeffect functions, then assume + // - native function : no side effects + // - non-native function : all side effects + if (!callee.IsNative()) { + SetEffectsTrue(); + return; + } + // If the caller and callee are in the same SCC, then its ok, since + // the side effect of SCC is the sum of the methods in the SCC. The + // side effect of the not yet visited method will be added in the + // combined SCC side effects later when it is actually visited. + if (callee.GetName() == caller.GetName()) { + return; + } + // !!!!!!!!!!!!MUST PRINT WARNING!!!!!!!!!!! + if (calleeScc != sccId && !MeOption::quiet) { + LogInfo::MapleLogger() << "WARNING: cross scc default no side effects " << callee.GetName() + << " Native-function\n"; + } + } +} + +bool IpaSideEffect::MEAnalyzeDefExpr(MeExpr &baseExprMe, std::vector &varVector) { + CHECK_FATAL(baseExprMe.GetOp() == OP_dread, "Must be dread"); + auto &baseExpr = static_cast(baseExprMe); + const OriginalSt *ostSymbol = meFunc.GetMeSSATab()->GetOriginalStFromID(baseExpr.GetOstIdx()); + if (!ostSymbol->IsLocal()) { + return true; + } + switch (baseExpr.GetDefBy()) { + case kDefByStmt: { + if (baseExpr.GetDefStmt() == nullptr) { + return true; + } + MeStmt *defStmt = baseExpr.GetDefStmt(); + CHECK_FATAL(defStmt->GetOp() == OP_dassign, "Must be dassign"); + auto *dassignMeStmt = static_cast(defStmt); + switch (dassignMeStmt->GetRHS()->GetOp()) { + case OP_dread: { + for (auto it = varVector.begin(); it != varVector.end(); ++it) { + // Cycle + if (*it == dassignMeStmt->GetRHS()) { + return true; + } + } + varVector.push_back(dassignMeStmt->GetRHS()); + if (MEAnalyzeDefExpr(*dassignMeStmt->GetRHS(), varVector)) { + return true; + } + break; + } + case OP_gcmallocjarray: + case OP_gcmalloc: + case OP_constval: { + return false; + } + case OP_iread: { + return true; + } + case OP_cvt: + case OP_retype: { + auto *node = static_cast(dassignMeStmt->GetRHS()); + CHECK_FATAL(node->GetOpnd(0)->GetOp() == OP_dread, "must be dread"); + for (auto it = varVector.begin(); it != varVector.end(); ++it) { + // Cycle + if (*it == node->GetOpnd(0)) { + return true; + } + } + varVector.push_back(node->GetOpnd(0)); + if (MEAnalyzeDefExpr(*node->GetOpnd(0), varVector)) { + return true; + } + break; + } + default: + CHECK_FATAL(false, "NYI"); + } + break; + } + case kDefByPhi: { + for (auto *expr : baseExpr.GetDefPhi().GetOpnds()) { + if (expr->GetMeOp() != kMeOpVar) { + continue; + } + if (std::find(varVector.begin(), varVector.end(), &baseExpr) != varVector.end()) { + return true; + } + varVector.push_back(expr); + if (MEAnalyzeDefExpr(*expr, varVector)) { + return true; + } + } + break; + } + case kDefByChi: + case kDefByMustDef: { + // Defined symbol is not a global + return false; + } + default: { + return true; + } + } + return false; +} + +// Def global variable or formal parameter +bool IpaSideEffect::AnalyzeDefExpr(VersionSt &baseVar, std::vector &varVector) { + if (!baseVar.GetOst()->IsLocal()) { + return true; + } + switch (baseVar.GetDefType()) { + case VersionSt::kAssign: { + if (baseVar.GetAssignNode() == nullptr) { + return true; + } + BaseNode *rhs = baseVar.GetAssignNode()->GetRHS(); + ASSERT_NOT_NULL(rhs); + switch (rhs->GetOpCode()) { + case OP_dread: { + VersionSt *st = (static_cast(rhs))->GetSSAVar(); + for (auto it = varVector.begin(); it != varVector.end(); ++it) { + // Cycle + if (*it == st) { + return true; + } + } + varVector.push_back(st); + if (AnalyzeDefExpr(*st, varVector)) { + return true; + } + break; + } + case OP_gcmallocjarray: + case OP_gcmalloc: + case OP_constval: { + return false; + } + case OP_iread: { + return true; + } + case OP_cvt: + case OP_retype: { + auto *node = static_cast(rhs); + CHECK_FATAL(node->Opnd(0)->GetOpCode() == OP_dread, "must be dread"); + VersionSt *st = (static_cast(node->Opnd(0)))->GetSSAVar(); + for (auto it = varVector.begin(); it != varVector.end(); ++it) { + // Cycle + if (*it == st) { + return true; + } + } + varVector.push_back(st); + if (AnalyzeDefExpr(*st, varVector)) { + return true; + } + break; + } + default: + CHECK_FATAL(false, "NYI"); + } + break; + } + // case VersionSt::Regassign: + case VersionSt::kPhi: { + for (size_t i = 0; i < baseVar.GetPhi()->GetPhiOpnds().size(); ++i) { + VersionSt *st = baseVar.GetPhi()->GetPhiOpnd(i); + for (auto it = varVector.begin(); it != varVector.end(); ++it) { + // Cycle + if (*it == st) { + return true; + } + } + varVector.push_back(st); + if (AnalyzeDefExpr(*st, varVector)) { + return true; + } + } + break; + } + case VersionSt::kMayDef: + case VersionSt::kMustDef: { + return true; + } + default: { + CHECK_FATAL(false, "NYI"); + break; + } + } + return false; +} + +bool IpaSideEffect::MatchPuidxAndSetSideEffects(PUIdx idx) { + if (idx == 0) { + return false; + } + auto mrtIt = mrtPuIdx.find(idx); + if (mrtIt == mrtPuIdx.end()) { + return false; + } + uint8 mrtSe = mrtIt->second; + notPure = notPure || !(mrtSe & kPure); + hasDefArg = hasDefArg || (mrtSe & kHasDefArg); + hasDef = hasDef || (mrtSe & kHasDef); + hasRetGlobal = hasRetGlobal || (mrtSe & kHasRetGlobal); + hasThrException = hasThrException || (mrtSe & kHasThrow); + hasRetArg = hasRetArg || (mrtSe & kHasRetArg); + hasPrivateDef = hasPrivateDef || (mrtSe & kHasPrivateDef); + return true; +} + + +bool IpaSideEffect::IsPureFromSummary(const MIRFunction &func) const { + const std::string &funcName = func.GetName(); + return funcName.find("_7ChashCode_7C") != std::string::npos || + funcName.find("_7CgetClass_7C") != std::string::npos || + funcName.find("_7CgetName_7C") != std::string::npos || + funcName.find("_7CtoString_7C") != std::string::npos || + funcName.find("_7CvalueOf_7C") != std::string::npos; +} + + +void IpaSideEffect::ReadSummary() { + if (mrtListSz != 0) { + return; + } + mrtListSz = sizeof(kMrtList) / sizeof(FuncWithSideEffect); + for (size_t i = 0; i < mrtListSz; i++) { + MIRSymbol *sym = GlobalTables::GetGsymTable().GetSymbolFromStrIdx( + GlobalTables::GetStrTable().GetStrIdxFromName(kMrtList[i].GetFuncName())); + if (sym != nullptr) { + MIRFunction *func = sym->GetFunction(); + uint8 seMask = 0; + if (kMrtList[i].GetPure()) { + seMask |= kPure; + func->SetPure(); + } + if (kMrtList[i].GetDefArg()) { + seMask |= kHasDefArg; + } else { + func->SetNoDefArgEffect(); + } + if (kMrtList[i].GetDef()) { + seMask |= kHasDef; + } else { + func->SetNoDefEffect(); + } + if (kMrtList[i].GetRetGlobal()) { + seMask |= kHasRetGlobal; + } else { + func->SetNoRetGlobal(); + } + if (kMrtList[i].GetException()) { + seMask |= kHasThrow; + } else { + func->SetNoThrowException(); + } + if (kMrtList[i].GetRetArg()) { + seMask |= kHasRetArg; + } else { + func->SetNoRetArg(); + } + if (kMrtList[i].GetPrivateDef()) { + seMask |= kHasPrivateDef; + } else { + func->SetNoPrivateDefEffect(); + } + func->SetIpaSeen(); + mrtPuIdx[func->GetPuidx()] = seMask; + } + } +} + +uint32 IpaSideEffect::GetOrSetSCCNodeId(MIRFunction &mirfunc) { + if (mirfunc.GetSCCId() != -1) { + return static_cast(mirfunc.GetSCCId()); + } + auto it = callGraph.GetNodesMap().find(&mirfunc); + if (it != callGraph.GetNodesMap().end()) { + CGNode *callGraphNode = it->second; + SCCNode *sccn = callGraphNode->GetSCCNode(); + if (sccn != nullptr && sccn->GetCGNodes().size() > 1) { + mirfunc.SetSCCId(static_cast(sccn->GetID())); + return sccn->GetID(); + } + } + mirfunc.SetSCCId(0); + return 0; +} + +bool IpaSideEffect::IsCallingIntoSCC(uint32 id) const { + if (id == 0) { + return false; + } + if (sccId == 0) { + return false; + } + return (id != sccId); +} + +void IpaSideEffect::UpdateExternalFuncSideEffects(MIRFunction &func) { + if (!func.IsIpaSeen()) { + return; + } + // This is an external caller read in from an already processed mplt file. + // Need to process all callee and update the caller side effects. + notPure = notPure || !func.IsPure(); + hasDefArg = hasDefArg || !func.IsNoDefArgEffect(); + hasDef = hasDef || !func.IsNoDefEffect(); + hasRetGlobal = hasRetGlobal || !func.IsNoRetGlobal(); + hasThrException = hasThrException || !func.IsNoThrowException(); + hasRetArg = hasRetArg || !func.IsNoRetArg(); + hasPrivateDef = hasPrivateDef || !func.IsNoPrivateDefEffect(); + auto callerIt = callGraph.GetNodesMap().find(&func); + CHECK_FATAL(callerIt != callGraph.GetNodesMap().end(), "CGNode not found."); + CGNode *cgNode = callerIt->second; + for (auto &callSite : cgNode->GetCallee()) { + // IPASEEN == true, body == NULL; + // IPASEEN == true, body != NULL; + // IPASEEN == false, body != NULL, ignore + // IPASEEN == false, body == NULL, most conservative + uint8 mask1 = 0; + uint8 mask2 = 0; + + for (auto &cgIt : *callSite.second) { + MIRFunction *callee = cgIt->GetMIRFunction(); + if (callee->IsIpaSeen()) { + auto &mask = (callee->GetBody() == nullptr) ? mask1 : mask2; + mask |= (!callee->IsNoDefArgEffect() ? kHasDefArg : 0) | + (!callee->IsNoDefEffect() ? kHasDef : 0) | + (!callee->IsNoRetGlobal() ? kHasRetGlobal : 0) | + (!callee->IsNoThrowException() ? kHasThrow : 0) | + (!callee->IsNoRetArg() ? kHasRetArg : 0) | + (!callee->IsNoPrivateDefEffect() ? kHasPrivateDef : 0); + } else if (!callee->IsIpaSeen() && callee->GetBody() == nullptr) { + if (!IsPureFromSummary(*callee)) { // Set pure + hasPrivateDef = true; + hasThrException = true; + hasDef = true; + } + } + } + if ((((mask1 & kHasDef) == 0) && ((mask2 & kHasDef) == kHasDef)) || + (((mask1 & kHasDefArg) == 0) && ((mask2 & kHasDefArg) == kHasDefArg))) { + CHECK_FATAL(false, "Need to update"); + } + } +} + +// Whether or not the expr is reading global or arg variables +void IpaSideEffect::AnalyzeExpr(MeExpr &expr, + std::set &globalExprs, std::set &argExprs, + std::set &nextLevelGlobalExprs, std::set &nextLevelArgExprs) { + bool isGlobalTmp = false; + bool isArgTmp = false; + if (expr.GetPrimType() != PTY_ptr && expr.GetPrimType() != PTY_ref) { + return; + } + Opcode op = expr.GetOp(); + for (size_t i = 0; i < expr.GetNumOpnds(); ++i) { + AnalyzeExpr(*expr.GetOpnd(i), globalExprs, argExprs, nextLevelGlobalExprs, nextLevelArgExprs); + } + switch (op) { + case OP_iread: { + hasThrException = true; + IvarMeExpr &ivarMeExpr = static_cast(expr); + MeExpr *tmpBase = ivarMeExpr.GetBase(); + CHECK_FATAL(tmpBase->GetOp() == OP_dread || tmpBase->GetOp() == OP_array, "Must be dread or array"); + MeExpr *baseNode = nullptr; + if (tmpBase->GetOp() == OP_array) { + NaryMeExpr *arrayNode = static_cast(tmpBase); + CHECK_FATAL(arrayNode->GetOpnd(0)->GetOp() == OP_dread, "Must be dread"); + baseNode = arrayNode->GetOpnd(0); + } else { + baseNode = tmpBase; + } + CHECK_FATAL(baseNode->GetOp() == OP_dread, "must be dread"); + VarMeExpr *dread = static_cast(baseNode); + if (nextLevelGlobalExprs.find(dread) != nextLevelGlobalExprs.end()) { + isGlobalTmp = true; + } + if (nextLevelArgExprs.find(dread) != nextLevelArgExprs.end()) { + isArgTmp = true; + } + break; + } + case OP_array: { + hasThrException = true; + break; + } + case OP_intrinsicop: { + NaryMeExpr &intrnNode = static_cast(expr); + if (intrnNode.GetIntrinsic() != INTRN_JAVA_MERGE) { + CHECK_FATAL(false, "NYI"); + } + break; + } + case OP_div: + case OP_rem: + case OP_gcmalloc: + case OP_gcmallocjarray: + case OP_gcpermallocjarray: + case OP_gcpermalloc: { + hasThrException = true; + isGlobalTmp = false; + isArgTmp = false; + break; + } + case OP_dread: { + VarMeExpr &dread = static_cast(expr); + const OriginalSt *ost = meFunc.GetMeSSATab()->GetSymbolOriginalStFromID(dread.GetOstIdx()); + if ((ost->GetMIRSymbol()->IsGlobal() && !ost->GetMIRSymbol()->IsConst() && !ost->GetMIRSymbol()->IsFinal()) || + globalExprs.find(&dread) != globalExprs.end()) { + isGlobalTmp = true; + } else if (meFunc.GetMirFunc()->IsAFormal(ost->GetMIRSymbol()) || argExprs.find(&dread) != argExprs.end()) { + isArgTmp = true; + } + break; + } + case OP_constval: + case OP_cvt: + case OP_shl: + case OP_lshr: + case OP_band: + case OP_add: + case OP_ashr: + case OP_bior: + case OP_bxor: + case OP_cand: + case OP_cior: + case OP_cmp: + case OP_cmpg: + case OP_cmpl: + case OP_addrof: + case OP_sub: { + isGlobalTmp = false; + isArgTmp = false; + break; + } + case OP_retype: + case OP_regread: { + break; + } + case OP_intrinsicopwithtype: { + NaryMeExpr &instrinsicExpr = static_cast(expr); + if (instrinsicExpr.GetIntrinsic() == INTRN_JAVA_CONST_CLASS || + instrinsicExpr.GetIntrinsic() == INTRN_JAVA_INSTANCE_OF) { + isGlobalTmp = false; + isArgTmp = false; + } else { + CHECK_FATAL(false, "NYI"); + } + break; + } + default: { + CHECK_FATAL(false, "NYI"); + } + } + isGlobal = isGlobal || isGlobalTmp; + isArg = isArg || isArgTmp; +} + +bool IpaSideEffect::UpdateSideEffectWithStmt(MeStmt &meStmt, + std::set &globalExprs, std::set &argExprs, + std::set &nextLevelGlobalExprs, + std::set &nextLevelArgExprs) { + isArg = false; + isGlobal = false; + Opcode op = meStmt.GetOp(); + switch (op) { + case OP_return: { + for (size_t i = 0; i < meStmt.NumMeStmtOpnds(); ++i) { + AnalyzeExpr(*meStmt.GetOpnd(i), globalExprs, argExprs, nextLevelGlobalExprs, nextLevelArgExprs); + } + if (isGlobal) { + hasRetGlobal = true; + } + if (isArg) { + hasRetArg = true; + } + break; + } + case OP_iassign: { + for (size_t i = 1; i < meStmt.NumMeStmtOpnds(); ++i) { // Ignore base (LHR), both array or structure + AnalyzeExpr(*meStmt.GetOpnd(i), globalExprs, argExprs, nextLevelGlobalExprs, nextLevelArgExprs); + } + hasThrException = true; + IassignMeStmt &iasNode = static_cast(meStmt); + CHECK_FATAL(iasNode.GetLHSVal()->GetBase()->GetOp() == OP_dread || + iasNode.GetLHSVal()->GetBase()->GetOp() == OP_array, "Must be dread"); + MeExpr *baseNode = nullptr; + if (iasNode.GetLHSVal()->GetBase()->GetOp() == OP_array) { + NaryMeExpr *arrayNode = static_cast(iasNode.GetLHSVal()->GetBase()); + CHECK_FATAL(arrayNode->GetOpnd(0)->GetOp() == OP_dread, "Must be dread"); + baseNode = arrayNode->GetOpnd(0); + } else { + baseNode = iasNode.GetLHSVal()->GetBase(); + } + VarMeExpr *dread = static_cast(baseNode); + const OriginalSt *ost = meFunc.GetMeSSATab()->GetSymbolOriginalStFromID(dread->GetOstIdx()); + if (ost->GetMIRSymbol()->IsGlobal() || globalExprs.find(dread) != globalExprs.end()) { + SetHasDef(); + } else if (meFunc.GetMirFunc()->IsAFormal(ost->GetMIRSymbol()) || argExprs.find(dread) != argExprs.end()) { + hasDefArg = true; + } + if (isGlobal) { + (void)nextLevelGlobalExprs.insert(dread); + } + if (isArg) { + (void)nextLevelArgExprs.insert(dread); + } + std::vector varVector; + if (MEAnalyzeDefExpr(*dread, varVector)) { + MIRType *baseType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(iasNode.GetTyIdx()); + MIRType *pType = static_cast(baseType)->GetPointedType(); + if (pType != nullptr && pType->IsInstanceOfMIRStructType()) { + MIRStructType *structType = static_cast(pType); + FieldAttrs fattrs = structType->GetFieldAttrs(iasNode.GetLHSVal()->GetFieldID()); + if (fattrs.GetAttr(FLDATTR_private)) { + hasPrivateDef = true; + } + } + } + break; + } + case OP_throw: { + hasThrException = true; + break; + } + case OP_intrinsiccall: + case OP_intrinsiccallwithtype: { + IntrinsiccallMeStmt &callNode = static_cast(meStmt); + if (callNode.GetIntrinsic() != INTRN_JAVA_CLINIT_CHECK) { + CHECK_FATAL(false, "NYI"); + } + break; + } + case OP_intrinsiccallassigned: + case OP_intrinsiccallwithtypeassigned: { + for (size_t i = 0; i < meStmt.NumMeStmtOpnds(); ++i) { + AnalyzeExpr(*meStmt.GetOpnd(i), globalExprs, argExprs, nextLevelGlobalExprs, nextLevelArgExprs); + } + IntrinsiccallMeStmt &callNode = static_cast(meStmt); + if (callNode.GetIntrinsic() == INTRN_JAVA_CHECK_CAST) { + hasThrException = true; + MeExpr *lhs = callNode.GetAssignedLHS(); + CHECK_NULL_FATAL(lhs); + CHECK_FATAL(lhs->GetOp() == OP_dread, "Must be dread."); + VarMeExpr *lhsVar = static_cast(lhs); + const OriginalSt *ost = meFunc.GetMeSSATab()->GetSymbolOriginalStFromID(lhsVar->GetOstIdx()); + if (ost->GetMIRSymbol()->IsGlobal()) { + SetHasDef(); + } + if (isGlobal) { + (void)globalExprs.insert(lhsVar); + } + if (isArg) { + (void)argExprs.insert(lhsVar); + } + } else if (callNode.GetIntrinsic() == INTRN_JAVA_ARRAY_FILL || + callNode.GetIntrinsic() == INTRN_JAVA_FILL_NEW_ARRAY) { + hasThrException = true; + MeExpr *lhs = meStmt.GetOpnd(0); + CHECK_FATAL(lhs->GetOp() == OP_dread, "Must be dread."); + VarMeExpr *lhsVar = static_cast(lhs); + const OriginalSt *ost = meFunc.GetMeSSATab()->GetSymbolOriginalStFromID(lhsVar->GetOstIdx()); + if (ost->GetMIRSymbol()->IsGlobal()) { + SetHasDef(); + } + if (isGlobal) { + (void)globalExprs.insert(lhsVar); + } + if (isArg) { + (void)argExprs.insert(lhsVar); + } + } else if (callNode.GetIntrinsic() == INTRN_JAVA_POLYMORPHIC_CALL) { + hasPrivateDef = hasThrException = true; + SetHasDef(); + CallMeStmt &callMeStmt = static_cast(meStmt); + MeExpr *lhs = callMeStmt.GetAssignedLHS(); + if (lhs != nullptr) { + CHECK_FATAL(lhs->GetOp() == OP_dread, "Must be dread."); + VarMeExpr *lhsVar = static_cast(lhs); + (void)globalExprs.insert(lhsVar); + if (isArg) { + (void)argExprs.insert(lhsVar); + } + } + if (isArg) { + hasDefArg = true; + } + } else { + CHECK_FATAL(false, "NYI"); + } + break; + } + case OP_dassign: { // Pass by value, special case is addrof C_str and const_array, in java only + for (size_t i = 0; i < meStmt.NumMeStmtOpnds(); ++i) { + AnalyzeExpr(*meStmt.GetOpnd(i), globalExprs, argExprs, nextLevelGlobalExprs, nextLevelArgExprs); + } + DassignMeStmt &dassignNode = static_cast(meStmt); + VarMeExpr *lhsVar = dassignNode.GetVarLHS(); + const OriginalSt *ost = meFunc.GetMeSSATab()->GetSymbolOriginalStFromID(lhsVar->GetOstIdx()); + if (ost->GetMIRSymbol()->IsGlobal()) { + SetHasDef(); + } + if (isGlobal) { + (void)globalExprs.insert(lhsVar); + } + if (isArg) { + (void)argExprs.insert(lhsVar); + } + break; + } + case OP_maydassign: { + for (size_t i = 0; i < meStmt.NumMeStmtOpnds(); ++i) { + AnalyzeExpr(*meStmt.GetOpnd(i), globalExprs, argExprs, nextLevelGlobalExprs, nextLevelArgExprs); + } + MaydassignMeStmt &dassignNode = static_cast(meStmt); + if (dassignNode.GetMayDassignSym()->GetMIRSymbol()->IsGlobal()) { + SetHasDef(); + } + if (isGlobal) { + (void)globalExprs.insert(dassignNode.GetChiList()->begin()->second->GetLHS()); + } + if (isArg) { + (void)argExprs.insert(dassignNode.GetChiList()->begin()->second->GetLHS()); + } + break; + } + case OP_callassigned: + case OP_virtualcallassigned: + case OP_interfacecallassigned: { + CallMeStmt &callMeStmt = static_cast(meStmt); + MIRFunction *callee = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callMeStmt.GetPUIdx()); + if (callee->GetBaseClassName().find(JARRAY_PREFIX_STR) == 0) { + // An array, must have method, but has all effects + SetEffectsTrue(); + break; + } + // If callee is init, process the first argument only. + size_t count = 0; + if (callee->IsConstructor()) { + count = 1; + } else { + count = meStmt.NumMeStmtOpnds(); + } + for (size_t i = 0; i < count; ++i) { + AnalyzeExpr(*meStmt.GetOpnd(i), globalExprs, argExprs, nextLevelGlobalExprs, nextLevelArgExprs); + } + CGNode *callerNode = callGraph.GetCGNode(meFunc.GetMirFunc()); + CHECK_FATAL(callerNode != nullptr, "Must not be null"); + bool defArg = false; + bool returnGlobal = false; + bool returnArg = false; + for (auto &callSite : callerNode->GetCallee()) { + if (callSite.first->GetID() == callMeStmt.GetStmtID()) { + for (auto *calleeNode : *callSite.second) { + MIRFunction *calleeFunc = calleeNode->GetMIRFunction(); + if (calleeFunc->IsIpaSeen()) { + if (IsPureFromSummary(*calleeFunc)) { // Set pure + continue; + } + if (!calleeFunc->IsNoPrivateDefEffect()) { + hasPrivateDef = true; + } + if (!calleeFunc->IsNoThrowException()) { + hasThrException = true; + } + if (!calleeFunc->IsNoDefEffect()) { + SetHasDef(); + } + if (!calleeFunc->IsNoDefArgEffect()) { + defArg = true; + } + if (!calleeFunc->IsNoRetGlobal()) { + returnGlobal = true; + } + if (!calleeFunc->IsNoRetArg()) { + returnArg = true; + } + if (hasPrivateDef && hasThrException && hasDef && defArg && returnGlobal && returnArg) { + break; + } + } else { + if (!IsPureFromSummary(*calleeFunc)) { // Set pure + hasPrivateDef = true; + hasThrException = true; + defArg = true; + returnGlobal = true; + returnArg = true; + SetHasDef(); + } + } + } + if (!isGlobal && !isArg) { + callSite.first->SetAllArgsLocal(); + } + break; + } + } + MeExpr *lhs = callMeStmt.GetAssignedLHS(); + if (lhs != nullptr) { + CHECK_FATAL(lhs->GetOp() == OP_dread, "Must be dread."); + VarMeExpr *lhsVar = static_cast(lhs); + const OriginalSt *ost = meFunc.GetMeSSATab()->GetSymbolOriginalStFromID(lhsVar->GetOstIdx()); + if (ost->GetMIRSymbol()->IsGlobal()) { + SetHasDef(); + } + if (returnGlobal) { + (void)globalExprs.insert(lhsVar); + } else if (returnArg) { + if (isGlobal) { + (void)globalExprs.insert(lhsVar); + } + if (isArg) { + (void)argExprs.insert(lhsVar); + } + } + } + if (defArg) { + if (isGlobal) { + SetHasDef(); + } + if (isArg) { + hasDefArg = true; + } + } + break; + } + case OP_call: + case OP_virtualcall: + case OP_interfacecall: { + for (size_t i = 0; i < meStmt.NumMeStmtOpnds(); ++i) { + AnalyzeExpr(*meStmt.GetOpnd(i), globalExprs, argExprs, nextLevelGlobalExprs, nextLevelArgExprs); + } + CallMeStmt &callMeStmt = static_cast(meStmt); + MIRFunction *callee = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callMeStmt.GetPUIdx()); + if (callee->GetBaseClassName().find(JARRAY_PREFIX_STR) == 0) { + // An array, must have method, but has all effects + SetEffectsTrue(); + break; + } + CGNode *callerNode = callGraph.GetCGNode(meFunc.GetMirFunc()); + CHECK_FATAL(callerNode != nullptr, "Must not be null"); + bool defArg = false; + for (Callsite callSite : callerNode->GetCallee()) { + if (callSite.first->GetID() == callMeStmt.GetStmtID()) { + for (auto *calleeNode : *callSite.second) { + MIRFunction *calleeFunc = calleeNode->GetMIRFunction(); + if (calleeFunc->IsIpaSeen()) { + if (IsPureFromSummary(*calleeFunc)) { // Set pure + continue; + } + if (!calleeFunc->IsNoPrivateDefEffect()) { + hasPrivateDef = true; + } + if (!calleeFunc->IsNoThrowException()) { + hasThrException = true; + } + if (!calleeFunc->IsNoDefEffect()) { + SetHasDef(); + } + if (!calleeFunc->IsNoDefArgEffect()) { + defArg = true; + } + if (hasPrivateDef && hasThrException && hasDef && defArg) { + break; + } + } else { + if (!IsPureFromSummary(*calleeFunc)) { // Set pure + hasPrivateDef = true; + hasThrException = true; + defArg = true; + SetHasDef(); + } + } + } + break; + } + } + if (defArg) { + if (isGlobal) { + SetHasDef(); + } + if (isArg) { + hasDefArg = true; + } + } + break; + } + case OP_virtualicallassigned: + case OP_interfaceicallassigned: + case OP_customcallassigned: + case OP_polymorphiccallassigned: + case OP_icallassigned: { + hasPrivateDef = hasThrException = true; + SetHasDef(); + for (size_t i = 0; i < meStmt.NumMeStmtOpnds(); ++i) { + AnalyzeExpr(*meStmt.GetOpnd(i), globalExprs, argExprs, nextLevelGlobalExprs, nextLevelArgExprs); + } + CallMeStmt &callMeStmt = static_cast(meStmt); + MeExpr *lhs = callMeStmt.GetAssignedLHS(); + if (lhs != nullptr) { + CHECK_FATAL(lhs->GetOp() == OP_dread, "Must be dread."); + VarMeExpr *lhsVar = static_cast(lhs); + (void)globalExprs.insert(lhsVar); + if (isArg) { + (void)argExprs.insert(lhsVar); + } + } + if (isArg) { + hasDefArg = true; + } + break; + } + case OP_virtualicall: + case OP_interfaceicall: + case OP_customcall: + case OP_polymorphiccall: + case OP_icall: { + hasPrivateDef = hasThrException = true; + SetHasDef(); + for (size_t i = 0; i < meStmt.NumMeStmtOpnds(); ++i) { + AnalyzeExpr(*meStmt.GetOpnd(i), globalExprs, argExprs, nextLevelGlobalExprs, nextLevelArgExprs); + } + if (isArg) { + hasDefArg = true; + } + break; + } + case OP_jscatch: + case OP_finally: + case OP_endtry: + case OP_cleanuptry: + case OP_membaracquire: + case OP_membarrelease: + case OP_membarstoreload: + case OP_membarstorestore: + case OP_retsub: + case OP_gosub: + case OP_goto: + case OP_brfalse: + case OP_brtrue: + case OP_comment: + case OP_jstry: + case OP_try: + case OP_catch: + case OP_syncenter: + case OP_syncexit: + case OP_assertnonnull: + case OP_eval: + case OP_free: + case OP_switch: + case OP_label: + break; + default: { + CHECK_FATAL(false, "NYI"); + } + } + return isGlobal; +} + +void IpaSideEffect::DoAnalysis() { + ReadSummary(); // Read once + MIRFunction *func = meFunc.GetMirFunc(); + if (func->IsAbstract() || mrtPuIdx.find(func->GetPuidx()) != mrtPuIdx.end()) { + return; + } + // SCC check + auto it = callGraph.GetNodesMap().find(func); + CHECK_FATAL(it != callGraph.GetNodesMap().end(), "Must have cg node"); + CGNode *cgNode = it->second; + SCCNode *sccNode = cgNode->GetSCCNode(); + CHECK_FATAL(sccNode != nullptr, "Must not be null."); + if (currSccNode == nullptr) { + currSccNode = sccNode; + cgNodeCount = sccNode->GetCGNodes().size(); + } else if (currSccNode == sccNode) { + CHECK_FATAL(cgNodeCount > 0, "cgNodeCount must be larger than 0"); + } else { + currSccNode = sccNode; + cgNodeCount = sccNode->GetCGNodes().size(); + } + bool useGlobal = false; + if (func->GetBody() == nullptr) { // External function from mplt, need to update effects + UpdateExternalFuncSideEffects(*func); + } else { + meFunc.BuildSCC(); + std::set globalExprs; + std::set argExprs; + std::set nextLevelGlobalExprs; + std::set nextLevelArgExprs; + for (size_t i = 0; i < meFunc.GetSccTopologicalVec().size(); ++i) { + SCCOfBBs *scc = meFunc.GetSccTopologicalVec()[i]; + CHECK_FATAL(scc != nullptr, "scc must not be null"); + if (scc->GetBBs().size() > 1) { + meFunc.BBTopologicalSort(*scc); + } + const uint32 maxLoopCount = 2; + unsigned loopCount = scc->GetBBs().size() > 1 ? maxLoopCount : 1; // Loop count + for (unsigned j = 0; j < loopCount; ++j) { + for (BB *bb : scc->GetBBs()) { + if (bb == meFunc.GetCommonEntryBB() || bb == meFunc.GetCommonExitBB()) { + continue; + } + for (auto &meStmt : bb->GetMeStmts()) { + if (UpdateSideEffectWithStmt(meStmt, globalExprs, argExprs, nextLevelGlobalExprs, nextLevelArgExprs)) { + useGlobal = true; + } + } + } + } + } + } + + uint8 mask = 0; + sccId = GetOrSetSCCNodeId(*func); + if (sccId != 0) { + auto itTmp = sccSe.find(sccId); + if (itTmp != sccSe.end()) { + mask = itTmp->second; + } + } + if (hasDefArg || hasDef || useGlobal) { + mask |= kNotPure; + } else { + func->SetPure(); + } + if (!hasDefArg) { + func->SetNoDefArgEffect(); + } + if (hasDef) { + mask |= kHasDef; + } else { + func->SetNoDefEffect(); + } + if (!hasRetGlobal) { + func->SetNoRetGlobal(); + } + if (hasThrException) { + mask |= kHasThrow; + } else { + func->SetNoThrowException(); + } + if (!hasRetArg) { + func->SetNoRetArg(); + } + if (hasPrivateDef) { + mask |= kHasPrivateDef; + } else { + func->SetNoPrivateDefEffect(); + } + func->SetIpaSeen(); + --cgNodeCount; + if (sccId != 0) { + sccSe[sccId] = mask; + } + if (cgNodeCount == 0 && sccNode->GetCGNodes().size() > 1) { + CopySccSideEffectToAllFunctions(*sccNode, mask); + } + // Delete redundant callinfo. func+callType+allargsarelocal + std::unordered_set callInfoHash; + for (auto callSite = cgNode->GetCallee().begin(); callSite != cgNode->GetCallee().end(); ++callSite) { + uint64 key = (static_cast(callSite->first->GetFunc()->GetPuidx()) << 32) + // leftshift 32 bits + (static_cast(callSite->first->GetCallType()) << 16) + // leftshift 16 bits + (callSite->first->AreAllArgsLocal() ? 1 : 0); + if (callInfoHash.find(key) != callInfoHash.end()) { + (void)cgNode->GetCallee().erase(callSite); + --callSite; + } else { + (void)callInfoHash.insert(key); + } + } +} + +AnalysisResult *DoIpaSideEffect::Run(MeFunction *func, MeFuncResultMgr *mfrm, ModuleResultMgr *mrm) { + if (func->GetMirFunc()->IsNative()) { + return nullptr; + } + Dominance *dom = nullptr; + if (func->GetMirFunc()->GetBody() != nullptr) { + dom = static_cast(mfrm->GetAnalysisResult(MeFuncPhase_DOMINANCE, func)); + } + CHECK_FATAL(dom != nullptr, "Dominance must be built."); + CallGraph *callGraph = static_cast(mrm->GetAnalysisResult(MoPhase_CALLGRAPH_ANALYSIS, + &func->GetMIRModule())); + CHECK_FATAL(callGraph != nullptr, "Call graph must be built."); + IpaSideEffect ipaSideEffect(*func, NewMemPool(), *callGraph, *dom); + ipaSideEffect.DoAnalysis(); + return nullptr; +} +} // namespace maple diff --git a/src/mapleall/maple_me/src/irmap_emit.cpp b/src/mapleall/maple_me/src/irmap_emit.cpp index b4dd5d3668cb9589079daeb8e20ef3269d33fbec..790d4dc313b7129e6f57d430c9196a0ce9eb1ee6 100644 --- a/src/mapleall/maple_me/src/irmap_emit.cpp +++ b/src/mapleall/maple_me/src/irmap_emit.cpp @@ -590,6 +590,9 @@ void BB::EmitBB(SSATab &ssaTab, BlockNode &curblk, bool needAnotherPass) { } StmtNode &stmt = meStmt.EmitStmt(ssaTab); curblk.AddStatement(&stmt); + if (&meStmt == &(meStmts.back())) { + ssaTab.GetModule().CurFunction()->SetFreqMap(stmt.GetStmtID(), GetFrequency()); + } } if (GetAttributes(kBBAttrIsTryEnd)) { // generate op_endtry diff --git a/src/mapleall/maple_me/src/me_alias_class.cpp b/src/mapleall/maple_me/src/me_alias_class.cpp index 84b814781a918956babe8287ac151603ef5bcde7..edfa716fabb0ac93d4500e9a3b26a063cf980bf7 100644 --- a/src/mapleall/maple_me/src/me_alias_class.cpp +++ b/src/mapleall/maple_me/src/me_alias_class.cpp @@ -57,6 +57,9 @@ void MeAliasClass::DoAliasAnalysis() { ApplyUnionForPointedTos(); UnionForNotAllDefsSeen(); } + if (!mirModule.IsJavaModule()) { + UnionForAggAndFields(); + } // TBAA if (!MeOption::noTBAA && mirModule.IsJavaModule()) { ReconstructAliasGroups(); diff --git a/src/mapleall/maple_me/src/me_analyze_rc.cpp b/src/mapleall/maple_me/src/me_analyze_rc.cpp index e012f236f9d7c9bab442d365aaaf8225efa9cd92..5f1d2884cb5a3cc8ea25de48ab1f619f0140a492 100644 --- a/src/mapleall/maple_me/src/me_analyze_rc.cpp +++ b/src/mapleall/maple_me/src/me_analyze_rc.cpp @@ -15,6 +15,8 @@ #include "me_analyze_rc.h" #include "me_option.h" #include "me_dominance.h" +#include "me_delegate_rc.h" +#include "me_subsum_rc.h" // This phase analyzes the defs and uses of ref pointers in the function and // performs the following modifications to the code: @@ -449,10 +451,14 @@ AnalysisResult *MeDoAnalyzeRC::Run(MeFunction *func, MeFuncResultMgr *m, ModuleR LogInfo::Info() << "\n============== After ANALYZE RC =============" << '\n'; func->Dump(false); } + if (MeOption::subsumRC && MeOption::rcLowering && MeOption::optLevel > 0) { + (void)m->GetAnalysisResult(MeFuncPhase_SUBSUMRC, func); + } if (!MeOption::noDelegateRC && MeOption::rcLowering && MeOption::optLevel > 0) { m->GetAnalysisResult(MeFuncPhase_DELEGATERC, func); } - if (!MeOption::noCondBasedRC && MeOption::rcLowering && MeOption::optLevel > 0) { + if (!MeOption::noCondBasedRC && !(func->GetHints() & kPlacementRCed) && + MeOption::rcLowering && MeOption::optLevel > 0) { m->GetAnalysisResult(MeFuncPhase_CONDBASEDRC, func); } if (DEBUGFUNC(func)) { diff --git a/src/mapleall/maple_me/src/me_bb_analyze.cpp b/src/mapleall/maple_me/src/me_bb_analyze.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0b8ac346605f66d4882ca39b240e16b1fd063e9d --- /dev/null +++ b/src/mapleall/maple_me/src/me_bb_analyze.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "me_bb_analyze.h" + +namespace maple { + void BBAnalyze::SetHotAndColdBBCountThreshold() { + std::vector times; + auto eIt = func.valid_end(); + for (auto bIt = func.valid_begin(); bIt != eIt; ++bIt) { + auto *bb = *bIt; + times.push_back((bb->GetFrequency())); + } + std::sort(times.begin(), times.end(), std::greater()); + uint32 hotIndex = + static_cast(static_cast(times.size()) / kPrecision * (MeOption::profileBBHotRate)); + uint32 coldIndex = + static_cast(static_cast(times.size()) / kPrecision * (MeOption::profileBBColdRate)); + hotBBCountThreshold = times.at(hotIndex); + coldBBCountThreshold = times.at(coldIndex); + } + + bool BBAnalyze::CheckBBHot(const BBId bbId) { + BB *bb = func.GetBBFromID(bbId); + return bb->GetFrequency() >= hotBBCountThreshold; + } + + bool BBAnalyze::CheckBBCold(const BBId bbId) { + BB *bb = func.GetBBFromID(bbId); + return bb->GetFrequency() <= coldBBCountThreshold; + } + + uint32 BBAnalyze::getHotBBCountThreshold() const { + return hotBBCountThreshold; + } + + uint32 BBAnalyze::getColdBBCountThreshold() const { + return coldBBCountThreshold; + } + + AnalysisResult *MeDoBBAnalyze::Run(MeFunction *func, MeFuncResultMgr *, ModuleResultMgr*) { + MemPool *meBBAnalyze = NewMemPool(); + BBAnalyze *bbAnalyze = meBBAnalyze->New(*meBBAnalyze, *func); + if (func->IsIRProfValid()) { + bbAnalyze->SetHotAndColdBBCountThreshold(); + return bbAnalyze; + } + return nullptr; + } +} // namespace maple \ No newline at end of file diff --git a/src/mapleall/maple_me/src/me_cfg.cpp b/src/mapleall/maple_me/src/me_cfg.cpp index be2da677bea6005e864354147c8b26e4e9bfe7bf..93c8927b7f8b39ae396043020153e5668b030ec1 100644 --- a/src/mapleall/maple_me/src/me_cfg.cpp +++ b/src/mapleall/maple_me/src/me_cfg.cpp @@ -37,10 +37,52 @@ static bool CaseValOfSwitchIsSuccInt(const maple::CaseVector &switchTable) { } namespace maple { +#define MATCH_STMT(stmt, kOpCode) do { \ + while ((stmt) != nullptr && (stmt)->GetOpCode() == OP_comment) { \ + (stmt) = (stmt)->GetNext(); \ + } \ + if ((stmt) == nullptr || (stmt)->GetOpCode() != (kOpCode)) { \ + return false; \ + } \ +} while (0) // END define // determine if need to be replaced by assertnonnull bool MeCFG::IfReplaceWithAssertNonNull(const BB &bb) const { - (void) bb; - return false; + const StmtNode *stmt = bb.GetStmtNodes().begin().d(); + constexpr const char npeTypeName[] = "Ljava_2Flang_2FNullPointerException_3B"; + GStrIdx npeGStrIdx = GlobalTables::GetStrTable().GetStrIdxFromName(npeTypeName); + TyIdx npeTypeIdx = func.GetMIRModule().GetTypeNameTab()->GetTyIdxFromGStrIdx(npeGStrIdx); + // match first stmt + MATCH_STMT(stmt, OP_intrinsiccallwithtype); + + auto *cNode = static_cast(stmt); + if (cNode->GetTyIdx() != npeTypeIdx) { + return false; + } + stmt = stmt->GetNext(); + // match second stmt + MATCH_STMT(stmt, OP_dassign); + + auto *dassignNode = static_cast(stmt); + if (dassignNode->GetRHS()->GetOpCode() != OP_gcmalloc) { + return false; + } + auto *gcMallocNode = static_cast(dassignNode->GetRHS()); + if (gcMallocNode->GetTyIdx() != npeTypeIdx) { + return false; + } + stmt = stmt->GetNext(); + // match third stmt + MATCH_STMT(stmt, OP_callassigned); + + auto *callNode = static_cast(stmt); + if (GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callNode->GetPUIdx())->GetName() != + "Ljava_2Flang_2FNullPointerException_3B_7C_3Cinit_3E_7C_28_29V") { + return false; + } + stmt = stmt->GetNext(); + MATCH_STMT(stmt, OP_throw); + + return true; } void MeCFG::ReplaceSwitchContainsOneCaseBranchWithBrtrue(maple::BB &bb, MapleVector &exitBlocks) { @@ -123,7 +165,7 @@ void MeCFG::AddCatchHandlerForTryBB(BB &bb, MapleVector &exitBlocks) { bb.SetAttributes(kBBAttrIsExit); // may exit exitBlocks.push_back(&bb); } - } else if ((func.GetMIRModule().GetSrcLang() == kSrcLangJava) && bb.GetAttributes(kBBAttrIsExit)) { + } else if ((func.GetMIRModule().GetSrcLang() == kSrcLangDex) && bb.GetAttributes(kBBAttrIsExit)) { // deal with throw bb, if throw bb in a tryblock and has finallyhandler auto &stmtNodes = bb.GetStmtNodes(); if (!stmtNodes.empty() && stmtNodes.back().GetOpCode() == OP_throw) { @@ -535,6 +577,52 @@ void MeCFG::FixMirCFG() { // replace "if() throw NPE()" with assertnonnull void MeCFG::ReplaceWithAssertnonnull() { + constexpr char rnnTypeName[] = + "Ljava_2Futil_2FObjects_3B_7CrequireNonNull_7C_28Ljava_2Flang_2FObject_3B_29Ljava_2Flang_2FObject_3B"; + if (func.GetName() == rnnTypeName) { + return; + } + for (LabelIdx lblIdx : patternSet) { + BB *bb = func.GetLabelBBAt(lblIdx); + // if BB->pred_.size()==0, it won't enter this function + for (size_t i = 0; i < bb->GetPred().size(); ++i) { + BB *innerBB = bb->GetPred(i); + if (innerBB->GetKind() == kBBCondGoto) { + StmtNode &stmt = innerBB->GetStmtNodes().back(); + Opcode stmtOp = stmt.GetOpCode(); + ASSERT(stmt.IsCondBr(), "CondGoto BB with no condGoto stmt"); + auto &condGotoNode = static_cast(stmt); + if ((stmtOp == OP_brtrue && condGotoNode.Opnd(0)->GetOpCode() != OP_eq) || + (stmtOp == OP_brfalse && condGotoNode.Opnd(0)->GetOpCode() != OP_ne)) { + continue; + } + auto *cmpNode = static_cast(condGotoNode.Opnd(0)); + BaseNode *opnd = nullptr; + if (cmpNode->GetOpndType() != PTY_ref && cmpNode->GetOpndType() != PTY_ptr) { + continue; + } + if (cmpNode->GetBOpnd(0)->GetOpCode() == OP_constval) { + auto *constNode = static_cast(cmpNode->GetBOpnd(0)); + if (!constNode->GetConstVal()->IsZero()) { + continue; + } + opnd = cmpNode->GetBOpnd(1); + } else if (cmpNode->GetBOpnd(1)->GetOpCode() == OP_constval) { + auto *constNode = static_cast(cmpNode->GetBOpnd(1)); + if (!constNode->GetConstVal()->IsZero()) { + continue; + } + opnd = cmpNode->GetBOpnd(0); + } + ASSERT(opnd != nullptr, "Compare with non-zero"); + UnaryStmtNode *nullCheck = func.GetMIRModule().GetMIRBuilder()->CreateStmtUnary(OP_assertnonnull, opnd); + innerBB->ReplaceStmt(&stmt, nullCheck); + innerBB->SetKind(kBBFallthru); + innerBB->RemoveSucc(*bb); + --i; + } + } + } } bool MeCFG::IsStartTryBB(maple::BB &meBB) const { diff --git a/src/mapleall/maple_me/src/me_cfg_opt.cpp b/src/mapleall/maple_me/src/me_cfg_opt.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f42e85c875e033cca3131c6929b615b7f2c0528a --- /dev/null +++ b/src/mapleall/maple_me/src/me_cfg_opt.cpp @@ -0,0 +1,425 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#include "me_cfg_opt.h" +#include "me_bb_layout.h" +#include "me_irmap.h" + +// We find the following pattern in JAVA code: +// if (empty) { a = 1; } else { a = 3; } +// +// It will generate the following IR in mpl file: +// brfalse @label1 (dread u1 %Reg4_Z) +// dassign %Reg1_I 0 (cvt i32 i8 (constval i8 1)) +// goto @label2 +// @label1 dassign %Reg1_I 0 (cvt i32 i8 (constval i8 3)) +// +// The mecfgopt phase overwrite the upper pattern with following code: +// regassign i32 %26 (select i32 ( +// select u1 ( +// ne u1 i32 (regread i32 %1, constval i32 0), +// constval u1 0, +// constval u1 1), +// constval i32 1, +// constval i32 3)) +namespace maple { +bool MeCfgOpt::IsExpensiveOp(Opcode op) { + switch (op) { + case OP_abs: + case OP_bnot: + case OP_lnot: + case OP_sqrt: + case OP_neg: + return false; + case OP_recip: + case OP_div: + case OP_rem: + case OP_alloca: + case OP_malloc: + case OP_gcmalloc: + case OP_gcmallocjarray: + return true; + case OP_ceil: + case OP_cvt: + case OP_floor: + case OP_retype: + case OP_round: + case OP_trunc: + return false; + case OP_sext: + case OP_zext: + case OP_extractbits: + return false; + case OP_iaddrof: + case OP_iread: + return true; + case OP_ireadoff: + return true; + case OP_ireadfpoff: + return true; + case OP_add: + case OP_ashr: + case OP_band: + case OP_bior: + case OP_bxor: + case OP_cand: + case OP_cior: + case OP_land: + case OP_lior: + case OP_lshr: + case OP_max: + case OP_min: + case OP_mul: + case OP_shl: + case OP_sub: + return false; + case OP_CG_array_elem_add: + return true; + case OP_eq: + case OP_ne: + case OP_ge: + case OP_gt: + case OP_le: + case OP_lt: + case OP_cmp: + case OP_cmpl: + case OP_cmpg: + return false; + case OP_depositbits: + return true; + case OP_select: + return false; + case OP_intrinsicop: + case OP_intrinsicopwithtype: + return true; + case OP_constval: + case OP_conststr: + case OP_conststr16: + return false; + case OP_sizeoftype: + case OP_fieldsdist: + return false; + case OP_array: + return true; + case OP_addrof: + case OP_dread: + case OP_regread: + case OP_addroffunc: + case OP_addroflabel: + return false; + // statement nodes start here + default: + CHECK_FATAL(false, "should be an expression or NYI"); + } +} + +const MeStmt *MeCfgOpt::GetCondBrStmtFromBB(const BB &bb) const { + CHECK_FATAL(bb.GetKind() == kBBCondGoto, "must be cond goto"); + const MeStmt *meStmt = to_ptr(bb.GetMeStmts().rbegin()); + if (meStmt->IsCondBr()) { + return meStmt; + } + CHECK_FATAL(meStmt->GetOp() == OP_comment, "NYI"); + return nullptr; +} + +// if the bb contains only one stmt other than comment, return that stmt +// otherwise return nullptr +MeStmt *MeCfgOpt::GetTheOnlyMeStmtFromBB(BB &bb) const { + MeStmt *noCommentStmt = nullptr; + for (auto &meStmt : bb.GetMeStmts()) { + if (meStmt.GetOp() == OP_comment) { + continue; + } + if (noCommentStmt != nullptr) { + return nullptr; + } + noCommentStmt = &meStmt; + } + return noCommentStmt; +} + +// if the bb contains only one stmt other than comment and goto, return that stmt +// otherwise return nullptr +MeStmt *MeCfgOpt::GetTheOnlyMeStmtWithGotoFromBB(BB &bb) const { + constexpr uint32 stmtCount = 2; + MeStmt *arrayStmt[stmtCount]; + uint32 index = 0; + for (auto &meStmt : bb.GetMeStmts()) { + if (meStmt.GetOp() == OP_comment) { + continue; + } + if (index >= stmtCount) { + return nullptr; + } + arrayStmt[index++] = &meStmt; + } + if (index == stmtCount && arrayStmt[0]->GetOp() != OP_comment && arrayStmt[1]->GetOp() == OP_goto) { + return arrayStmt[0]; + } + return nullptr; +} + +bool MeCfgOpt::IsOk2Select(const MeExpr &expr0, const MeExpr &expr1) const { + if (expr0.GetExprID() == expr1.GetExprID()) { + return true; + } + std::set expensiveOps1; + std::set expensiveOps2; + if (CollectExpensiveOps(expr0, expensiveOps1)) { + return false; + } + if (CollectExpensiveOps(expr1, expensiveOps2)) { + return false; + } + if (expensiveOps1.size() != expensiveOps2.size()) { + return false; + } + for (auto it = expensiveOps1.begin(); it != expensiveOps1.end(); ++it) { + int32 expr1Id = *it; + if (expensiveOps2.find(expr1Id) == expensiveOps2.end()) { + return false; + } + } + return true; +} + +bool MeCfgOpt::HasFloatCmp(const MeExpr &meExpr) const { + Opcode op = meExpr.GetOp(); + if ((op == OP_cmpl || op == OP_cmpg || op == OP_cmp) && + IsPrimitiveFloat(static_cast(meExpr).GetOpndType())) { + return true; + } + for (size_t i = 0; i < meExpr.GetNumOpnds(); ++i) { + if (HasFloatCmp(*meExpr.GetOpnd(i))) { + return true; + } + } + return false; +} + +bool MeCfgOpt::PreCheck(const MeFunction &func) const { + auto eIt = func.valid_end(); + for (auto bIt = func.valid_begin(); bIt != eIt; ++bIt) { + auto *bb = *bIt; + if (bb->GetAttributes(kBBAttrIsTry) && bb->GetBBLabel() != 0) { + for (size_t i = 0; i < bb->GetPred().size(); ++i) { + BB *predBB = bb->GetPred(i); + if (!predBB->GetAttributes(kBBAttrIsTry)) { + // comes from outside of try. give up folding select. + return false; + } + } + } + for (auto &stmt : bb->GetMeStmts()) { + for (size_t i = 0; i < stmt.NumMeStmtOpnds(); ++i) { + MeExpr *meExpr = stmt.GetOpnd(i); + if (HasFloatCmp(*meExpr)) { + return false; + } + } + } + } + return true; +} + +bool MeCfgOpt::Run(MeFunction &func) { + if (!PreCheck(func)) { + return false; + } + auto eIt = func.valid_end(); + for (auto bIt = func.valid_begin(); bIt != eIt; ++bIt) { + auto *bb = *bIt; + constexpr uint32 numOfSuccs = 2; + if (bb->GetKind() == kBBCondGoto && bb->GetSucc().size() == numOfSuccs) { + const MeStmt *condMeStmt = GetCondBrStmtFromBB(*bb); + if (condMeStmt == nullptr || !condMeStmt->IsCondBr()) { + continue; + } + BB *bbLeft = bb->GetSucc(0); + BB *bbRight = bb->GetSucc(1); + if (bbLeft->GetSucc().size() != 1 || bbLeft->GetPred().size() != 1 || + bbRight->GetPred().size() != 1 || bbRight->GetSucc().size() != 1) { + continue; + } + const auto *condGotoMeStmt = static_cast(condMeStmt); + if (bbLeft->GetBBLabel() && bbLeft->GetBBLabel() == condGotoMeStmt->GetOffset()) { + BB *tmpBB = bbLeft; + bbLeft = bbRight; + bbRight = tmpBB; + } + if (bbLeft->GetKind() != kBBGoto || bbLeft->GetPred(0)->GetBBId() != bb->GetBBId() || + bbRight->GetKind() != kBBFallthru || bbRight->GetPred(0)->GetBBId() != bb->GetBBId() || + bbLeft->GetSucc(0) != bbRight->GetSucc(0)) { + continue; + } + MeStmt *assStmtLeft = GetTheOnlyMeStmtWithGotoFromBB(*bbLeft); + if (!(assStmtLeft != nullptr && (assStmtLeft->GetOp() == OP_iassign || assStmtLeft->GetOp() == OP_dassign))) { + continue; + } + MeStmt *assStmtRight = GetTheOnlyMeStmtFromBB(*bbRight); + if (!(assStmtRight != nullptr && (assStmtRight->GetOp() == OP_iassign || assStmtRight->GetOp() == OP_dassign) && + assStmtRight->GetOp() == assStmtLeft->GetOp())) { + continue; + } + bool isTrueBr = (condMeStmt->GetOp() == OP_brtrue); + bool isIassign = (assStmtLeft->GetOp() == OP_iassign); + MeExpr *selectOpLeft = nullptr; + MeExpr *selectOpRight = nullptr; + if (isIassign) { + auto *iassLeft = static_cast(assStmtLeft); + auto *iassRight = static_cast(assStmtRight); + if (iassLeft->GetLHSVal()->GetBase() != iassRight->GetLHSVal()->GetBase() || + iassLeft->GetLHSVal()->GetFieldID() != iassRight->GetLHSVal()->GetFieldID()) { + continue; + } + // patter match + selectOpLeft = iassLeft->GetRHS(); + selectOpRight = iassRight->GetRHS(); + } else { + auto *dassLeft = static_cast(assStmtLeft); + auto *dassRight = static_cast(assStmtRight); + if (!dassLeft->GetLHS()->IsUseSameSymbol(*dassRight->GetLHS())) { + continue; + } + selectOpLeft = dassLeft->GetRHS(); + selectOpRight = dassRight->GetRHS(); + } + if (!IsOk2Select(*selectOpLeft, *selectOpRight) || + (selectOpLeft->GetPrimType() == PTY_ref && MeOption::rcLowering)) { + continue; + } + MeExpr *selectMeExpr = meIrMap->CreateMeExprSelect( + selectOpLeft->GetPrimType(), *condGotoMeStmt->GetOpnd(), + *(isTrueBr ? selectOpRight : selectOpLeft), + *(isTrueBr ? selectOpLeft : selectOpRight)); + if (isIassign) { + // use bb as the new bb and put new iassign there + static_cast(assStmtLeft)->SetRHS(selectMeExpr); + } else { + static_cast(assStmtLeft)->SetRHS(selectMeExpr); + } + bb->ReplaceMeStmt(condMeStmt, assStmtLeft); + // update the preds and succs + bb->RemoveAllSucc(); + BB *succBB = bbLeft->GetSucc(0); + succBB->RemovePred(*bbLeft); + if (bbRight->IsPredBB(*succBB)) { + succBB->RemovePred(*bbRight); + } + bb->AddSucc(*succBB); + bb->SetKind(kBBFallthru); + bb->GetSuccFreq().push_back(bb->GetFrequency()); + func.DeleteBasicBlock(*bbLeft); + func.DeleteBasicBlock(*bbRight); + SetCfgChanged(); + } + } + return IsCfgChanged(); +} + +void MeDoCfgOpt::EmitMapleIr(MeFunction &func, MeFuncResultMgr &m) { + if (func.NumBBs() > 0) { + (void)m.GetAnalysisResult(MeFuncPhase_BBLAYOUT, &func); + CHECK_FATAL(func.HasLaidOut(), "Check bb layout phase."); + auto layoutBBs = func.GetLaidOutBBs(); + CHECK_NULL_FATAL(func.GetIRMap()); + MIRFunction *mirFunction = func.GetMirFunc(); + if (mirFunction->GetCodeMemPool() != nullptr) { + mirFunction->GetCodeMemPool()->Release(); + } + mirFunction->SetCodeMemPool(memPoolCtrler.NewMemPool("IR from IRMap::Emit()")); + mirFunction->GetCodeMPAllocator().SetMemPool(mirFunction->GetCodeMemPool()); + mirFunction->SetBody(mirFunction->GetCodeMemPool()->New()); + for (size_t k = 1; k < mirFunction->GetSymTab()->GetSymbolTableSize(); ++k) { + MIRSymbol *sym = mirFunction->GetSymTab()->GetSymbolFromStIdx(k); + if (sym->GetSKind() == kStVar) { + sym->SetIsDeleted(); + } + } + func.GetIRMap()->SetNeedAnotherPass(true); + for (BB *bb : layoutBBs) { + ASSERT(bb != nullptr, "bb should not be nullptr"); + bb->EmitBB(*func.GetMeSSATab(), *func.GetMirFunc()->GetBody(), true); + } + func.ClearLayout(); + } +} + +bool MeDoCfgOpt::FindLocalRefVarUses(const MeIRMap &irMap, const MeExpr &expr, + const MeStmt &meStmt, const VarMeExpr &var) const { + if (expr.GetMeOp() == kMeOpVar) { + const auto &varMeExpr = static_cast(expr); + if (varMeExpr.GetOstIdx() == var.GetOstIdx()) { + return true; + } + } + for (size_t i = 0; i < expr.GetNumOpnds(); ++i) { + if (FindLocalRefVarUses(irMap, *expr.GetOpnd(i), meStmt, var)) { + return true; + } + } + return false; +} + +AnalysisResult *MeDoCfgOpt::Run(MeFunction *func, MeFuncResultMgr *m, ModuleResultMgr*) { + auto *irMap = static_cast(m->GetAnalysisResult(MeFuncPhase_IRMAPBUILD, func)); + ASSERT(irMap != nullptr, "irMap should not be nullptr"); + MeCfgOpt cfgOpt(irMap); + if (cfgOpt.Run(*func)) { + SetChangeCFG(); + EmitMapleIr(*func, *m); + return nullptr; + } + + // check all basic blocks searching for split case + for (BB *bb : func->GetAllBBs()) { + if (bb == nullptr || !(bb->GetAttributes(kBBAttrIsTry))) { + continue; + } + // use and def in the same bb. + for (MeStmt *stmt = to_ptr(bb->GetMeStmts().begin()); stmt != nullptr; stmt = stmt->GetNextMeStmt()) { + // use and def the same var in one callassign statement + if (stmt->GetOp() == OP_dassign) { // skip identity assignments + auto *dass = static_cast(stmt); + if (dass->GetLHS()->IsUseSameSymbol(*dass->GetRHS())) { + continue; + } + } + VarMeExpr *theLHS = nullptr; + if (stmt->GetOp() == OP_dassign || kOpcodeInfo.IsCallAssigned(stmt->GetOp())) { + theLHS = static_cast(stmt->GetLHSRef(false)); + } + if (theLHS == nullptr) { + continue; + } + MeStmt *nextStmt = stmt->GetNextMeStmt(); + for (MeStmt *stmtNew = to_ptr(bb->GetMeStmts().begin()); stmtNew != nullptr && stmtNew != nextStmt; + stmtNew = stmtNew->GetNextMeStmt()) { + // look for use occurrence of localrefvars + for (size_t i = 0; i < stmtNew->NumMeStmtOpnds(); ++i) { + ASSERT(stmtNew->GetOpnd(i) != nullptr, "null ptr check"); + if (FindLocalRefVarUses(*irMap, *stmtNew->GetOpnd(i), *stmtNew, *theLHS)) { + SetChangeCFG(); + EmitMapleIr(*func, *m); + return nullptr; + } + } + } + } + } + return nullptr; +} +} // namespace maple diff --git a/src/mapleall/maple_me/src/me_check_cast.cpp b/src/mapleall/maple_me/src/me_check_cast.cpp new file mode 100644 index 0000000000000000000000000000000000000000..36fd3af1552675c10c5ef3cce005172369e8d349 --- /dev/null +++ b/src/mapleall/maple_me/src/me_check_cast.cpp @@ -0,0 +1,722 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "me_check_cast.h" + +namespace maple { +MIRStructType *GetClassTypeFromName(const std::string &className); +void FunctionGenericDump(MIRFunction &func); + +std::string GetLabel(AnnotationType &aType) { + std::string lable; + switch (aType.GetKind()) { + case kPrimeType: + case kGenericType: { + lable = aType.GetName(); + break; + } + case kGenericDeclare: { + GenericDeclare *gDeclare = static_cast(&aType); + lable = "(" + gDeclare->GetBelongToName() + ")" + ": T" + gDeclare->GetName(); + break; + } + case kGenericMatch: { + lable = "*"; + break; + } + case kExtendType: { + ExtendGeneric *extendGeneric = static_cast(&aType); + AnnotationType *contains = extendGeneric->GetContainsGeneric(); + if (extendGeneric->GetExtendInfo() == kHierarchyExtend) { + lable = "(+)" + GetLabel(*contains); + } else if (extendGeneric->GetExtendInfo() == kArrayType) { + lable = "([)" + GetLabel(*contains); + } else { + lable = "(-)" + GetLabel(*contains); + } + break; + } + default: + CHECK_FATAL(false, "must be"); + } + return lable; +} + +void CheckCast::DumpGenericNode(GenericNode &node, std::ostream &out) { + std::string lable = GetLabel(*node.aType); + out << node.aType->GetId() << " [label=\"" << lable << "\"];\n"; + if (node.next != nullptr) { + out << node.aType->GetId() << "->" << node.next->aType->GetId() << ";\n"; + } +} + +void CheckCast::DumpGenericGraph() { + std::filebuf fileBuf; + std::string outFile = func->GetName() + "-GenericGraph.dot"; + std::filebuf *fileBufPtr = fileBuf.open(outFile, std::ios::trunc | std::ios::out); + CHECK_FATAL(fileBufPtr, "open file : %s failed!", outFile.c_str()); + std::ostream dotFile(&fileBuf); + dotFile << "digraph InequalityGraph {\n"; + for (auto pair : created) { + GenericNode *node = pair.second; + DumpGenericNode(*node, dotFile); + } + dotFile << "}\n"; + fileBufPtr = fileBuf.close(); + CHECK_FATAL(fileBufPtr, "close file : %s failed", outFile.c_str()); +} + +GenericNode *CheckCast::GetOrCreateGenericNode(AnnotationType *annoType) { + if (created.find(annoType) != created.end()) { + return created[annoType]; + } + GenericNode *newNode = graphTempMem->New(); + newNode->aType = annoType; + created[annoType] = newNode; + return newNode; +} + +void CheckCast::AddNextNode(GenericNode &from, GenericNode &to) const { + if (from.multiOutput || + (from.next != nullptr && from.next != &to && from.next->aType->GetKind() != kGenericDeclare)) { + from.multiOutput = true; + from.next = nullptr; + return; + } + from.next = &to; +} + +void CheckCast::BuildGenericGraph(AnnotationType *annoType) { + if (annoType == nullptr) { + return; + } + switch (annoType->GetKind()) { + case kGenericType: { + GenericType *gType = static_cast(annoType); + for (auto pair : gType->GetGenericMap()) { + GenericDeclare *gDeclare = pair.first; + AnnotationType *realType = pair.second; + GenericNode *gDeclareNode = GetOrCreateGenericNode(gDeclare); + GenericNode *realTypeNode = GetOrCreateGenericNode(realType); + AddNextNode(*gDeclareNode, *realTypeNode); + BuildGenericGraph(realType); + } + break; + } + case kExtendType: { + ExtendGeneric *extendGeneric = static_cast(annoType); + if (extendGeneric->GetExtendInfo() == kHierarchyExtend) { + GenericNode *gExtendNode = GetOrCreateGenericNode(annoType); + GenericNode *containsNode = GetOrCreateGenericNode(extendGeneric->GetContainsGeneric()); + AddNextNode(*gExtendNode, *containsNode); + BuildGenericGraph(extendGeneric->GetContainsGeneric()); + } + break; + } + case kGenericDeclare: + case kGenericMatch: + case kPrimeType: + break; + default: + CHECK_FATAL(false, "must be"); + } +} + +void CheckCast::TryToResolveFuncArg(MeExpr &expr, AnnotationType &at) { + MIRType *mirType = nullptr; + if (at.GetKind() == kGenericDeclare) { + if (expr.GetMeOp() == kMeOpVar) { + VarMeExpr *var = static_cast(&expr); + const OriginalSt *symOst = func->GetIRMap()->GetSSATab().GetOriginalStFromID(var->GetOstIdx()); + const MIRSymbol *sym = symOst->GetMIRSymbol(); + mirType = sym->GetType(); + } else if (expr.GetMeOp() == kMeOpIvar) { + IvarMeExpr *ivar = static_cast(&expr); + mirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ivar->GetTyIdx()); + if (mirType->GetKind() == kTypePointer) { + mirType = static_cast(mirType)->GetPointedType(); + } + CHECK_FATAL(mirType->IsStructType(), "must be"); + mirType = static_cast(mirType)->GetFieldType(ivar->GetFieldID()); + } else { + return; + } + if (mirType->GetKind() == kTypePointer) { + mirType = static_cast(mirType)->GetPointedType(); + } + GenericType *realType = graphTempMem->New(mirType->GetNameStrIdx(), + mirType, graphTempAllocator); + GenericNode *realNode = GetOrCreateGenericNode(realType); + GenericNode *declareNode = GetOrCreateGenericNode(&at); + AddNextNode(*declareNode, *realNode); + } else if (at.GetKind() == kGenericType && expr.GetMeOp() == kMeOpVar) { + VarMeExpr *var = static_cast(&expr); + if (var->GetDefBy() != kDefByStmt) { + return; + } + GenericType *gt = static_cast(&at); + MeStmt *defStmt = var->GetDefStmt(); + if (!(defStmt->GetOp() == OP_dassign && defStmt->GetRHS()->GetMeOp() == kMeOpNary)) { + return; + } + NaryMeExpr *naryExpr = static_cast(defStmt->GetRHS()); + if (naryExpr->GetIntrinsic() == INTRN_JAVA_CONST_CLASS) { + mirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(naryExpr->GetTyIdx()); + if (mirType->GetKind() == kTypePointer) { + mirType = static_cast(mirType)->GetPointedType(); + } + MapleMap >Map = gt->GetGenericMap(); + CHECK_FATAL(gtMap.size() == 1, "must be"); + AnnotationType *gd = gtMap.begin()->second; + if (gd->GetKind() != kGenericDeclare) { + return; + } + GenericType *realType = graphTempMem->New(mirType->GetNameStrIdx(), mirType, + graphTempAllocator); + GenericNode *realNode = GetOrCreateGenericNode(realType); + GenericNode *declareNode = GetOrCreateGenericNode(gd); + AddNextNode(*declareNode, *realNode); + } + } else if(at.GetKind() == kExtendType && expr.GetMeOp() == kMeOpVar) { + ExtendGeneric *extendG = static_cast(&at); + CHECK_FATAL(extendG->GetExtendInfo() == kArrayType, "must be"); + if (extendG->GetContainsGeneric()->GetKind() != kGenericDeclare) { + return; + } + VarMeExpr *var = static_cast(&expr); + const OriginalSt *symOst = func->GetIRMap()->GetSSATab().GetOriginalStFromID(var->GetOstIdx()); + const MIRSymbol *sym = symOst->GetMIRSymbol(); + mirType = sym->GetType(); + if (mirType->GetKind() == kTypePointer) { + mirType = static_cast(mirType)->GetPointedType(); + } + if (!mirType->IsMIRJarrayType()) { + return; + } + GenericType *realType = graphTempMem->New(mirType->GetNameStrIdx(), mirType, + graphTempAllocator); + GenericNode *realNode = GetOrCreateGenericNode(realType); + GenericNode *declareNode = GetOrCreateGenericNode(extendG); + AddNextNode(*declareNode, *realNode); + mirType = static_cast(mirType)->GetElemType(); + if (mirType->GetKind() == kTypePointer) { + mirType = static_cast(mirType)->GetPointedType(); + } + GenericType *subRealType = graphTempMem->New(mirType->GetNameStrIdx(), mirType, + graphTempAllocator); + GenericNode *subRealNode = GetOrCreateGenericNode(subRealType); + GenericNode *subDeclareNode = GetOrCreateGenericNode(extendG->GetContainsGeneric()); + AddNextNode(*subDeclareNode, *subRealNode); + } +} + +void CheckCast::TryToResolveFuncGeneric(MIRFunction &callee, const CallMeStmt &callMeStmt, size_t thisIdx) { + size_t argStartPos = thisIdx; + if (!callee.IsStatic()) { + argStartPos += 1; + } + MapleVector &argVec = callee.GetFuncGenericArg(); + CHECK_FATAL(callMeStmt.NumMeStmtOpnds() == argVec.size() + argStartPos, "must be"); + for (size_t i = 0; i < argVec.size(); ++i) { + AnnotationType *at = argVec[i]; + MeExpr *expr = callMeStmt.GetOpnd(i + argStartPos); + TryToResolveFuncArg(*expr, *at); + } +} + +void CheckCast::TryToResolveCall(MeStmt &meStmt) { + CallMeStmt &callMeStmt = static_cast(meStmt); + MIRFunction &callee = callMeStmt.GetTargetFunction(); + size_t thisIdx = 0; + if (callMeStmt.GetOp() == OP_interfaceicallassigned || callMeStmt.GetOp() == OP_virtualicallassigned) { + CHECK_FATAL(callee.GetParamSize() + 1 == callMeStmt.GetOpnds().size(), "must be"); + thisIdx = 1; + } else if (callMeStmt.GetOp() == OP_callassigned) { + thisIdx = 0; + } else { + CHECK_FATAL(false, "must be"); + } + if (!callee.GetFuncGenericDeclare().empty()) { + TryToResolveFuncGeneric(callee, callMeStmt, thisIdx); + } + if (callee.GetClassTyIdx() == 0 || callee.IsStatic()) { + return; + } + MIRStructType *structType = static_cast( + GlobalTables::GetTypeTable().GetTypeFromTyIdx(callee.GetClassTyIdx())); + if (structType->GetGenericDeclare().empty()) { + return; + } + switch (callMeStmt.GetOpnd(thisIdx)->GetMeOp()) { + case kMeOpVar: { + (void)TryToResolveVar(*static_cast(callMeStmt.GetOpnd(thisIdx)), structType); + break; + } + case kMeOpIvar: { + TryToResolveIvar(*static_cast(callMeStmt.GetOpnd(thisIdx)), structType); + break; + } + default: + break; + } + BuildGenericGraph(callee.GetFuncGenericRet()); + return; +} + +void CheckCast::TryToResolveIvar(IvarMeExpr &ivar, MIRStructType *callStruct) { + if (ivar.GetBase()->GetMeOp() == kMeOpIvar) { + TryToResolveIvar(*static_cast(ivar.GetBase())); + } else if (ivar.GetBase()->GetMeOp() != kMeOpVar) { + return; + } + MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ivar.GetTyIdx()); + if (type->GetKind() == kTypePointer) { + type = static_cast(type)->GetPointedType(); + } + if (!type->IsStructType()) { + return; + } + MIRStructType *structType = static_cast(type); + GStrIdx gStrIdx = structType->GetFieldGStrIdx(ivar.GetFieldID()); + MIRType *ivarType = structType->GetFieldType(ivar.GetFieldID()); + if (ivarType->GetKind() == kTypePointer) { + ivarType = static_cast(ivarType)->GetPointedType(); + } + CHECK_FATAL(ivarType->IsStructType(), "must be"); + AnnotationType *annotationType = nullptr; + MIRStructType *tmpStructType = structType; + do { + annotationType = tmpStructType->GetFieldGenericDeclare(gStrIdx); + Klass *super = klassh->GetKlassFromTyIdx(tmpStructType->GetTypeIndex())->GetSuperKlass(); + if (super != nullptr) { + tmpStructType = super->GetMIRStructType(); + } else { + tmpStructType = nullptr; + } + } while (annotationType == nullptr && tmpStructType != nullptr); + + if (NeedChangeVarType(static_cast(ivarType), callStruct)) { + ivarType = callStruct; + annotationType = CloneNewAnnotationType(annotationType, callStruct); + } + AddClassInheritanceInfo(*ivarType); + if (annotationType == nullptr) { + return; + } + if (annotationType->GetKind() == kGenericType) { + BuildGenericGraph(annotationType); + return; + } +} + +bool CheckCast::TryToResolveStaticVar(const VarMeExpr &var) { + const OriginalSt *symOst = func->GetIRMap()->GetSSATab().GetOriginalStFromID(var.GetOstIdx()); + const MIRSymbol *sym = symOst->GetMIRSymbol(); + if (!sym->IsStatic()) { + return false; + } + std::string varTotalName = sym->GetName(); + size_t posOfClass = varTotalName.find("_7C"); + std::string className = varTotalName.substr(0, posOfClass); + std::string varName = varTotalName.substr(posOfClass + strlen(namemangler::kNameSplitterStr)); + MIRStructType *structType = GetClassTypeFromName(className); + GStrIdx gStrIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(varName); + AnnotationType *aType = structType->GetFieldGenericDeclare(gStrIdx); + if (aType == nullptr) { + return true; + } + if (aType->GetKind() == kGenericType) { + BuildGenericGraph(aType); + } else { + CHECK_FATAL(false, "must be"); + } + return true; +} + +void CheckCast::TryToResolveDassign(MeStmt &meStmt) { + CHECK_FATAL(meStmt.GetOp() == OP_dassign, "must be"); + DassignMeStmt &dassignMeStmt = static_cast(meStmt); + if (dassignMeStmt.GetRHS()->GetMeOp() == kMeOpIvar) { + IvarMeExpr *ivar = static_cast(dassignMeStmt.GetRHS()); + TryToResolveIvar(*ivar); + } else if (dassignMeStmt.GetRHS()->GetMeOp() == kMeOpVar) { + bool tmpResult = TryToResolveStaticVar(*static_cast(dassignMeStmt.GetRHS())); + if (!tmpResult) { + (void)TryToResolveVar(static_cast(*dassignMeStmt.GetRHS())); + } + } +} + +MIRType *CheckCast::TryToResolveType(GenericNode &retNode) { + (void)visited.insert(&retNode); + if (retNode.next == nullptr || visited.find(retNode.next) != visited.end()) { + AnnotationType *at = retNode.aType; + if (at->GetKind() == kGenericType) { + return static_cast(at)->GetMIRType(); + } else if (at->GetKind() == kGenericDeclare) { + AnnotationType *defaultType = static_cast(at)->GetDefaultType(); + while (defaultType->GetKind() == kGenericDeclare) { + defaultType = static_cast(defaultType)->GetDefaultType(); + } + if (defaultType->GetKind() == kGenericType) { + return static_cast(defaultType)->GetMIRStructType(); + } + CHECK_FATAL(false, "must be"); + } else { + return nullptr; + } + } + return TryToResolveType(*retNode.next); +} + +void CheckCast::AddClassInheritanceInfo(MIRType &mirType) { + if (mirType.GetKind() == kTypePointer) { + mirType = *static_cast(mirType).GetPointedType(); + } + if (!mirType.IsStructType()) { + return; + } + MIRStructType *structType = static_cast(&mirType); + for (GenericType *gt : structType->GetInheritanceGeneric()) { + BuildGenericGraph(gt); + AddClassInheritanceInfo(*gt->GetMIRStructType()); + } +} + +// varStruct is parent, callStruct is child +bool CheckCast::ExactlyMatch(MIRStructType &varStruct, MIRStructType &callStruct) { + if (varStruct.GetGenericDeclare().size() == 0 || callStruct.GetGenericDeclare().size() == 0) { + return false; + } + if (varStruct.GetGenericDeclare().size() != callStruct.GetGenericDeclare().size()) { + return false; + } + GenericType *gTmp = nullptr; + for (GenericType *gt : callStruct.GetInheritanceGeneric()) { + if (gt->GetMIRStructType() == &varStruct) { + gTmp = gt; + break; + } + } + if (gTmp == nullptr) { + return false; + } + + for (size_t i = 0; i < gTmp->GetGenericArg().size(); ++i) { + if (gTmp->GetGenericArg()[i] != callStruct.GetGenericDeclare()[i]) { + return false; + } + } + return true; +} + +bool CheckCast::NeedChangeVarType(MIRStructType *varStruct, MIRStructType *callStruct) { + if (callStruct == nullptr) { + return false; + } + if (varStruct == callStruct) { + return false; + } + Klass *varKlass = klassh->GetKlassFromTyIdx(varStruct->GetTypeIndex()); + Klass *callKlass = klassh->GetKlassFromTyIdx(callStruct->GetTypeIndex()); + if (klassh->IsSuperKlass(varKlass, callKlass) || + klassh->IsSuperKlassForInterface(varKlass, callKlass) || klassh->IsInterfaceImplemented(varKlass, callKlass)) { + if (ExactlyMatch(*varStruct, *callStruct)) { + return true; + } + } + return false; +} + +AnnotationType *CheckCast::CloneNewAnnotationType(AnnotationType *at, MIRStructType *callStruct) { + if (at == nullptr || at->GetKind() != kGenericType) { + return at; + } + GenericType *newGT = graphTempMem->New(callStruct->GetNameStrIdx(), callStruct, graphTempAllocator); + MapleVector &argVec = static_cast(at)->GetGenericArg(); + for (size_t i = 0; i < argVec.size(); i++) { + newGT->AddGenericPair(callStruct->GetGenericDeclare()[i], argVec[i]); + } + return newGT; +} + +bool CheckCast::RetIsGenericRelative(MIRFunction &callee) { + if (callee.GetFuncGenericRet() == nullptr) { + return false; + } + AnnotationType *ret = callee.GetFuncGenericRet(); + if (ret->GetKind() == kGenericDeclare) { + return true; + } + if (ret->GetKind() == kExtendType) { + ExtendGeneric *extendRet = static_cast(ret); + if (extendRet->GetExtendInfo() != kArrayType && extendRet->GetExtendInfo() != kHierarchyExtend) { + return false; + } + if (extendRet->GetContainsGeneric()->GetKind() == kGenericDeclare) { + return true; + } + } + return false; +} + +bool CheckCast::TryToResolveVar(VarMeExpr &var, MIRStructType *callStruct, bool checkFirst) { + const OriginalSt *symOst = func->GetIRMap()->GetSSATab().GetOriginalStFromID(var.GetOstIdx()); + const MIRSymbol *sym = symOst->GetMIRSymbol(); + AnnotationType *at = func->GetMirFunc()->GetFuncLocalGenericVar(sym->GetNameStrIdx()); + + MIRType *varType = sym->GetType(); + if (at != nullptr && at->GetKind() == kGenericType) { + varType = static_cast(at)->GetMIRStructType(); + } + if (varType->GetKind() == kTypePointer) { + varType = static_cast(varType)->GetPointedType(); + } + if (varType->IsStructType() && NeedChangeVarType(static_cast(varType), callStruct)) { + varType = callStruct; + at = CloneNewAnnotationType(at, callStruct); + } + if (at != nullptr && at->GetKind() == kGenericType) { + BuildGenericGraph(at); + } + AddClassInheritanceInfo(*varType); + + MeDefBy defBy = var.GetDefBy(); + switch (defBy) { + case kDefByStmt: { + if (checkFirst) { + break; + } + CHECK_FATAL(var.GetDefStmt()->GetOp() == OP_dassign, "must be"); + TryToResolveDassign(*var.GetDefStmt()); + break; + } + case kDefByPhi: + break; + case kDefByChi: { + if (checkFirst) { + break; + } + (void)TryToResolveStaticVar(var); + break; + } + case kDefByMustDef: { + CallMeStmt *callMeStmt = safe_cast(var.GetDefMustDef().GetBase()); + if (callMeStmt == nullptr) { + break; + } + MIRFunction &callee = callMeStmt->GetTargetFunction(); + if (checkFirst) { + if (!RetIsGenericRelative(callee)) { + break; + } + } + TryToResolveCall(*var.GetDefMustDef().GetBase()); + if (checkFirst) { + GenericNode *retNode = GetOrCreateGenericNode(callee.GetFuncGenericRet()); + MIRType *resultType = TryToResolveType(*retNode); + if (curCheckCastType == resultType) { + return true; + } + } + break; + } + default: + break; + } + return false; +} + +bool CheckCast::ProvedByAnnotationInfo(const IntrinsiccallMeStmt &callNode) { + MeExpr *expr = callNode.GetOpnd(0); + bool result = false; + switch (expr->GetMeOp()) { + case kMeOpVar: { + VarMeExpr *var = static_cast(expr); + result = TryToResolveVar(*var, nullptr, true); + break; + } + case kMeOpConst: + CHECK_FATAL(static_cast(expr)->IsZero(), "must be"); + break; + case kMeOpIvar: { + break; + } + default: + break; + } + created.clear(); + visited.clear(); + return result; +} + +void CheckCast::RemoveRedundantCheckCast(MeStmt &stmt, BB &bb) { + if (stmt.GetOp() == OP_intrinsiccallwithtypeassigned) { + auto *callAssign = static_cast(&stmt); + MeExpr *lhs = callAssign->GetAssignedLHS(); + DassignMeStmt *newDass = func->GetIRMap()->CreateDassignMeStmt(*lhs, *(callAssign->GetOpnd(0)), bb); + newDass->SetSrcPos(stmt.GetSrcPosition()); + lhs->SetDefByStmt(*newDass); + bb.InsertMeStmtBefore(&stmt, newDass); + } + bb.RemoveMeStmt(&stmt); +} + +ProveRes CheckCast::TraverseBackProve(MeExpr &expr, MIRType &targetType, std::set &visitedPhi) { + if (expr.GetMeOp() == kMeOpConst) { + CHECK_FATAL(static_cast(&expr)->IsZero(), "must be"); + return ProveRes::kT; + } + if (expr.GetMeOp() == kMeOpIvar) { + return TraverseBackProve(*(static_cast(expr).GetMu()), targetType, visitedPhi); + } + if (expr.GetMeOp() != kMeOpVar) { + return ProveRes::kF; + } + if (meSSI->GetInferredType(&expr) == &targetType) { + return ProveRes::kT; + } + VarMeExpr *var = static_cast(&expr); + switch (var->GetDefBy()) { + case kDefByStmt: { + MeStmt *meStmt = var->GetDefStmt(); + if (meStmt->IsAssign()) { + return TraverseBackProve(*(meStmt->GetRHS()), targetType, visitedPhi); + } + break; + } + case kDefByPhi: { + MePhiNode &phi = var->GetDefPhi(); + if (visitedPhi.find(&phi) == visitedPhi.end()) { + return ProveRes::kIgnore; + } + visitedPhi.insert(&phi); + ProveRes res = ProveRes::kF; + for (auto *scalar : phi.GetOpnds()) { + ProveRes tmp = TraverseBackProve(*scalar, targetType, visitedPhi); + if (tmp == ProveRes::kF) { + return ProveRes::kF; + } else if (tmp == ProveRes::kT) { + res = ProveRes::kT; + } + } + return res; + break; + } + default: + break; + } + return ProveRes::kF; +} + +bool CheckCast::ProvedBySSI(const IntrinsiccallMeStmt &callNode) { + std::set visitedPhi; + MeExpr *expr = callNode.GetOpnd(0); + MIRType *mirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(callNode.GetTyIdx()); + return TraverseBackProve(*expr, *mirType, visitedPhi) == ProveRes::kT; +} + +void CheckCast::DoCheckCastOpt() { + for (BB *bb : func->GetAllBBs()) { + if (bb == nullptr) { + continue; + } + MeStmt *nextStmt = nullptr; + auto &meStmts = bb->GetMeStmts(); + MeStmt *stmt = to_ptr(meStmts.begin()); + for (; stmt != nullptr; stmt = nextStmt) { + nextStmt = stmt->GetNext(); + if (stmt->GetOp() != OP_intrinsiccallwithtypeassigned && stmt->GetOp() != OP_intrinsiccallwithtype) { + continue; + } + auto *callNode = safe_cast(stmt); + if (callNode == nullptr || callNode->GetIntrinsic() != INTRN_JAVA_CHECK_CAST) { + continue; + } + MIRType *mirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(callNode->GetTyIdx()); + if (mirType->GetKind() == kTypePointer) { + mirType = static_cast(mirType)->GetPointedType(); + } + if (!mirType->IsInstanceOfMIRStructType()) { + if (!mirType->IsMIRJarrayType()) { + continue; + } + MIRType *tmpType = static_cast(mirType)->GetElemType(); + if (tmpType->GetKind() == kTypePointer) { + tmpType = static_cast(tmpType)->GetPointedType(); + } + if (!tmpType->IsInstanceOfMIRStructType()) { + continue; + } + } + curCheckCastType = mirType; + + if (ProvedByAnnotationInfo(*callNode)) { + RemoveRedundantCheckCast(*stmt, *bb); + continue; + } + } + } + memPoolCtrler.DeleteMemPool(graphTempMem); +} + +void CheckCast::FindRedundantChecks() { + for (BB *bb : func->GetAllBBs()) { + if (bb == nullptr) { + continue; + } + MeStmt *nextStmt = nullptr; + auto &meStmts = bb->GetMeStmts(); + MeStmt *stmt = to_ptr(meStmts.begin()); + for (; stmt != nullptr; stmt = nextStmt) { + nextStmt = stmt->GetNext(); + if (stmt->GetOp() != OP_intrinsiccallwithtypeassigned && stmt->GetOp() != OP_intrinsiccallwithtype) { + continue; + } + auto *callNode = safe_cast(stmt); + if (callNode == nullptr || callNode->GetIntrinsic() != INTRN_JAVA_CHECK_CAST) { + continue; + } + if (ProvedBySSI(*callNode)) { + redundantChecks.push_back(stmt); + } + } + } +} + +void CheckCast::DeleteRedundants() { + for (MeStmt *meStmt : redundantChecks) { + RemoveRedundantCheckCast(*meStmt, *(meStmt->GetBB())); + } +} + +AnalysisResult *MeDoCheckCastOpt::Run(MeFunction *func, MeFuncResultMgr *m, ModuleResultMgr *moduleResultMgr) { + auto *dom = static_cast(m->GetAnalysisResult(MeFuncPhase_DOMINANCE, func)); + auto *kh = static_cast(moduleResultMgr->GetAnalysisResult(MoPhase_CHA, &func->GetMIRModule())); + ASSERT_NOT_NULL(dom); + ASSERT_NOT_NULL(m->GetAnalysisResult(MeFuncPhase_IRMAPBUILD, func)); + MemPool *checkcastMemPool = NewMemPool(); + MeSSI meSSI(*func, *dom, *func->GetIRMap(), *checkcastMemPool); + CheckCast checkCast(*func, *kh, meSSI); + meSSI.SetSSIType(kCheckCastOpt); + meSSI.ConvertToSSI(); + checkCast.FindRedundantChecks(); + meSSI.ConvertToSSA(); + checkCast.DeleteRedundants(); + if (MeOption::checkCastOpt) { + checkCast.DoCheckCastOpt(); + } + return nullptr; +} +} // namespace maple diff --git a/src/mapleall/maple_me/src/me_delegate_rc.cpp b/src/mapleall/maple_me/src/me_delegate_rc.cpp index 1bd5206d26fc2331e00bad868718526a9813eb86..1b914d16486c9fc3fee096f99677696891cc7f45 100644 --- a/src/mapleall/maple_me/src/me_delegate_rc.cpp +++ b/src/mapleall/maple_me/src/me_delegate_rc.cpp @@ -542,7 +542,9 @@ bool DelegateRC::CanOmitRC4LHSVar(const MeStmt &stmt, bool &onlyWithDecref) cons return false; } const OriginalSt *ost = theLhs->GetOst(); - if (!ost->IsLocal() || ost->IsFormal()) { + if (!ost->IsLocal() || ost->IsFormal() || + // avoid multi-version vars because of it is hard to find the decrefreset. + ((func.GetHints() & kPlacementRCed) && ssaTab.GetVersionsIndicesSize(ost->GetIndex()) > 2)) { return false; } if (ost->GetMIRSymbol()->IsInstrumented()) { @@ -569,6 +571,10 @@ bool DelegateRC::CanOmitRC4LHSVar(const MeStmt &stmt, bool &onlyWithDecref) cons onlyWithDecref = false; return false; } + // except reset of localrefvar because of special handle throw operand + if ((func.GetHints() & kPlacementRCed) && theRhs->GetOp() == OP_constval) { + return false; + } return true; } break; @@ -588,7 +594,9 @@ bool DelegateRC::CanOmitRC4LHSVar(const MeStmt &stmt, bool &onlyWithDecref) cons return false; } const OriginalSt *ost = theLhs->GetOst(); - if (!ost->IsLocal() || ost->IsFormal()) { + if (!ost->IsLocal() || ost->IsFormal() || + // avoid multi-version vars because of it is hard to find the decrefreset. + ((func.GetHints() & kPlacementRCed) && ssaTab.GetVersionsIndicesSize(ost->GetIndex()) > 2)) { return false; } if (verStCantDelegate[theLhs->GetVstIdx()]) { @@ -786,6 +794,26 @@ void DelegateRC::CleanUpDeadLocalRefVar(const std::set &liveLocalrefvars } intrin->EraseOpnds(intrin->GetOpnds().begin() + nextPos, intrin->GetOpnds().end()); } + if (func.GetHints() & kPlacementRCed) { // delete decref if opnd not in livelocalrefvars + auto eIt = func.valid_end(); + for (auto bIt = func.valid_begin(); bIt != eIt; ++bIt) { + auto *bb = *bIt; + for (auto &stmt : bb->GetMeStmts()) { + if (stmt.GetOp() != OP_decrefreset) { + continue; + } + if (stmt.GetOpnd(0)->GetMeOp() != kMeOpAddrof) { + continue; + } + auto *varMeExpr = static_cast(stmt.GetOpnd(0)); + const OriginalSt *ost = ssaTab.GetOriginalStFromID(varMeExpr->GetOstIdx()); + if (ost->IsLocal() && !ost->IsFormal() && !ost->IsIgnoreRC() && + liveLocalrefvars.find(varMeExpr->GetOstIdx()) == liveLocalrefvars.end()) { + bb->RemoveMeStmt(&stmt); + } + } + } + } } AnalysisResult *MeDoDelegateRC::Run(MeFunction *func, MeFuncResultMgr *m, ModuleResultMgr*) { diff --git a/src/mapleall/maple_me/src/me_emit.cpp b/src/mapleall/maple_me/src/me_emit.cpp index 8aa69c97a64c3e687f671f3c372588ef25a6121e..d568e8ee82508b319b0636ea5f83d8423c631d09 100644 --- a/src/mapleall/maple_me/src/me_emit.cpp +++ b/src/mapleall/maple_me/src/me_emit.cpp @@ -13,13 +13,18 @@ * See the Mulan PSL v2 for more details. */ #include "me_emit.h" +#include +#include "thread_env.h" #include "me_bb_layout.h" #include "me_irmap.h" #include "me_cfg.h" +#include "constantfold.h" namespace maple { // emit IR to specified file AnalysisResult *MeDoEmit::Run(MeFunction *func, MeFuncResultMgr*, ModuleResultMgr*) { + static std::mutex mtx; + ParallelGuard guard(mtx, ThreadEnv::IsMeParallel()); if (func->NumBBs() > 0) { CHECK_FATAL(func->GetIRMap() != nullptr, "Why not hssa?"); // generate bblist after layout (bb physical position) @@ -43,6 +48,8 @@ AnalysisResult *MeDoEmit::Run(MeFunction *func, MeFuncResultMgr*, ModuleResultMg ASSERT(bb != nullptr, "Check bblayout phase"); bb->EmitBB(*func->GetMeSSATab(), *mirFunction->GetBody(), false); } + ConstantFold cf(func->GetMIRModule()); + cf.Simplify(func->GetMirFunc()->GetBody()); if (DEBUGFUNC(func)) { LogInfo::MapleLogger() << "\n==============after meemit =============" << '\n'; func->GetMirFunc()->Dump(); diff --git a/src/mapleall/maple_me/src/me_func_opt.cpp b/src/mapleall/maple_me/src/me_func_opt.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ab9094a4b29d7861e1d7ec0fe3287d64a428a02f --- /dev/null +++ b/src/mapleall/maple_me/src/me_func_opt.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "me_func_opt.h" +#include "thread_env.h" + +namespace maple { +thread_local std::unique_ptr MeFuncOptScheduler::funcOptLocal; + +int MeFuncOptTask::RunImpl(MplTaskParam *param) { + module.SetCurFunction(&mirFunc); + auto *optExe = static_cast(param); + CHECK_NULL_FATAL(optExe); + optExe->ProcessRun(mirFunc, rangeNum, meInput); + return 0; +} + +std::unique_ptr MeFuncOptExecutor::Clone() const { + // thread local memPoolCtrler and fpm + auto threadLocalCtrler = std::make_unique(); + auto *memPool = threadLocalCtrler->NewMemPool("thread local func opt mempool"); + MeFuncPhaseManager &fpmCopy = fpm.Clone(*memPool, *threadLocalCtrler); + auto copy = std::make_unique(std::move(threadLocalCtrler), fpmCopy); + return copy; +} + +void MeFuncOptExecutor::ProcessRun(MIRFunction &mirFunc, size_t rangeNum, const std::string &meInput) { + fpm.Run(&mirFunc, rangeNum, meInput, *mpCtrler); +} + +void MeFuncOptScheduler::CallbackThreadMainStart() { + ThreadEnv::InitThreadIndex(std::this_thread::get_id()); + funcOptLocal = funcOpt->Clone(); +} + +void MeFuncOptScheduler::CallbackThreadMainEnd() { + funcOptLocal = nullptr; +} + +MplTaskParam *MeFuncOptScheduler::CallbackGetTaskRunParam() const { + return funcOptLocal.get(); +} + +MplTaskParam *MeFuncOptScheduler::CallbackGetTaskFinishParam() const { + return funcOptLocal.get(); +} + +void MeFuncOptScheduler::AddFuncOptTask(MIRModule &module, MIRFunction &mirFunc, + size_t rangeNum, const std::string &meInput) { + std::unique_ptr task = std::make_unique(module, mirFunc, rangeNum, meInput); + AddTask(task.get()); + tasksUniquePtr.emplace_back(std::move(task)); +} +} // namespace maple diff --git a/src/mapleall/maple_me/src/me_gc_lowering.cpp b/src/mapleall/maple_me/src/me_gc_lowering.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1ac38a8decb757538699b8eb89048ac36babcdf3 --- /dev/null +++ b/src/mapleall/maple_me/src/me_gc_lowering.cpp @@ -0,0 +1,285 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "me_gc_lowering.h" +#include + +// GCLowering phase generate GC intrinsic for reference assignment +// based on previous analyze results. GC intrinsic will later be lowered +// in Code Generation +namespace maple { +AnalysisResult *MeDoGCLowering::Run(MeFunction *func, MeFuncResultMgr *funcMgr, ModuleResultMgr*) { + if (func->GetIRMap() == nullptr) { + auto *hMap = static_cast(funcMgr->GetAnalysisResult(MeFuncPhase_IRMAPBUILD, func)); + CHECK_NULL_FATAL(hMap); + func->SetIRMap(hMap); + } + + GCLowering gcLowering(*func, DEBUGFUNC(func)); + gcLowering.Prepare(); + gcLowering.GCLower(); + gcLowering.Finish(); + return nullptr; +} + +void GCLowering::Prepare() { + isReferent = func.GetMirFunc()->GetName() == "Ljava_2Flang_2Fref_2FReference_3B_7C_3Cinit_3E_7C_" + "28Ljava_2Flang_2FObject_3BLjava_2Flang_2Fref_2FReferenceQueue_3B_29V"; + // preparation steps before going through basicblocks + MIRFunction *mirFunction = func.GetMirFunc(); + size_t tableSize = mirFunction->GetSymTab()->GetSymbolTableSize(); + for (size_t i = 0; i < tableSize; ++i) { + MIRSymbol *sym = mirFunction->GetSymTab()->GetSymbolFromStIdx(i); + if (sym != nullptr && sym->GetStorageClass() == kScAuto) { + MIRType *type = sym->GetType(); + if (type != nullptr && type->GetPrimType() == PTY_ref) { + sym->SetLocalRefVar(); + } + } + } +} + +void GCLowering::GCLower() { + auto eIt = func.valid_end(); + for (auto bIt = func.valid_begin(); bIt != eIt; ++bIt) { + if (bIt == func.common_entry() || bIt == func.common_exit()) { + continue; + } + GCLower(**bIt); + } +} + +void GCLowering::Finish() { + CheckRefs(); + if (enabledDebug) { + LogInfo::MapleLogger() << "\n============== After GC LOWERING =============" << '\n'; + func.Dump(false); + } +} + +void GCLowering::GCLower(BB &bb) { + for (auto &stmt : bb.GetMeStmts()) { + if (stmt.IsAssign()) { + HandleAssignMeStmt(stmt); + } + } +} + +void GCLowering::HandleAssignMeStmt(MeStmt &stmt) { + MeExpr *lhs = stmt.GetLHSRef(false); + if (lhs == nullptr) { + return; + } + if (lhs->GetMeOp() == kMeOpVar) { + HandleVarAssignMeStmt(stmt); + } else if (lhs->GetMeOp() == kMeOpIvar) { + HandleIvarAssignMeStmt(stmt); + } +} + +void GCLowering::HandleVarAssignMeStmt(MeStmt &stmt) { + VarMeExpr *lhsVar = stmt.GetVarLHS(); + ASSERT_NOT_NULL(lhsVar); + MIRSymbol *lSym = ssaTab.GetMIRSymbolFromID(lhsVar->GetOstIdx()); + if (lSym == nullptr || !lSym->IsGlobal()) { + return; + } + std::vector opnds = { irMap.CreateAddrofMeExpr(*lhsVar), stmt.GetRHS() }; + MeStmt *writeRefCall = irMap.CreateIntrinsicCallMeStmt(SelectWriteBarrier(stmt), opnds); + stmt.GetBB()->ReplaceMeStmt(&stmt, writeRefCall); +} + +MIRIntrinsicID GCLowering::SelectWriteBarrier(MeStmt &stmt) { + MeExpr *lhs = stmt.GetLHS(); + CHECK_NULL_FATAL(lhs); + MeExprOp meOp = lhs->GetMeOp(); + CHECK_FATAL((meOp == kMeOpVar || meOp == kMeOpIvar), "Not Expected meOp"); + if (lhs->IsVolatile()) { + return PrepareVolatileCall(stmt, meOp == kMeOpVar ? INTRN_MCCWriteSVol : INTRN_MCCWriteVol); + } + return meOp == kMeOpVar ? INTRN_MCCWriteS : INTRN_MCCWrite; +} + +static inline void CheckRemove(const MeStmt *stmt, Opcode op) { + if (stmt != nullptr && stmt->GetOp() == op) { + stmt->GetBB()->RemoveMeStmt(stmt); + } +} + +MIRIntrinsicID GCLowering::PrepareVolatileCall(MeStmt &stmt, MIRIntrinsicID intrnId) { + CheckRemove(stmt.GetPrev(), OP_membarrelease); + CheckRemove(stmt.GetNext(), OP_membarstoreload); + return intrnId; +} + +void GCLowering::HandleIvarAssignMeStmt(MeStmt &stmt) { + auto &iAssignStmt = static_cast(stmt); + HandleWriteReferent(iAssignStmt); + IvarMeExpr *lhsInner = iAssignStmt.GetLHSVal(); + MeExpr *base = GetBase(*lhsInner); + std::vector opnds = { &(base->GetAddrExprBase()), + irMap.CreateAddrofMeExpr(*lhsInner), stmt.GetRHS() }; + MeStmt *writeRefCall = irMap.CreateIntrinsicCallMeStmt(SelectWriteBarrier(stmt), opnds); + stmt.GetBB()->ReplaceMeStmt(&stmt, writeRefCall); +} + +MeExpr *GCLowering::GetBase(IvarMeExpr &ivar) { + MeExpr *base = ivar.GetBase(); + CHECK_NULL_FATAL(base); + if (!Options::buildApp || ivar.GetFieldID() != 0 || base->GetMeOp() != kMeOpReg) { + return base; + } + MeExpr *expr = base; + while (expr->GetMeOp() == kMeOpReg) { + auto *reg = static_cast(expr); + if (reg->GetDefBy() != kDefByStmt) { + break; + } + expr = reg->GetDefStmt()->GetRHS(); + CHECK_NULL_FATAL(expr); + } + if (expr->GetOp() != OP_add) { + return base; + } + while (expr->GetOpnd(0)->GetOp() == OP_add) { + expr = expr->GetOpnd(0); + ASSERT_NOT_NULL(expr); + } + if (expr->GetMeOp() == kMeOpNary) { + auto *naryExp = static_cast(expr); + MIRIntrinsicID intrinID = naryExp->GetIntrinsic(); + if (intrinID == INTRN_MPL_READ_OVTABLE_ENTRY || + intrinID == INTRN_MPL_READ_OVTABLE_ENTRY2 || + intrinID == INTRN_MPL_READ_OVTABLE_ENTRY_LAZY || + intrinID == INTRN_MPL_READ_OVTABLE_ENTRY_VTAB_LAZY || + intrinID == INTRN_MPL_READ_OVTABLE_ENTRY_FIELD_LAZY) { + return expr->GetOpnd(0); + } + } + return base; +} + +void GCLowering::HandleWriteReferent(IassignMeStmt &stmt) { + if (!isReferent) { + return; + } + IvarMeExpr *lhsInner = stmt.GetLHSVal(); + MIRType *baseType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(lhsInner->GetTyIdx()); + MIRType *ptype = utils::ToRef(safe_cast(baseType)).GetPointedType(); + FieldID id = mirModule.GetMIRBuilder()->GetStructFieldIDFromFieldNameParentFirst(ptype, "referent"); + if (id != lhsInner->GetFieldID()) { + return; + } + CheckRemove(stmt.GetNext(), OP_membarstoreload); + std::vector opnds = { &(lhsInner->GetBase()->GetAddrExprBase()), stmt.GetRHS() }; + MeStmt *writeReferentCall = irMap.CreateIntrinsicCallMeStmt(INTRN_MCCWriteReferent, opnds); + stmt.GetBB()->InsertMeStmtAfter(&stmt, writeReferentCall); +} + +// DFX Support: +// traverse all statement, and add MCCGCCheck for each ref +// Formals of type ref +// LHS of type ref in assign +// return value of type ref +void GCLowering::CheckRefs() { + ParseCheckFlag(); + if (checkRefFormal) { + CheckFormals(); + } + for (BB *bb : func.GetAllBBs()) { + if (bb == nullptr) { + continue; + } + if (checkRefAssign) { + CheckRefsInAssignStmt(*bb); + } + if (checkRefReturn) { + CheckRefReturn(*bb); + } + } +} + +void GCLowering::ParseCheckFlag() { + if (MeOption::checkRefUsedInFuncs.find(func.GetName()) != MeOption::checkRefUsedInFuncs.end() || + MeOption::checkRefUsedInFuncs.find("ALL") != MeOption::checkRefUsedInFuncs.end() || + MeOption::checkRefUsedInFuncs.find("*") != MeOption::checkRefUsedInFuncs.end()) { + checkRefFormal = true; + checkRefAssign = true; + checkRefReturn = true; + } else { + if (MeOption::checkRefUsedInFuncs.find("FORMAL") != MeOption::checkRefUsedInFuncs.end()) { + checkRefFormal = true; + } + if (MeOption::checkRefUsedInFuncs.find("ASSIGN") != MeOption::checkRefUsedInFuncs.end()) { + checkRefAssign = true; + } + if (MeOption::checkRefUsedInFuncs.find("RETURN") != MeOption::checkRefUsedInFuncs.end()) { + checkRefReturn = true; + } + } +} + +void GCLowering::CheckFormals() { + MIRFunction *mirFunc = func.GetMirFunc(); + if (mirFunc->IsEmpty()) { + return; + } + + BB *firstBB = func.GetFirstBB(); + for (size_t i = 0; i < mirFunc->GetFormalCount(); ++i) { + MIRSymbol *formalSt = mirFunc->GetFormal(i); + if (formalSt == nullptr || formalSt->GetType()->GetPrimType() != PTY_ref) { + continue; + } + OriginalSt *ost = ssaTab.FindOrCreateSymbolOriginalSt(*formalSt, func.GetMirFunc()->GetPuidx(), 0); + MeExpr *argVar = irMap.GetOrCreateZeroVersionVarMeExpr(*ost); + std::vector opnds = { argVar }; + IntrinsiccallMeStmt *checkCall = irMap.CreateIntrinsicCallMeStmt(INTRN_MCCGCCheck, opnds); + firstBB->AddMeStmtFirst(checkCall); + } +} + +void GCLowering::CheckRefsInAssignStmt(BB &bb) { + for (MeStmt &stmt : bb.GetMeStmts()) { + if (!stmt.IsAssign()) { + continue; + } + MeExpr *lhs = stmt.GetLHS(); + CHECK_NULL_FATAL(lhs); + if (lhs->GetPrimType() != PTY_ref && lhs->GetPrimType() != PTY_ptr) { + continue; + } + std::vector opnds = { lhs }; + IntrinsiccallMeStmt *checkCall = irMap.CreateIntrinsicCallMeStmt(INTRN_MCCGCCheck, opnds); + bb.InsertMeStmtAfter(&stmt, checkCall); + } +} + +void GCLowering::CheckRefReturn(BB &bb) { + if (bb.GetKind() != kBBReturn) { + return; + } + MeStmt *lastMeStmt = to_ptr(bb.GetMeStmts().rbegin()); + if (lastMeStmt == nullptr || lastMeStmt->GetOp() != OP_return || lastMeStmt->NumMeStmtOpnds() == 0) { + return; + } + MeExpr* ret = lastMeStmt->GetOpnd(0); + if (ret->GetPrimType() != PTY_ref && ret->GetPrimType() != PTY_ptr) { + return; + } + std::vector opnds = { ret }; + IntrinsiccallMeStmt *checkCall = irMap.CreateIntrinsicCallMeStmt(INTRN_MCCGCCheck, opnds); + bb.InsertMeStmtBefore(lastMeStmt, checkCall); +} +} // namespace maple diff --git a/src/mapleall/maple_me/src/me_gc_write_barrier_opt.cpp b/src/mapleall/maple_me/src/me_gc_write_barrier_opt.cpp new file mode 100644 index 0000000000000000000000000000000000000000..90af5be89ad91fae0b22a83c135d5d66c640fe7e --- /dev/null +++ b/src/mapleall/maple_me/src/me_gc_write_barrier_opt.cpp @@ -0,0 +1,231 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "me_gc_write_barrier_opt.h" +#include "dominance.h" + +// GCWriteBarrierOpt phase generate GC intrinsic for reference assignment +// based on previous analyze results. GC intrinsic will later be lowered +// in Code Generation +namespace maple { +AnalysisResult *MeDoGCWriteBarrierOpt::Run(MeFunction *func, MeFuncResultMgr *funcResMgr, ModuleResultMgr*) { + Dominance *dom = static_cast(funcResMgr->GetAnalysisResult(MeFuncPhase_DOMINANCE, func)); + CHECK_FATAL(dom != nullptr, "dominance phase has problem"); + + GCWriteBarrierOpt gcWriteBarrierOpt(*func, *dom, DEBUGFUNC(func)); + gcWriteBarrierOpt.Prepare(); + std::map> writeBarrierMap; + BB *entryBB = func->GetCommonEntryBB(); + gcWriteBarrierOpt.GCLower(*entryBB, writeBarrierMap); + gcWriteBarrierOpt.Finish(); + return nullptr; +} + +void GCWriteBarrierOpt::Prepare() { + if (enabledDebug) { + LogInfo::MapleLogger() << "\n============== Before GC WRITE BARRIER OPT =============" << '\n'; + func.Dump(false); + } +} + +void GCWriteBarrierOpt::GCLower(BB &bb, std::map> &writeBarrierMap) { + // to record stack size + std::map savedStacksize; + for (const auto &item : writeBarrierMap) { + savedStacksize[item.first] = item.second.size(); + } + for (auto &stmt : bb.GetMeStmts()) { + if (!visited[bb.GetBBId()] && IsCall(stmt)) { + callBBs[bb.GetBBId()] = true; + visited[bb.GetBBId()] = true; + } + if (IsWriteBarrier(stmt)) { + IntrinsiccallMeStmt &intrinsicCall = static_cast(stmt); + MeExpr *opnd = intrinsicCall.GetOpnd(0); + OStIdx ostIdx = GetOStIdx(*opnd); + CHECK_FATAL(ostIdx != 0u, "ostIdx is not expected."); + std::vector &stmtVec = writeBarrierMap[ostIdx]; + if (stmtVec.empty()) { + stmtVec.push_back(&stmt); + callBBs[bb.GetBBId()] = true; + } else { + MeStmt *start = stmtVec.back(); + if (!HasYieldPoint(*start, stmt)) { + ResetMeStmt(intrinsicCall); + } else { + stmtVec.push_back(&stmt); + callBBs[bb.GetBBId()] = true; + } + } + } + } + visited[bb.GetBBId()] = true; + const MapleSet domChildren = dominance.GetDomChildren(bb.GetBBId()); + for (const auto &childBBId : domChildren) { + BB *child = func.GetAllBBs().at(childBBId); + if (child == nullptr) { + continue; + } + GCLower(*child, writeBarrierMap); + } + // restore the stacks to their size at entry to this function invocation + for (auto &item : writeBarrierMap) { + size_t lastSize = savedStacksize[item.first]; + while (item.second.size() > lastSize) { + item.second.pop_back(); + } + } +} + +bool GCWriteBarrierOpt::IsWriteBarrier(const MeStmt &stmt) { + if (stmt.GetOp() != OP_intrinsiccall) { + return false; + } + const IntrinsiccallMeStmt &intrinsicCall = static_cast(stmt); + MIRIntrinsicID id = intrinsicCall.GetIntrinsic(); + return id == INTRN_MCCWriteS || id == INTRN_MCCWrite; +} + +void GCWriteBarrierOpt::ResetMeStmt(IntrinsiccallMeStmt &stmt) { + MeStmt *meStmt = nullptr; + MeExpr *rhs = stmt.GetOpnds().back(); + if (stmt.GetIntrinsic() == INTRN_MCCWrite) { + OpMeExpr *opnd = static_cast(stmt.GetOpnd(1)); + IvarMeExpr *ivar = irMap.BuildLHSIvar(*opnd->GetOpnd(0), opnd->GetPrimType(), + opnd->GetTyIdx(), opnd->GetFieldID()); + MapleMap *chiList = stmt.GetChiList(); + meStmt = irMap.CreateIassignMeStmt(opnd->GetTyIdx(), *ivar, *rhs, *chiList); + } else { + MeExpr *lhs = stmt.GetOpnds().front(); + if (lhs->GetMeOp() == kMeOpReg) { + meStmt = irMap.CreateRegassignMeStmt(*lhs, *rhs, *stmt.GetBB()); + } else { + CHECK_FATAL((lhs->GetMeOp() == kMeOpVar && stmt.GetIntrinsic() == INTRN_MCCWriteS), "Not Expected."); + auto *ost = ssaTab.GetOriginalStFromID(GetOStIdx(*lhs)); + VarMeExpr *lhsVar = irMap.GetOrCreateZeroVersionVarMeExpr(*ost); + meStmt = irMap.CreateDassignMeStmt(*lhsVar, *rhs, *stmt.GetBB()); + } + } + stmt.GetBB()->ReplaceMeStmt(&stmt, meStmt); +} + +OStIdx GCWriteBarrierOpt::GetOStIdx(MeExpr &meExpr) { + MeExprOp meOp = meExpr.GetMeOp(); + switch (meOp) { + case kMeOpAddrof: + return (static_cast(meExpr)).GetOstIdx(); + case kMeOpVar: + return (static_cast(meExpr)).GetOstIdx(); + case kMeOpReg: + return (static_cast(meExpr)).GetOstIdx(); + case kMeOpIvar: + return GetOStIdx(*((static_cast(meExpr)).GetBase())); + default: + CHECK_FATAL(meOp == kMeOpReg, "MeOp is not expected."); + break; + } + return OStIdx(0); +} + +bool GCWriteBarrierOpt::IsCall(const MeStmt &stmt) { + return kOpcodeInfo.IsCall(stmt.GetOp()) && !IsWriteBarrier(stmt); +} + +bool GCWriteBarrierOpt::HasYieldPoint(const MeStmt &start, const MeStmt &end) { + BB *startBB = start.GetBB(); + BB *endBB = end.GetBB(); + if (startBB == endBB) { + return HasCallBetweenStmt(start, end); + } + if (!dominance.Dominate(*startBB, *endBB)) { + return true; + } + if (HasCallAfterStmt(start) || HasCallBeforeStmt(end) || IsBackEdgeDest(*endBB)) { + return true; + } + const MapleSet domChildren = dominance.GetDomChildren(startBB->GetBBId()); + const MapleSet pdomChildren = dominance.GetPdomChildrenItem(endBB->GetBBId()); + const MapleVector bbVec = func.GetAllBBs(); + for (const auto &childBBId : domChildren) { + if (pdomChildren.find(childBBId) == pdomChildren.end()) { + continue; + } + BB *bb = bbVec.at(childBBId); + if (bb == nullptr) { + continue; + } + if (IsBackEdgeDest(*bb)) { + return true; + } + if (HasCallInBB(*bb)) { + return true; + } + } + return false; +} + +bool GCWriteBarrierOpt::HasCallAfterStmt(const MeStmt &stmt) { + const MeStmt &lastMeStmt = stmt.GetBB()->GetMeStmts().back(); + return HasCallBetweenStmt(stmt, lastMeStmt); +} + +bool GCWriteBarrierOpt::HasCallBeforeStmt(const MeStmt &stmt) { + const MeStmt &firstMeStmt = stmt.GetBB()->GetMeStmts().front(); + return HasCallBetweenStmt(firstMeStmt, stmt); +} + +bool GCWriteBarrierOpt::HasCallBetweenStmt(const MeStmt &start, const MeStmt &end) { + CHECK_FATAL(start.GetBB() == end.GetBB(), "NYI."); + for (const MeStmt *meStmt = &start; meStmt != &end; meStmt = meStmt->GetNext()) { + if (IsCall(*meStmt)) { + return true; + } + } + return IsCall(end); +} + +bool GCWriteBarrierOpt::IsBackEdgeDest(const BB &bb) { + for (BB *pred : bb.GetPred()) { + if (dominance.Dominate(bb, *pred)) { + return true; + } + } + return false; +} + +bool GCWriteBarrierOpt::HasCallInBB(const BB &bb) { + BBId id = bb.GetBBId(); + if (callBBs.at(id)) { + return true; + } else if (visited.at(id)) { + return false; + } + for (auto &stmt : bb.GetMeStmts()) { + if (IsCall(stmt)) { + callBBs[id] = true; + visited[id] = true; + return true; + } + } + visited[id] = true; + return false; +} + +void GCWriteBarrierOpt::Finish() { + if (enabledDebug) { + LogInfo::MapleLogger() << "\n============== After GC WRITE BARRIER OPT =============" << '\n'; + func.Dump(false); + } +} +} // namespace maple diff --git a/src/mapleall/maple_me/src/me_loop_unrolling.cpp b/src/mapleall/maple_me/src/me_loop_unrolling.cpp new file mode 100644 index 0000000000000000000000000000000000000000..553a9dfbe50df7dc780f45f82d0c9947f489f955 --- /dev/null +++ b/src/mapleall/maple_me/src/me_loop_unrolling.cpp @@ -0,0 +1,1292 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "me_loop_unrolling.h" +#include +#include +#include "me_cfg.h" +#include "me_option.h" +#include "mir_module.h" +#include "mir_builder.h" + +namespace maple { +bool MeDoLoopUnrolling::enableDebug = false; +bool MeDoLoopUnrolling::enableDump = false; +constexpr uint32 kOneInsn = 1; +constexpr uint32 kTwoInsn = 2; +constexpr uint32 kThreeInsn = 3; +constexpr uint32 kFiveInsn = 5; +constexpr uint32 kMaxIndex = 2; +constexpr uint32 kLoopBodyNum = 1; +constexpr uint32 kOperandNum = 2; + +void LoopUnrolling::InsertCandsForSSAUpdate(OStIdx ostIdx, const BB &bb) { + if (cands.find(ostIdx) == cands.end()) { + MapleSet *bbSet = memPool->New>(std::less(), mpAllocator.Adapter()); + bbSet->insert(bb.GetBBId()); + cands[ostIdx] = bbSet; + } else { + cands[ostIdx]->insert(bb.GetBBId()); + } +} + +void LoopUnrolling::BuildChiList(const BB &bb, MeStmt &newStmt, const MapleMap &oldChilist, + MapleMap &newChiList) { + CHECK_FATAL(newChiList.empty(), "must be empty"); + for (auto &chiNode : oldChilist) { + CHECK_FATAL(chiNode.first == chiNode.second->GetLHS()->GetOstIdx(), "must be"); + VarMeExpr *newMul = irMap->CreateVarMeExprVersion(chiNode.second->GetLHS()->GetOst()); + InsertCandsForSSAUpdate(newMul->GetOstIdx(), bb); + ChiMeNode *newChiNode = irMap->New(&newStmt); + newMul->SetDefChi(*newChiNode); + newMul->SetDefBy(kDefByChi); + newChiNode->SetLHS(newMul); + newChiNode->SetRHS(chiNode.second->GetRHS()); + CHECK_FATAL(newChiList.find(chiNode.first) == newChiList.end(), "must not exit"); + newChiList[chiNode.first] = newChiNode; + } +} + +void LoopUnrolling::BuildMustDefList(const BB &bb, MeStmt &newStmt, const MapleVector &oldMustDef, + MapleVector &newMustDef) { + CHECK_FATAL(newMustDef.empty(), "must be empty"); + for (auto &mustDefNode : oldMustDef) { + const VarMeExpr *varLHS = static_cast(mustDefNode.GetLHS()); + CHECK_FATAL(varLHS->GetMeOp() == kMeOpReg || varLHS->GetMeOp() == kMeOpVar, "unexpected opcode"); + VarMeExpr *newVarLHS = irMap->CreateVarMeExprVersion(varLHS->GetOst()); + newVarLHS->SetDefBy(kDefByMustDef); + InsertCandsForSSAUpdate(newVarLHS->GetOstIdx(), bb); + auto *mustDef = irMap->New(newVarLHS, &newStmt); + newVarLHS->SetDefMustDef(*mustDef); + newMustDef.push_back(*mustDef); + } +} + +void LoopUnrolling::CopyDassignStmt(const MeStmt &stmt, BB &bb) { + VarMeExpr *varLHS = static_cast(&stmt)->GetVarLHS(); + VarMeExpr *newVarLHS = irMap->CreateVarMeExprVersion(varLHS->GetOst()); + InsertCandsForSSAUpdate(newVarLHS->GetOstIdx(), bb); + bb.AddMeStmtLast(irMap->CreateDassignMeStmt(*newVarLHS, *stmt.GetRHS(), bb)); +} + +void LoopUnrolling::CopyIassignStmt(MeStmt &stmt, BB &bb) { + auto *iassStmt = static_cast(&stmt); + IvarMeExpr *ivar = irMap->BuildLHSIvarFromIassMeStmt(*iassStmt); + IassignMeStmt *newIassStmt = irMap->NewInPool( + iassStmt->GetTyIdx(), *static_cast(ivar), *iassStmt->GetRHS()); + BuildChiList(bb, *newIassStmt, *iassStmt->GetChiList(), *newIassStmt->GetChiList()); + bb.AddMeStmtLast(newIassStmt); +} + +void LoopUnrolling::CopyIntrinsiccallStmt(MeStmt &stmt, BB &bb) { + auto *intrnStmt = static_cast(&stmt); + IntrinsiccallMeStmt *newIntrnStmt = + irMap->NewInPool(static_cast(intrnStmt), intrnStmt->GetIntrinsic(), + intrnStmt->GetTyIdx(), intrnStmt->GetReturnPrimType()); + for (auto &mu : *intrnStmt->GetMuList()) { + CHECK_FATAL(newIntrnStmt->GetMuList()->find(mu.first) == newIntrnStmt->GetMuList()->end(), "must not exit"); + newIntrnStmt->GetMuList()->insert(std::make_pair(mu.first, mu.second)); + } + BuildChiList(bb, *newIntrnStmt, *intrnStmt->GetChiList(), *newIntrnStmt->GetChiList()); + BuildMustDefList(bb, *newIntrnStmt, *intrnStmt->GetMustDefList(), *newIntrnStmt->GetMustDefList()); + bb.AddMeStmtLast(newIntrnStmt); +} + +void LoopUnrolling::CopyCallStmt(MeStmt &stmt, BB &bb) { + auto *callStmt = static_cast(&stmt); + if (callStmt->GetAssignedLHS() != nullptr) { + CHECK_FATAL(callStmt->GetAssignedLHS()->GetMeOp() == kMeOpVar, "should be var"); + } + CallMeStmt *newCallStmt = + irMap->NewInPool(static_cast(callStmt), callStmt->GetPUIdx()); + for (auto &mu : *callStmt->GetMuList()) { + CHECK_FATAL(newCallStmt->GetMuList()->find(mu.first) == newCallStmt->GetMuList()->end(), "must not exit"); + newCallStmt->GetMuList()->insert(std::make_pair(mu.first, mu.second)); + } + BuildChiList(bb, *newCallStmt, *callStmt->GetChiList(), *newCallStmt->GetChiList()); + BuildMustDefList(bb, *newCallStmt, *callStmt->GetMustDefList(), *newCallStmt->GetMustDefList()); + bb.AddMeStmtLast(newCallStmt); +} + +void LoopUnrolling::CopyAndInsertStmt(BB &bb, std::vector &meStmts) { + for (auto stmt : meStmts) { + switch (stmt->GetOp()) { + case OP_dassign: { + CopyDassignStmt(*stmt, bb); + break; + } + case OP_iassign: { + CopyIassignStmt(*stmt, bb); + break; + } + case OP_maydassign: { + auto *maydassStmt = static_cast(stmt); + MaydassignMeStmt *newMaydassStmt = irMap->NewInPool(*maydassStmt); + BuildChiList(bb, *newMaydassStmt, *maydassStmt->GetChiList(), *newMaydassStmt->GetChiList()); + bb.AddMeStmtLast(newMaydassStmt); + break; + } + case OP_goto: { + auto *gotoStmt = static_cast(stmt); + GotoMeStmt *newGotoStmt = irMap->New(*gotoStmt); + bb.AddMeStmtLast(newGotoStmt); + break; + } + case OP_brfalse: + case OP_brtrue: { + auto *condGotoStmt = static_cast(stmt); + CondGotoMeStmt *newCondGotoStmt = irMap->New(*condGotoStmt); + bb.AddMeStmtLast(newCondGotoStmt); + break; + } + case OP_intrinsiccall: + case OP_intrinsiccallassigned: + case OP_intrinsiccallwithtype: { + CopyIntrinsiccallStmt(*stmt, bb); + break; + } + case OP_call: + case OP_callassigned: + case OP_virtualcallassigned: + case OP_virtualicallassigned: + case OP_interfaceicallassigned: { + CopyCallStmt(*stmt, bb); + break; + } + case OP_assertnonnull: { + auto *unaryStmt = static_cast(stmt); + UnaryMeStmt *newUnaryStmt = irMap->New(unaryStmt); + bb.AddMeStmtLast(newUnaryStmt); + break; + } + case OP_membaracquire: + case OP_membarrelease: + case OP_membarstoreload: + case OP_membarstorestore: { + auto *newStmt = irMap->New(stmt->GetOp()); + bb.AddMeStmtLast(newStmt); + break; + } + case OP_comment: { + break; + } + default: + LogInfo::MapleLogger() << "consider this op :"<< stmt->GetOp() << "\n"; + CHECK_FATAL(false, "consider"); + break; + } + } +} + +void LoopUnrolling::ComputeCodeSize(const MeStmt &meStmt, uint32 &cost) { + switch (meStmt.GetOp()) { + case OP_switch: { + canUnroll = false; + break; + } + case OP_comment: { + break; + } + case OP_goto: + case OP_dassign: + case OP_membarrelease: { + cost += kOneInsn; + break; + } + case OP_brfalse: + case OP_brtrue: + case OP_maydassign: { + cost += kTwoInsn; + break; + } + case OP_iassign: + case OP_assertnonnull: + case OP_membaracquire: { + cost += kThreeInsn; + break; + } + case OP_call: + case OP_callassigned: + case OP_virtualcallassigned: + case OP_virtualicallassigned: + case OP_interfaceicallassigned: + case OP_intrinsiccall: + case OP_intrinsiccallassigned: + case OP_intrinsiccallwithtype: + case OP_membarstorestore: + case OP_membarstoreload: { + cost += kFiveInsn; + break; + } + default: + if (MeDoLoopUnrolling::enableDebug) { + LogInfo::MapleLogger() << "consider this op :"<< meStmt.GetOp() << "\n"; + } + CHECK_FATAL(false, "not support"); + canUnroll = false; + break; + } +} + +BB *LoopUnrolling::CopyBB(BB &bb, bool isInLoop) { + BB *newBB = func->NewBasicBlock(); + if (isInLoop) { + newBB->SetAttributes(kBBAttrIsInLoop); + } + newBB->SetKind(bb.GetKind()); + std::vector meStmts; + for (auto &meStmt : bb.GetMeStmts()) { + meStmts.push_back(&meStmt); + } + CopyAndInsertStmt(*newBB, meStmts); + return newBB; +} + +void LoopUnrolling::SetLabelWithCondGotoOrGotoBB(BB &bb, std::unordered_map &old2NewBB, const BB &exitBB, + LabelIdx oldlabIdx) { + CHECK_FATAL(!bb.GetMeStmts().empty(), "must not be empty"); + for (auto succ : bb.GetSucc()) { + // process in replace preds of exit bb + if (succ == &exitBB || old2NewBB.find(succ) == old2NewBB.end()) { + continue; + } + bool inLastNew2OldBB = false; + if (old2NewBB.find(succ) == old2NewBB.end()) { + for (auto it : lastNew2OldBB) { + if (it.second == succ) { + inLastNew2OldBB = true; + break; + } + } + if (inLastNew2OldBB) { + continue; + } else { + CHECK_FATAL(false, "impossible"); + } + } + if (oldlabIdx == succ->GetBBLabel()) { + LabelIdx label = old2NewBB[succ]->GetBBLabel(); + CHECK_FATAL(label != 0, "label must not be zero"); + if (bb.GetKind() == kBBCondGoto) { + static_cast(old2NewBB[&bb]->GetMeStmts().back()).SetOffset(label); + } else { + CHECK_FATAL(bb.GetKind() == kBBGoto, "must be kBBGoto"); + static_cast(old2NewBB[&bb]->GetMeStmts().back()).SetOffset(label); + } + } + } +} + +// When loop unroll times is two, use this function to update the preds and succs of the duplicate loopbody. +void LoopUnrolling::ResetOldLabel2NewLabel(std::unordered_map &old2NewBB, BB &bb, + const BB &exitBB, BB &newHeadBB) { + if (bb.GetKind() == kBBCondGoto) { + CHECK_FATAL(!bb.GetMeStmts().empty(), "must not be empty"); + CondGotoMeStmt &condGotoNode = static_cast(bb.GetMeStmts().back()); + LabelIdx oldlabIdx = condGotoNode.GetOffset(); + CHECK_FATAL(oldlabIdx == exitBB.GetBBLabel(), "must equal"); + LabelIdx label = func->GetOrCreateBBLabel(newHeadBB); + condGotoNode.SetOffset(label); + static_cast(newHeadBB.GetMeStmts().back()).SetOffset(oldlabIdx); + } else if (bb.GetKind() == kBBGoto) { + CHECK_FATAL(!bb.GetMeStmts().empty(), "must not be empty"); + GotoMeStmt &gotoStmt = static_cast(bb.GetMeStmts().back()); + LabelIdx oldlabIdx = gotoStmt.GetOffset(); + CHECK_FATAL(oldlabIdx == exitBB.GetBBLabel(), "must equal"); + LabelIdx label = func->GetOrCreateBBLabel(newHeadBB); + gotoStmt.SetOffset(label); + static_cast(old2NewBB[&bb]->GetMeStmts().back()).SetOffset(oldlabIdx); + } +} + +// When loop unroll times more than two, use this function to update the preds and succs of duplicate loopbodys. +void LoopUnrolling::ResetOldLabel2NewLabel2(std::unordered_map &old2NewBB, BB &bb, + const BB &exitBB, BB &newHeadBB) { + if (bb.GetKind() == kBBCondGoto) { + CHECK_FATAL(!bb.GetMeStmts().empty(), "must not be empty"); + CondGotoMeStmt &condGotoNode = static_cast(bb.GetMeStmts().back()); + LabelIdx oldlabIdx = condGotoNode.GetOffset(); + CHECK_FATAL(oldlabIdx == exitBB.GetBBLabel(), "must equal"); + LabelIdx label = func->GetOrCreateBBLabel(newHeadBB); + condGotoNode.SetOffset(label); + static_cast(newHeadBB.GetMeStmts().back()).SetOffset(oldlabIdx); + } else if (bb.GetKind() == kBBGoto) { + CHECK_FATAL(!bb.GetMeStmts().empty(), "must not be empty"); + GotoMeStmt &gotoStmt = static_cast(bb.GetMeStmts().back()); + LabelIdx oldlabIdx = gotoStmt.GetOffset(); + LabelIdx label = func->GetOrCreateBBLabel(newHeadBB); + gotoStmt.SetOffset(label); + static_cast(old2NewBB[lastNew2OldBB[&bb]]->GetMeStmts().back()).SetOffset(oldlabIdx); + } +} + +void LoopUnrolling::ResetFrequency(const BB &curBB, const BB &succ, const BB &exitBB, + BB &curCopyBB, bool copyAllLoop) { + if (resetFreqForUnrollWithVar && copyAllLoop) { + if (&curBB == &exitBB && &succ == *loop->inloopBB2exitBBs.begin()->second->begin()) { + curCopyBB.PushBackSuccFreq(loop->head->GetFrequency() % replicatedLoopNum == 0 ? 0 : 1); + } + if ((&curBB == loop->latch && &succ == loop->head) || (&curBB == &exitBB && &succ == loop->latch)) { + curCopyBB.PushBackSuccFreq(loop->head->GetFrequency() % replicatedLoopNum == 0 ? 0 : + loop->head->GetFrequency() % replicatedLoopNum - 1); + } else { + curCopyBB.PushBackSuccFreq(curBB.GetEdgeFreq(&succ) % replicatedLoopNum); + } + } else { + profValid && resetFreqForAfterInsertGoto ? + curCopyBB.PushBackSuccFreq(curBB.GetEdgeFreq(&succ) - 1 == 0 ? curBB.GetEdgeFreq(&succ) : + curBB.GetEdgeFreq(&succ) - 1) : + curCopyBB.PushBackSuccFreq(curBB.GetEdgeFreq(&succ)); + } +} + +void LoopUnrolling::CreateLableAndInsertLabelBB(BB &newHeadBB, std::set &labelBBs) { + if (loop->head->GetBBLabel() != 0) { + (void)func->GetOrCreateBBLabel(newHeadBB); + } + if (newHeadBB.GetKind() == kBBCondGoto || newHeadBB.GetKind() == kBBGoto) { + labelBBs.insert(loop->head); + } +} + +void LoopUnrolling::CopyLoopBodyForProfile(BB &newHeadBB, std::unordered_map &old2NewBB, + std::set &labelBBs, const BB &exitBB, bool copyAllLoop) { + CreateLableAndInsertLabelBB(newHeadBB, labelBBs); + std::queue bbQue; + bbQue.push(loop->head); + while (!bbQue.empty()) { + BB *curBB = bbQue.front(); + bbQue.pop(); + BB *curCopyBB = old2NewBB[curBB]; + for (BB *succ : curBB->GetSucc()) { + if (loop->loopBBs.find(succ->GetBBId()) == loop->loopBBs.end() || + (!copyAllLoop && (succ == &exitBB || succ == loop->latch))) { + continue; + } + if (old2NewBB.find(succ) != old2NewBB.end()) { + ResetFrequency(*curBB, *succ, exitBB, *curCopyBB, copyAllLoop); + curCopyBB->AddSucc(*old2NewBB[succ]); + } else { + if (needUpdateInitLoopFreq) { + ResetFrequency(*succ); + } + BB *newBB = CopyBB(*succ, true); + if (resetFreqForUnrollWithVar) { + if (succ == loop->latch) { + newBB->SetFrequency(loop->head->GetFrequency() % replicatedLoopNum - 1); + } else { + newBB->SetFrequency(succ->GetFrequency() % replicatedLoopNum); + } + } else { + resetFreqForAfterInsertGoto ? + newBB->SetFrequency(succ->GetFrequency() - 1 == 0 ? succ->GetFrequency() : + succ->GetFrequency() - 1) : + newBB->SetFrequency(succ->GetFrequency()); + } + curCopyBB->AddSucc(*newBB); + ResetFrequency(*curBB, *succ, exitBB, *curCopyBB, copyAllLoop); + old2NewBB.insert({ succ, newBB }); + bbQue.push(succ); + if (succ->GetBBLabel() != 0) { + (void)func->GetOrCreateBBLabel(*newBB); + } + if (succ->GetKind() == kBBCondGoto || succ->GetKind() == kBBGoto) { + labelBBs.insert(succ); + } + } + } + } +} + +void LoopUnrolling::CopyLoopBody(BB &newHeadBB, std::unordered_map &old2NewBB, + std::set &labelBBs, const BB &exitBB, bool copyAllLoop) { + CreateLableAndInsertLabelBB(newHeadBB, labelBBs); + std::queue bbQue; + bbQue.push(loop->head); + while (!bbQue.empty()) { + BB *curBB = bbQue.front(); + bbQue.pop(); + BB *curCopyBB = old2NewBB[curBB]; + for (BB *succ : curBB->GetSucc()) { + if (loop->loopBBs.find(succ->GetBBId()) == loop->loopBBs.end() || + (!copyAllLoop && (succ == &exitBB || succ == loop->latch))) { + continue; + } + if (old2NewBB.find(succ) != old2NewBB.end()) { + curCopyBB->AddSucc(*old2NewBB[succ]); + } else { + BB *newBB = CopyBB(*succ, true); + curCopyBB->AddSucc(*newBB); + CHECK_NULL_FATAL(newBB); + old2NewBB.insert({ succ, newBB }); + bbQue.push(succ); + if (succ->GetBBLabel() != 0) { + (void)func->GetOrCreateBBLabel(*newBB); + } + if (succ->GetKind() == kBBCondGoto || succ->GetKind() == kBBGoto) { + labelBBs.insert(succ); + } + } + } + } +} + +// Update frequency of old BB. +void LoopUnrolling::ResetFrequency(BB &bb) { + auto freq = bb.GetFrequency() / replicatedLoopNum; + if (freq == 0 && partialCount == 0 && bb.GetFrequency() != 0) { + freq = 1; + } + bb.SetFrequency(freq + partialCount); + for (size_t i = 0; i < bb.GetSucc().size(); ++i) { + auto currFreq = bb.GetEdgeFreq(i) / replicatedLoopNum; + if (currFreq == 0 && partialCount == 0 && bb.GetFrequency() != 0) { + currFreq = 1; + } + bb.SetEdgeFreq(bb.GetSucc(i), currFreq + partialCount); + } +} + +// Update frequency of old exiting BB and latch BB. +void LoopUnrolling::ResetFrequency() { + auto exitBB = func->GetBBFromID(loop->inloopBB2exitBBs.begin()->first); + auto latchBB = loop->latch; + if (isUnrollWithVar) { + auto latchFreq = loop->head->GetFrequency() % replicatedLoopNum - loop->preheader->GetFrequency(); + exitBB->SetFrequency(loop->head->GetFrequency() % replicatedLoopNum - latchFreq); + exitBB->SetEdgeFreq(latchBB, latchFreq); + latchBB->SetFrequency(latchFreq); + latchBB->SetEdgeFreq(loop->head, latchFreq); + } else { + auto exitFreq = exitBB->GetFrequency() / replicatedLoopNum; + if (exitFreq == 0 && exitBB->GetFrequency() != 0) { + exitFreq = 1; + } + exitBB->SetFrequency(exitFreq); + auto exitEdgeFreq = exitBB->GetEdgeFreq(latchBB) / replicatedLoopNum; + if(exitEdgeFreq == 0 && exitBB->GetEdgeFreq(latchBB) != 0) { + exitEdgeFreq = 1; + } + exitBB->SetEdgeFreq(latchBB, exitEdgeFreq); + auto latchFreq = latchBB->GetFrequency() / replicatedLoopNum; + if (latchFreq == 0 && latchBB->GetFrequency() != 0) { + latchFreq = 1; + } + latchBB->SetFrequency(latchFreq); + latchBB->SetEdgeFreq(loop->head, latchFreq); + } +} + +void LoopUnrolling::AddEdgeForExitBBLastNew2OldBBEmpty(BB &exitBB, std::unordered_map &old2NewBB, + BB &newHeadBB) { + for (size_t idx = 0; idx < exitBB.GetPred().size(); ++idx) { + auto *bb = exitBB.GetPred(idx); + auto it = old2NewBB.find(bb); + CHECK_FATAL(it != old2NewBB.end(), "Can not find bb in old2NewBB"); + bb->ReplaceSucc(&exitBB, &newHeadBB); + exitBB.AddPred(*old2NewBB[bb], idx); + if (profValid) { + resetFreqForAfterInsertGoto ? + (bb->GetEdgeFreq(idx) - 1 == 0 ? old2NewBB[bb]->PushBackSuccFreq(bb->GetEdgeFreq(idx)) : + old2NewBB[bb]->PushBackSuccFreq(bb->GetEdgeFreq(idx) - 1)) : + old2NewBB[bb]->PushBackSuccFreq(bb->GetEdgeFreq(idx)); + } + ResetOldLabel2NewLabel(old2NewBB, *bb, exitBB, newHeadBB); + } +} + +void LoopUnrolling::AddEdgeForExitBB(BB &exitBB, std::unordered_map &old2NewBB, BB &newHeadBB) { + for (size_t idx = 0; idx < exitBB.GetPred().size(); ++idx) { + auto *bb = exitBB.GetPred(idx); + auto it = old2NewBB.find(lastNew2OldBB[bb]); + CHECK_FATAL(it != old2NewBB.end(), "Can not find bb in lastNew2OldBB"); + bb->ReplaceSucc(&exitBB, &newHeadBB); + exitBB.AddPred(*old2NewBB[lastNew2OldBB[bb]], idx); + if (profValid) { + (resetFreqForAfterInsertGoto && firstResetForAfterInsertGoto) ? + (bb->GetEdgeFreq(idx) - 1 == 0 ? old2NewBB[lastNew2OldBB[bb]]->PushBackSuccFreq(bb->GetEdgeFreq(idx)) : + old2NewBB[lastNew2OldBB[bb]]->PushBackSuccFreq(bb->GetEdgeFreq(idx) - 1)) : + old2NewBB[lastNew2OldBB[bb]]->PushBackSuccFreq(bb->GetEdgeFreq(idx)); + firstResetForAfterInsertGoto = false; + } + ResetOldLabel2NewLabel2(old2NewBB, *bb, exitBB, newHeadBB); + } +} + +// Copy loop except exiting BB and latch BB. +void LoopUnrolling::CopyAndInsertBB(bool isPartial) { + auto exitBB = func->GetBBFromID(loop->inloopBB2exitBBs.begin()->first); + CHECK_FATAL(exitBB->GetKind() == kBBCondGoto, "exiting bb must be kBBCondGoto"); + std::unordered_map old2NewBB; + BB *newHeadBB = CopyBB(*loop->head, true); + if (profValid && needUpdateInitLoopFreq) { + ResetFrequency(*loop->head); + ResetFrequency(); + } + profValid && resetFreqForAfterInsertGoto ? + (loop->head->GetFrequency() - 1 == 0 ? newHeadBB->SetFrequency(loop->head->GetFrequency()) : + newHeadBB->SetFrequency(loop->head->GetFrequency() - 1)) : + newHeadBB->SetFrequency(loop->head->GetFrequency()); + old2NewBB.insert({ loop->head, newHeadBB }); + std::set labelBBs; + profValid ? CopyLoopBodyForProfile(*newHeadBB, old2NewBB, labelBBs, *exitBB, false) : + CopyLoopBody(*newHeadBB, old2NewBB, labelBBs, *exitBB, false); + if (isPartial) { + partialSuccHead = newHeadBB; + } + for (auto bb : labelBBs) { + if (bb->GetKind() == kBBCondGoto) { + CHECK_FATAL(!bb->GetMeStmts().empty(), "must not be empty"); + LabelIdx oldlabIdx = static_cast(bb->GetMeStmts().back()).GetOffset(); + SetLabelWithCondGotoOrGotoBB(*bb, old2NewBB, *exitBB, oldlabIdx); + } else if (bb->GetKind() == kBBGoto) { + CHECK_FATAL(!bb->GetMeStmts().empty(), "must not be empty"); + LabelIdx oldlabIdx = static_cast(bb->GetMeStmts().back()).GetOffset(); + SetLabelWithCondGotoOrGotoBB(*bb, old2NewBB, *exitBB, oldlabIdx); + } else { + CHECK_FATAL(false, "must be kBBCondGoto or kBBGoto"); + } + } + if (lastNew2OldBB.empty()) { + AddEdgeForExitBBLastNew2OldBBEmpty(*exitBB, old2NewBB, *newHeadBB); + } else { + AddEdgeForExitBB(*exitBB, old2NewBB, *newHeadBB); + } + lastNew2OldBB.clear(); + for (auto it : old2NewBB) { + lastNew2OldBB[it.second] = it.first; + } +} + +void LoopUnrolling::RemoveCondGoto() { + BB *exitingBB = func->GetBBFromID(loop->inloopBB2exitBBs.begin()->first); + CHECK_FATAL(exitingBB->GetSucc().size() == 2, "must has two succ bb"); + if (exitingBB->GetSucc(0) != loop->latch && exitingBB->GetSucc(1) != loop->latch) { + CHECK_FATAL(false, "latch must be pred of exiting bb"); + } + exitingBB->RemoveSucc(*loop->latch); + exitingBB->RemoveMeStmt(exitingBB->GetLastMe()); + exitingBB->SetKind(kBBFallthru); + if (profValid) { + exitingBB->SetEdgeFreq(exitingBB->GetSucc(0), exitingBB->GetFrequency()); + } + loop->head->RemovePred(*loop->latch); + func->DeleteBasicBlock(*loop->latch); +} + +bool LoopUnrolling::LoopFullyUnroll(int64 tripCount) { + uint32 costResult = 0; + for (auto bbId : loop->loopBBs) { + BB *bb = func->GetBBFromID(bbId); + for (auto &meStmt : bb->GetMeStmts()) { + uint32 cost = 0; + ComputeCodeSize(meStmt, cost); + if (canUnroll == false) { + return false; + } + costResult += cost; + if (costResult * tripCount > kMaxCost) { + return false; + } + } + } + replicatedLoopNum = tripCount; + for (int64 i = 0; i < tripCount; ++i) { + if (i > 0) { + needUpdateInitLoopFreq = false; + } + CopyAndInsertBB(false); + } + RemoveCondGoto(); + mgr->InvalidAnalysisResult(MeFuncPhase_DOMINANCE, func); + dom = static_cast(mgr->GetAnalysisResult(MeFuncPhase_DOMINANCE, func)); + MeSSAUpdate ssaUpdate(*func, *func->GetMeSSATab(), *dom, cands, *memPool); + ssaUpdate.Run(); + return true; +} + +void LoopUnrolling::ResetFrequency(BB &newCondGotoBB, BB &exitingBB, const BB &exitedBB, uint32 headFreq) { + if (profValid) { + newCondGotoBB.SetFrequency(headFreq); + exitingBB.SetEdgeFreq(&exitedBB, 0); + } +} + +void LoopUnrolling::InsertCondGotoBB() { + CHECK_NULL_FATAL(partialSuccHead); + BB *exitingBB = func->GetBBFromID(loop->inloopBB2exitBBs.begin()->first); + BB *exitedBB = *(loop->inloopBB2exitBBs.begin()->second->begin()); + BB *newCondGotoBB = CopyBB(*exitingBB, true); + auto headFreq = loop->head->GetFrequency(); + ResetFrequency(*newCondGotoBB, *exitingBB, *exitedBB, headFreq); + MeStmt *lastMeStmt = newCondGotoBB->GetLastMe(); + CHECK_FATAL(lastMeStmt != nullptr, "last meStmt must not be nullptr"); + CHECK_FATAL(partialSuccHead->GetBBLabel() != 0, "label must not be zero"); + static_cast(lastMeStmt)->SetOffset(partialSuccHead->GetBBLabel()); + bool addExitedSucc = false; + if (exitingBB->GetSucc().front() == exitedBB) { + addExitedSucc = true; + newCondGotoBB->AddSucc(*exitedBB); + if (profValid) { + newCondGotoBB->PushBackSuccFreq(1); + } + } + for (size_t idx = 0; idx < partialSuccHead->GetPred().size(); ++idx) { + auto *pred = partialSuccHead->GetPred(idx); + pred->ReplaceSucc(partialSuccHead, newCondGotoBB); + partialSuccHead->AddPred(*newCondGotoBB, idx); + if (profValid) { + newCondGotoBB->PushBackSuccFreq(headFreq - 1 == 0 ? headFreq : headFreq - 1); + } + if (pred->GetKind() == kBBCondGoto) { + CHECK_FATAL(!pred->GetMeStmts().empty(), "must not be empty"); + CondGotoMeStmt &condGotoNode = static_cast(pred->GetMeStmts().back()); + LabelIdx oldlabIdx = condGotoNode.GetOffset(); + CHECK_FATAL(oldlabIdx == partialSuccHead->GetBBLabel(), "must equal"); + LabelIdx label = func->GetOrCreateBBLabel(*newCondGotoBB); + condGotoNode.SetOffset(label); + } else if (pred->GetKind() == kBBGoto) { + CHECK_FATAL(!pred->GetMeStmts().empty(), "must not be empty"); + GotoMeStmt &gotoStmt = static_cast(pred->GetMeStmts().back()); + LabelIdx oldlabIdx = gotoStmt.GetOffset(); + CHECK_FATAL(oldlabIdx == partialSuccHead->GetBBLabel(), "must equal"); + LabelIdx label = func->GetOrCreateBBLabel(*newCondGotoBB); + gotoStmt.SetOffset(label); + } + } + if (addExitedSucc == false) { + newCondGotoBB->AddSucc(*exitedBB); + if (profValid) { + newCondGotoBB->PushBackSuccFreq(headFreq - 1 == 0 ? headFreq : headFreq - 1); + } + } +} + +bool LoopUnrolling::DetermineUnrollTimes(uint32 &index, bool isConst) { + uint32 costResult = 0; + uint32 unrollTime = unrollTimes[index]; + for (auto bbId : loop->loopBBs) { + BB *bb = func->GetBBFromID(bbId); + auto exitBB = func->GetBBFromID(loop->inloopBB2exitBBs.begin()->first); + if (bb == exitBB) { + continue; + } + for (auto &meStmt : bb->GetMeStmts()) { + uint32 cost = 0; + ComputeCodeSize(meStmt, cost); + if (canUnroll == false) { + return false; + } + costResult += cost; + if ((isConst && costResult * (unrollTime - 1) > kMaxCost) || (!isConst && costResult * unrollTime > kMaxCost)) { + if (index < kMaxIndex) { + ++index; + return DetermineUnrollTimes(index, isConst); + } else { + return false; + } + } + } + } + if (MeDoLoopUnrolling::enableDebug) { + LogInfo::MapleLogger() << "CodeSize: " << costResult << "\n"; + } + return true; +} + +void LoopUnrolling::AddPreHeader(BB *oldPreHeader, BB *head) { + CHECK_FATAL(oldPreHeader->GetKind() == kBBCondGoto, "must be kBBCondGoto"); + auto *preheader = func->NewBasicBlock(); + preheader->SetAttributes(kBBAttrArtificial); + preheader->SetKind(kBBFallthru); + auto preheaderFreq = 0; + if (profValid) { + preheaderFreq = oldPreHeader->GetEdgeFreq(head); + } + size_t index = head->GetPred().size(); + while (index > 0) { + if (head->GetPred(index - 1) == oldPreHeader) { + break; + } + --index; + } + oldPreHeader->ReplaceSucc(head, preheader); + --index; + head->AddPred(*preheader, index); + if (profValid) { + preheader->PushBackSuccFreq(preheaderFreq); + preheader->SetFrequency(preheaderFreq); + } + CondGotoMeStmt *condGotoStmt = static_cast(oldPreHeader->GetLastMe()); + LabelIdx oldlabIdx = condGotoStmt->GetOffset(); + if (oldlabIdx == head->GetBBLabel()) { + LabelIdx label = func->GetOrCreateBBLabel(*preheader); + condGotoStmt->SetOffset(label); + } +} + +bool LoopUnrolling::LoopPartialUnrollWithConst(uint32 tripCount) { + uint32 index = 0; + if (!DetermineUnrollTimes(index, true)) { + if (MeDoLoopUnrolling::enableDebug) { + LogInfo::MapleLogger() << "CodeSize is too large" << "\n"; + } + return false; + } + uint32 unrollTime = unrollTimes[index]; + if (MeDoLoopUnrolling::enableDebug) { + LogInfo::MapleLogger() << "Unrolltime: " << unrollTime << "\n"; + } + if (tripCount / unrollTime < 1) { + return false; + } + uint32 remainder = (tripCount + kLoopBodyNum) % unrollTime; + if (MeDoLoopUnrolling::enableDebug) { + LogInfo::MapleLogger() << "Remainder: " << remainder << "\n"; + } + if (remainder == 0) { + for (int64 i = 1; i < unrollTime; ++i) { + if (i > 1) { + needUpdateInitLoopFreq = false; + } + replicatedLoopNum = unrollTime; + CopyAndInsertBB(false); + } + } else { + partialCount = 1; + for (int64 i = 1; i < unrollTime; ++i) { + if (i > 1) { + needUpdateInitLoopFreq = false; + } + resetFreqForAfterInsertGoto = i < remainder ? false : true; + replicatedLoopNum = unrollTime; + if (i == remainder) { + CopyAndInsertBB(true); + } else { + CopyAndInsertBB(false); + } + } + replicatedLoopNum = unrollTime; + InsertCondGotoBB(); + } + mgr->InvalidAnalysisResult(MeFuncPhase_DOMINANCE, func); + dom = static_cast(mgr->GetAnalysisResult(MeFuncPhase_DOMINANCE, func)); + MeSSAUpdate ssaUpdate(*func, *func->GetMeSSATab(), *dom, cands, *memPool); + ssaUpdate.Run(); + return true; +} + +void LoopUnrolling::CopyLoopForPartialAndPre(BB *&newHead, BB *&newExiting) { + needUpdateInitLoopFreq = false; + auto exitBB = func->GetBBFromID(loop->inloopBB2exitBBs.begin()->first); + CHECK_FATAL(exitBB->GetKind() == kBBCondGoto, "exiting bb must be kBBCondGoto"); + std::unordered_map old2NewBB; + BB *newHeadBB = CopyBB(*loop->head, true); + if (profValid) { + newHeadBB->SetFrequency(loop->head->GetFrequency() % replicatedLoopNum); + } + old2NewBB.insert({ loop->head, newHeadBB }); + std::set labelBBs; + resetFreqForUnrollWithVar = true; + profValid ? CopyLoopBodyForProfile(*newHeadBB, old2NewBB, labelBBs, *exitBB, true) : + CopyLoopBody(*newHeadBB, old2NewBB, labelBBs, *exitBB, true); + resetFreqForUnrollWithVar = false; + for (auto bb : labelBBs) { + if (bb->GetKind() == kBBCondGoto) { + CHECK_FATAL(!bb->GetMeStmts().empty(), "must not be empty"); + LabelIdx oldlabIdx = static_cast(bb->GetMeStmts().back()).GetOffset(); + SetLabelWithCondGotoOrGotoBB(*bb, old2NewBB, *exitBB, oldlabIdx); + } else if (bb->GetKind() == kBBGoto) { + CHECK_FATAL(!bb->GetMeStmts().empty(), "must not be empty"); + LabelIdx oldlabIdx = static_cast(bb->GetMeStmts().back()).GetOffset(); + SetLabelWithCondGotoOrGotoBB(*bb, old2NewBB, *exitBB, oldlabIdx); + } else { + CHECK_FATAL(false, "must be kBBCondGoto or kBBGoto"); + } + } + newHead = newHeadBB; + newExiting = old2NewBB[exitBB]; +} + +VarMeExpr *LoopUnrolling::CreateIndVarOrTripCountWithName(const std::string &name) { + MIRSymbol *symbol = + func->GetMIRModule().GetMIRBuilder()->CreateLocalDecl(name, *GlobalTables::GetTypeTable().GetInt32()); + OriginalSt *ost = irMap->GetSSATab().CreateSymbolOriginalSt(*symbol, func->GetMirFunc()->GetPuidx(), 0); + ost->SetZeroVersionIndex(irMap->GetVerst2MeExprTable().size()); + irMap->GetVerst2MeExprTable().push_back(nullptr); + ost->PushbackVersionsIndices(ost->GetZeroVersionIndex()); + VarMeExpr *var = irMap->CreateVarMeExprVersion(ost); + return var; +} + +// i < tripcount / unrollTime +void LoopUnrolling::UpdateCondGotoStmt(BB &bb, VarMeExpr &indVar, MeExpr &tripCount, + MeExpr &unrollTimeExpr, uint32 offset) { + for (auto &stmt : bb.GetMeStmts()) { + bb.RemoveMeStmt(&stmt); + } + MeExpr *divMeExpr = irMap->CreateMeExprBinary(OP_div, PTY_i32, tripCount, unrollTimeExpr); + MeExpr *opMeExpr = irMap->CreateMeExprCompare(OP_ge, PTY_u1, PTY_i32, static_cast(indVar), *divMeExpr); + UnaryMeStmt *unaryMeStmt = irMap->New(OP_brfalse); + unaryMeStmt->SetOpnd(0, opMeExpr); + CondGotoMeStmt *newCondGotoStmt = irMap->New(*unaryMeStmt, offset); + bb.AddMeStmtLast(newCondGotoStmt); +} + +// i++ +// i < tripcount / unrollTime +void LoopUnrolling::UpdateCondGotoBB(BB &bb, VarMeExpr &indVar, MeExpr &tripCount, MeExpr &unrollTimeExpr) { + uint32 offset = static_cast(bb.GetLastMe())->GetOffset(); + for (auto &stmt : bb.GetMeStmts()) { + bb.RemoveMeStmt(&stmt); + } + VarMeExpr *newVarLHS = irMap->CreateVarMeExprVersion(indVar.GetOst()); + InsertCandsForSSAUpdate(newVarLHS->GetOstIdx(), bb); + MeExpr *constMeExprForOne = irMap->CreateIntConstMeExpr(1, PTY_i32); + MeExpr *addMeExpr = irMap->CreateMeExprBinary(OP_add, PTY_i32, indVar, *constMeExprForOne); + UpdateCondGotoStmt(bb, indVar, tripCount, unrollTimeExpr, offset); + bb.AddMeStmtFirst(irMap->CreateDassignMeStmt(*newVarLHS, *addMeExpr, bb)); +} + +void LoopUnrolling::ExchangeSucc(BB &partialExit) { + BB *succ0 = partialExit.GetSucc(0); + partialExit.SetSucc(0, partialExit.GetSucc(1)); + partialExit.SetSucc(1, succ0); +} + +// copy loop for partial +void LoopUnrolling::CopyLoopForPartial(BB &partialCondGoto, BB &exitedBB, BB &exitingBB) { + BB *partialHead = nullptr; + BB *partialExit = nullptr; + CopyLoopForPartialAndPre(partialHead, partialExit); + (void)func->GetOrCreateBBLabel(partialCondGoto); + CHECK_FATAL(partialHead->GetBBLabel() != 0, "must not be zero"); + CHECK_FATAL(!partialCondGoto.GetMeStmts().empty(), "must not be empty"); + CondGotoMeStmt &condGotoStmt = static_cast(partialCondGoto.GetMeStmts().back()); + condGotoStmt.SetOffset(partialHead->GetBBLabel()); + size_t index = exitedBB.GetPred().size(); + while (index > 0) { + if (exitedBB.GetPred(index - 1) == &exitingBB) { + break; + } + --index; + } + exitingBB.ReplaceSucc(&exitedBB, &partialCondGoto); + --index; + exitedBB.AddPred(partialCondGoto, index); + if (profValid) { + partialCondGoto.PushBackSuccFreq(exitedBB.GetFrequency() - (loop->head->GetFrequency() % replicatedLoopNum)); + } + partialExit->AddSucc(exitedBB); + if (profValid) { + partialExit->PushBackSuccFreq(loop->head->GetFrequency() % replicatedLoopNum); + } + CHECK_FATAL(partialExit->GetKind() == kBBCondGoto, "must be kBBCondGoto"); + if (static_cast(partialExit->GetLastMe())->GetOffset() != partialExit->GetSucc(1)->GetBBLabel()) { + ExchangeSucc(*partialExit); + if (profValid) { + auto tempFreq = partialExit->GetEdgeFreq(partialExit->GetSucc(0)); + partialExit->SetEdgeFreq(partialExit->GetSucc(0), partialExit->GetEdgeFreq(partialExit->GetSucc(1))); + partialExit->SetEdgeFreq(partialExit->GetSucc(1), tempFreq); + } + } + partialCondGoto.AddSucc(*partialHead); + if (profValid) { + partialCondGoto.PushBackSuccFreq(loop->head->GetFrequency() % replicatedLoopNum); + partialCondGoto.SetFrequency(partialCondGoto.GetEdgeFreq(static_cast(0)) + partialCondGoto.GetEdgeFreq(1)); + } + CHECK_FATAL(partialCondGoto.GetKind() == kBBCondGoto, "must be partialCondGoto"); + CHECK_FATAL(!partialCondGoto.GetMeStmts().empty(), "must not be empty"); + if (static_cast(partialCondGoto.GetLastMe())->GetOffset() != + partialCondGoto.GetSucc(1)->GetBBLabel()) { + ExchangeSucc(partialCondGoto); + } + AddPreHeader(&partialCondGoto, partialHead); +} + +MeExpr *LoopUnrolling::CreateExprWithCRNode(CRNode &crNode) { + switch (crNode.GetCRType()) { + case kCRConstNode: { + return irMap->CreateIntConstMeExpr(static_cast(crNode).GetConstValue(), PTY_i32); + } + case kCRVarNode: { + CHECK_FATAL(crNode.GetExpr() != nullptr, "expr must not be nullptr"); + return crNode.GetExpr(); + } + case kCRAddNode: { + auto addCRNode = static_cast(crNode); + auto addOpnd1 = CreateExprWithCRNode(*addCRNode.GetOpnd(0)); + auto addOpnd2 = CreateExprWithCRNode(*addCRNode.GetOpnd(1)); + MeExpr *addOpnds = irMap->CreateMeExprBinary(OP_add, PTY_i32, *addOpnd1, *addOpnd2); + for (size_t i = 2; i < addCRNode.GetOpndsSize(); ++i) { + auto addOpnd = CreateExprWithCRNode(*addCRNode.GetOpnd(i)); + addOpnds = irMap->CreateMeExprBinary(OP_add, PTY_i32, *addOpnds, *addOpnd); + } + return addOpnds; + } + case kCRMulNode: { + auto mulCRNode = static_cast(crNode); + auto mulOpnd1 = CreateExprWithCRNode(*mulCRNode.GetOpnd(0)); + auto mulOpnd2 = CreateExprWithCRNode(*mulCRNode.GetOpnd(1)); + MeExpr *mulOpnds = irMap->CreateMeExprBinary(OP_mul, PTY_i32, *mulOpnd1, *mulOpnd2); + for (size_t i = 2; i < mulCRNode.GetOpndsSize(); ++i) { + auto mulOpnd = CreateExprWithCRNode(*mulCRNode.GetOpnd(i)); + mulOpnds = irMap->CreateMeExprBinary(OP_mul, PTY_i32, *mulOpnds, *mulOpnd); + } + return mulOpnds; + } + case kCRDivNode: { + auto divCRNode = static_cast(crNode); + auto opnd1 = CreateExprWithCRNode(*divCRNode.GetLHS()); + auto opnd2 = CreateExprWithCRNode(*divCRNode.GetRHS()); + return irMap->CreateMeExprBinary(OP_div, PTY_i32, *opnd1, *opnd2); + } + default: { + CHECK_FATAL(false, "impossible"); + } + } +} + +void LoopUnrolling::CreateIndVarAndCondGotoStmt(CR &cr, CRNode &varNode, BB &preCondGoto, uint32 unrollTime, uint32 i) { + // create stmt : int i = 0. + BB *indVarAndTripCountDefBB = func->NewBasicBlock(); + std::string indVarName = std::string("__LoopUnrolllIndvar__") + std::to_string(i); + VarMeExpr *indVar = CreateIndVarOrTripCountWithName(indVarName); + indVarAndTripCountDefBB->SetKind(kBBFallthru); + MeExpr *constMeExprForZero = irMap->CreateIntConstMeExpr(0, PTY_i32); + indVarAndTripCountDefBB->AddMeStmtLast( + irMap->CreateDassignMeStmt(*indVar, *constMeExprForZero, *indVarAndTripCountDefBB)); + InsertCandsForSSAUpdate(indVar->GetOstIdx(), *indVarAndTripCountDefBB); + + // create stmt : tripCount = (n - start) / stride. + BB *exitingBB = func->GetBBFromID(loop->inloopBB2exitBBs.begin()->first); + auto opnd0 = CreateExprWithCRNode(*cr.GetOpnd(0)); + auto opnd1 = CreateExprWithCRNode(*cr.GetOpnd(1)); + MeExpr *conditionExpr = CreateExprWithCRNode(varNode); + + MeExpr *subMeExpr = irMap->CreateMeExprBinary(OP_sub, PTY_i32, *conditionExpr, *opnd0); + MeExpr *divMeExpr = irMap->CreateMeExprBinary(OP_div, PTY_i32, *subMeExpr, *opnd1); + std::string tripConutName = std::string("__LoopUnrolllTripCount__") + std::to_string(i); + VarMeExpr *tripCountExpr = CreateIndVarOrTripCountWithName(tripConutName); + indVarAndTripCountDefBB->AddMeStmtLast( + irMap->CreateDassignMeStmt(*tripCountExpr, *divMeExpr, *indVarAndTripCountDefBB)); + InsertCandsForSSAUpdate(tripCountExpr->GetOstIdx(), *indVarAndTripCountDefBB); + for (size_t idx = 0; idx < preCondGoto.GetPred().size(); ++idx) { + auto *bb = preCondGoto.GetPred(idx); + bb->ReplaceSucc(&preCondGoto, indVarAndTripCountDefBB); + preCondGoto.AddPred(*indVarAndTripCountDefBB, idx); + if (profValid) { + indVarAndTripCountDefBB->PushBackSuccFreq(preCondGoto.GetEdgeFreq(idx)); + } + switch (bb->GetKind()) { + case kBBFallthru: { + break; + } + case kBBGoto: { + auto gotoStmt= static_cast(bb->GetLastMe()); + if (preCondGoto.GetBBLabel() == gotoStmt->GetOffset()) { + LabelIdx label = func->GetOrCreateBBLabel(*indVarAndTripCountDefBB); + gotoStmt->SetOffset(label); + } + break; + } + case kBBCondGoto: { + auto condGotoStmt= static_cast(bb->GetLastMe()); + if (preCondGoto.GetBBLabel() == condGotoStmt->GetOffset()) { + LabelIdx label = func->GetOrCreateBBLabel(*indVarAndTripCountDefBB); + condGotoStmt->SetOffset(label); + } + break; + } + default: { + CHECK_FATAL(false, "NYI"); + } + } + } + MeExpr *unrollTimeExpr = irMap->CreateIntConstMeExpr(unrollTime, PTY_i32); + UpdateCondGotoBB(*exitingBB, *indVar, *tripCountExpr, *unrollTimeExpr); + UpdateCondGotoStmt(preCondGoto, *indVar, *tripCountExpr, *unrollTimeExpr, loop->head->GetBBLabel()); +} + +void LoopUnrolling::CopyLoopForPartial(CR &cr, CRNode &varNode, uint32 j, uint32 unrollTime) { + BB *exitingBB = func->GetBBFromID(loop->inloopBB2exitBBs.begin()->first); + BB *exitedBB = *loop->inloopBB2exitBBs.begin()->second->begin(); + BB *partialCondGoto = CopyBB(*exitingBB, false); + replicatedLoopNum = unrollTime; + CopyLoopForPartial(*partialCondGoto, *exitedBB, *exitingBB); + // create preCondGoto bb + BB *preCondGoto = func->NewBasicBlock(); + if (profValid) { + preCondGoto->SetFrequency(loop->preheader->GetFrequency()); + } + size_t idx = loop->head->GetPred().size(); + while (idx > 0) { + if (loop->head->GetPred(idx - 1) == loop->preheader) { + break; + } + --idx; + } + loop->preheader->ReplaceSucc(loop->head, preCondGoto); + --idx; + loop->head->AddPred(*preCondGoto, idx); + preCondGoto->AddSucc(*partialCondGoto); + preCondGoto->GetSuccFreq().resize(kOperandNum); + if (profValid) { + preCondGoto->SetEdgeFreq(partialCondGoto, loop->head->GetFrequency() >= unrollTime ? 0 : 1); + preCondGoto->SetEdgeFreq(loop->head, loop->head->GetFrequency() / unrollTime); + } + preCondGoto->SetKind(kBBCondGoto); + CreateIndVarAndCondGotoStmt(cr, varNode, *preCondGoto, unrollTime, j); + AddPreHeader(preCondGoto, loop->head); + CHECK_FATAL(preCondGoto->GetKind() == kBBCondGoto, "must be kBBCondGoto"); + if (static_cast(preCondGoto->GetLastMe())->GetOffset() != preCondGoto->GetSucc(1)->GetBBLabel()) { + ExchangeSucc(*preCondGoto); + auto tempFreq = preCondGoto->GetEdgeFreq(preCondGoto->GetSucc(0)); + if (profValid) { + preCondGoto->SetEdgeFreq(preCondGoto->GetSucc(0), preCondGoto->GetEdgeFreq(preCondGoto->GetSucc(1))); + preCondGoto->SetEdgeFreq(preCondGoto->GetSucc(1), tempFreq); + } + } +} + +void LoopUnrolling::LoopPartialUnrollWithVar(CR &cr, CRNode &varNode, uint32 j) { + uint32 index = 0; + if (!DetermineUnrollTimes(index, false)) { + if (MeDoLoopUnrolling::enableDebug) { + LogInfo::MapleLogger() << "codesize is too large" << "\n"; + } + return; + } + if (MeDoLoopUnrolling::enableDebug) { + LogInfo::MapleLogger() << "partial unrolling with var" << "\n"; + } + if (MeDoLoopUnrolling::enableDump) { + irMap->Dump(); + profValid ? func->GetTheCfg()->DumpToFile("cfgIncludeFreqInfobeforeLoopPartialWithVarUnrolling", false, true) : + func->GetTheCfg()->DumpToFile("cfgbeforeLoopPartialWithVarUnrolling"); + } + uint32 unrollTime = unrollTimes[index]; + if (MeDoLoopUnrolling::enableDebug) { + LogInfo::MapleLogger() << "unrolltime: " << unrollTime << "\n"; + } + CopyLoopForPartial(cr, varNode, j, unrollTime); + replicatedLoopNum = unrollTime; + needUpdateInitLoopFreq = true; + isUnrollWithVar = true; + for (int64 i = 1; i < unrollTime; ++i) { + if (i > 1) { + needUpdateInitLoopFreq = false; + } + CopyAndInsertBB(false); + } + mgr->InvalidAnalysisResult(MeFuncPhase_DOMINANCE, func); + dom = static_cast(mgr->GetAnalysisResult(MeFuncPhase_DOMINANCE, func)); + MeSSAUpdate ssaUpdate(*func, *func->GetMeSSATab(), *dom, cands, *memPool); + ssaUpdate.Run(); + if (MeDoLoopUnrolling::enableDump) { + irMap->Dump(); + profValid ? func->GetTheCfg()->DumpToFile("cfgIncludeFreqInfoafterLoopPartialWithVarUnrolling", false, true) : + func->GetTheCfg()->DumpToFile("cfgafterLoopPartialWithVarUnrolling"); + } +} + +void MeDoLoopUnrolling::SetNestedLoop(const IdentifyLoops &meLoop) { + for (auto loop : meLoop.GetMeLoops()) { + if (loop->nestDepth == 0) { + continue; + } + CHECK_NULL_FATAL(loop->parent); + auto it = parentLoop.find(loop->parent); + if (it == parentLoop.end()) { + parentLoop[loop->parent] = { loop }; + } else { + parentLoop[loop->parent].insert(loop); + } + } +} + +bool MeDoLoopUnrolling::IsDoWhileLoop(MeFunction &func, LoopDesc &loop) const { + for (auto succ : loop.head->GetSucc()) { + if (!loop.Has(*succ)) { + return false; + } + } + auto exitBB = func.GetBBFromID(loop.inloopBB2exitBBs.begin()->first); + for (auto pred : exitBB->GetPred()) { + if (!loop.Has(*pred)) { + return false; + } + } + return true; +} + +bool MeDoLoopUnrolling::PredIsOutOfLoopBB(MeFunction &func, LoopDesc &loop) const { + for (auto bbID : loop.loopBBs) { + auto bb = func.GetBBFromID(bbID); + if (bb == loop.head) { + continue; + } + for (auto pred : bb->GetPred()) { + if (!loop.Has(*pred)) { + CHECK_FATAL(false, "pred is out of loop bb"); + return true; + } + } + } + return false; +} + +bool MeDoLoopUnrolling::IsCanonicalAndOnlyOneExitLoop(MeFunction &func, LoopDesc &loop) const { + // Only handle one nested loop. + if (parentLoop.find(&loop) != parentLoop.end()) { + return false; + } + // Must be canonical loop and has one exit bb. + if (loop.inloopBB2exitBBs.size() != 1 || loop.inloopBB2exitBBs.begin()->second->size() != 1 || + !loop.IsCanonicalLoop()) { + return false; + } + CHECK_NULL_FATAL(loop.preheader); + CHECK_NULL_FATAL(loop.latch); + auto headBB = loop.head; + auto exitBB = func.GetBBFromID(loop.inloopBB2exitBBs.begin()->first); + CHECK_FATAL(headBB->GetPred().size() == 2, "head must has two preds"); + if (!IsDoWhileLoop(func, loop)) { + if (enableDebug) { + LogInfo::MapleLogger() << "While-do loop" << "\n"; + } + return false; + } + if (PredIsOutOfLoopBB(func, loop)) { + return false; + } + // latch bb only has one pred bb + if (loop.latch->GetPred().size() != 1 || loop.latch->GetPred(0) != exitBB) { + return false; + } + CHECK_FATAL(exitBB->GetLastMe() == &(exitBB->GetMeStmts().front()), "exit bb only has condgoto stmt"); + return true; +} + +void MeDoLoopUnrolling::ExcuteLoopUnrollingWithConst(uint32 tripCount, MeFunction &func, MeIRMap &irMap, + LoopUnrolling &loopUnrolling) { + if (tripCount == 0) { + if (enableDebug) { + LogInfo::MapleLogger() << "tripCount is zero" << "\n"; + } + return; + } + if (enableDebug) { + LogInfo::MapleLogger() << "start unrolling with const" << "\n"; + LogInfo::MapleLogger() << "tripCount: " << tripCount << "\n"; + } + if (enableDump) { + irMap.Dump(); + func.IsIRProfValid() ? func.GetTheCfg()->DumpToFile("cfgIncludeFreqInfobeforLoopUnrolling", false, true) : + func.GetTheCfg()->DumpToFile("cfgbeforLoopUnrolling"); + } + // fully unroll + if (loopUnrolling.LoopFullyUnroll(tripCount)) { + if (enableDebug) { + LogInfo::MapleLogger() << "fully unrolling" << "\n"; + } + if (enableDump) { + irMap.Dump(); + func.IsIRProfValid() ? func.GetTheCfg()->DumpToFile("cfgIncludeFreqInfoafterLoopFullyUnrolling", false, true) : + func.GetTheCfg()->DumpToFile("cfgafterLoopFullyUnrolling"); + } + return; + } + // partial unroll with const + if (loopUnrolling.LoopPartialUnrollWithConst(tripCount)) { + if (enableDebug) { + LogInfo::MapleLogger() << "partial unrolling with const" << "\n"; + } + if (enableDump) { + irMap.Dump(); + func.IsIRProfValid() ? func.GetTheCfg()->DumpToFile("cfgIncludeFreqInfoafterLoopPartialWithConst", false, true) : + func.GetTheCfg()->DumpToFile("cfgafterLoopPartialWithConstUnrolling"); + } + return; + } +} + +void MeDoLoopUnrolling::ExecuteLoopUnrolling(MeFunction &func, MeFuncResultMgr &m, MeIRMap &irMap) { + enableDebug = false; + enableDump = false; + if (enableDebug) { + LogInfo::MapleLogger() << func.GetName() << "\n"; + } + IdentifyLoops *meLoop = static_cast(m.GetAnalysisResult(MeFuncPhase_MELOOP, &func)); + if (meLoop == nullptr) { + return; + } + SetNestedLoop(*meLoop); + uint32 i = 0; + for (auto loop : meLoop->GetMeLoops()) { + auto *dom = static_cast(m.GetAnalysisResult(MeFuncPhase_DOMINANCE, &func)); + if (!IsCanonicalAndOnlyOneExitLoop(func, *loop)) { + continue; + } + if (enableDebug) { + LogInfo::MapleLogger() << "start unrolling" << "\n"; + LogInfo::MapleLogger() << "IRProf Valid : " << func.IsIRProfValid() << "\n"; + } + LoopScalarAnalysisResult sa(irMap, *loop); + LoopUnrolling loopUnrolling(func, m, *loop, irMap, *NewMemPool(), dom); + uint32 tripCount = 0; + CRNode *conditionCRNode = nullptr; + CR *itCR = nullptr; + TripCountType type = sa.ComputeTripCount(func, tripCount, conditionCRNode, itCR); + if (enableDebug) { + LogInfo::MapleLogger() << "tripcount type is " << type << "\n"; + } + if (type == kConstCR) { + ExcuteLoopUnrollingWithConst(tripCount, func, irMap, loopUnrolling); + } else if ((type == kVarCR || type == kVarCondition) && itCR->GetOpndsSize() == kOperandNum) { + loopUnrolling.LoopPartialUnrollWithVar(*itCR, *conditionCRNode, i); + ++i; + } + } +} + +AnalysisResult *MeDoLoopUnrolling::Run(MeFunction *func, MeFuncResultMgr *m, ModuleResultMgr*) { + auto &profile = func->GetMIRModule().GetProfile(); + if (!profile.IsValid()) { + if (enableDebug) { + LogInfo::MapleLogger() << "DeCompress failed in loopUnrolling" << "\n"; + } + return nullptr; + } + if (!profile.CheckFuncHot(func->GetName())) { + if (enableDebug) { + LogInfo::MapleLogger() << "func is not hot" << "\n"; + } + return nullptr; + } + if (enableDebug) { + LogInfo::MapleLogger() << "func is hot" << "\n"; + } + if (func->GetSecondPass()) { + return nullptr; + } + CHECK_NULL_FATAL(m); + auto *irMap = static_cast(m->GetAnalysisResult(MeFuncPhase_IRMAPBUILD, func)); + CHECK_NULL_FATAL(irMap); + ExecuteLoopUnrolling(*func, *m, *irMap); + m->InvalidAnalysisResult(MeFuncPhase_DOMINANCE, func); + m->InvalidAnalysisResult(MeFuncPhase_MELOOP, func); + return nullptr; +} +} // namespace maple diff --git a/src/mapleall/maple_me/src/me_phase_manager.cpp b/src/mapleall/maple_me/src/me_phase_manager.cpp index e2a58cfe222d2c8ef12aa667ba36a7ee81539f57..18343daf1be641a6599a5fa64c1fee9209b5e4f6 100644 --- a/src/mapleall/maple_me/src/me_phase_manager.cpp +++ b/src/mapleall/maple_me/src/me_phase_manager.cpp @@ -31,12 +31,24 @@ #include "me_hdse.h" #include "me_prop.h" #include "me_rename2preg.h" +#include "me_loop_unrolling.h" +#include "me_cfg_opt.h" +#include "meconstprop.h" +#include "me_bb_analyze.h" #include "me_ssa_lpre.h" #include "me_ssa_epre.h" #include "me_stmt_pre.h" #include "me_store_pre.h" #include "me_cond_based_rc.h" #include "me_cond_based_npc.h" +#include "me_check_cast.h" +#include "me_placement_rc.h" +#include "me_subsum_rc.h" +#include "me_predict.h" +#include "ipa_side_effect.h" +#include "do_ipa_escape_analysis.h" +#include "me_gc_lowering.h" +#include "me_gc_write_barrier_opt.h" #include "preg_renamer.h" #include "me_ssa_devirtual.h" #include "me_delegate_rc.h" @@ -49,6 +61,9 @@ #include "me_emit.h" #include "me_rc_lowering.h" #include "gen_check_cast.h" +#if MIR_JAVA +#include "sync_select.h" +#endif // MIR_JAVA #include "me_ssa_tab.h" #include "mpl_timer.h" #include "constantfold.h" @@ -63,10 +78,15 @@ void MeFuncPhaseManager::RunFuncPhase(MeFunction *func, MeFuncPhase *phase) { LogInfo::MapleLogger() << "---Run Phase [ " << phase->PhaseName() << " ]---\n"; } // 3. tracetime(phase.id()) +#ifdef DEBUG_TIMER + MPLTimer timer; + timer.Start(); +#endif // 4. run: skip mplme phase except "emit" if no cfg in MeFunction AnalysisResult *analysisRes = nullptr; MePhaseID phaseID = phase->GetPhaseId(); - if ((func->NumBBs() > 0) || (phaseID == MeFuncPhase_EMIT)) { + if ((func->NumBBs() > 0 || (mirModule.IsInIPA() && phaseID == MeFuncPhase_IPASIDEEFFECT)) || + (phaseID == MeFuncPhase_EMIT) || (phaseID == MeFuncPhase_SSARENAME2PREG)) { analysisRes = phase->Run(func, &arFuncManager, modResMgr); phase->ClearMemPoolsExcept(analysisRes == nullptr ? nullptr : analysisRes->GetMempool()); phase->ClearString(); diff --git a/src/mapleall/maple_me/src/me_predict.cpp b/src/mapleall/maple_me/src/me_predict.cpp new file mode 100644 index 0000000000000000000000000000000000000000..59c733109a5c96b6fbf5308aa9f339020c2c17a7 --- /dev/null +++ b/src/mapleall/maple_me/src/me_predict.cpp @@ -0,0 +1,696 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "me_predict.h" +#include +#include +#include +#include +#include "me_ir.h" +#include "me_irmap.h" + +namespace { +using namespace maple; +// The base value for branch probability notes and edge probabilities. +constexpr int kProbBase = 10000; +// The base value for BB frequency. +constexpr int kFreqBase = 10000; +constexpr uint32 kScaleDownFactor = 2; +// kProbVeryUnlikely should be small enough so basic block predicted +// by it gets below HOT_BB_FREQUENCY_FRACTION. +constexpr int kLevelVeryUnlikely = 2000; // higher the level, smaller the probability +constexpr int kProbVeryUnlikely = kProbBase / kLevelVeryUnlikely - 1; +constexpr int kProbAlways = kProbBase; +constexpr uint32 kProbUninitialized = 0; +constexpr int kHitRateOffset = 50; +constexpr int kHitRateDivisor = 100; +} // anonymous namespace + +namespace maple { +// Recompute hitrate in percent to our representation. +#define HITRATE(VAL) (static_cast((VAL) * kProbBase + kHitRateOffset) / kHitRateDivisor) +#define DEF_PREDICTOR(ENUM, NAME, HITRATE) { NAME, HITRATE }, +const PredictorInfo MePrediction::predictorInfo[kEndPrediction + 1] = { +#include "me_predict.def" + // Upper bound on predictors. + { nullptr, 0 } +}; +// return the edge src->dest if it exists. +Edge *MePrediction::FindEdge(const BB &src, const BB &dest) const { + Edge *edge = edges[src.GetBBId()]; + while (edge != nullptr) { + if (&dest == &edge->dest) { + return edge; + } + edge = edge->next; + } + return nullptr; +} + +// Recognize backedges identified by loops. +bool MePrediction::IsBackEdge(const Edge &edge) const { + for (auto *backEdge : backEdges) { + if (backEdge == &edge) { + return true; + } + } + return false; +} + +// Try to guess whether the value of return means error code. +Predictor MePrediction::ReturnPrediction(const MeExpr *val, Prediction &prediction) const { + if (val == nullptr || val->GetMeOp() != kMeOpReg) { + return kPredNoPrediction; + } + auto *reg = static_cast(val); + if (reg->GetDefBy() != kDefByStmt) { + return kPredNoPrediction; + } + MeStmt *def = reg->GetDefStmt(); + if (def->GetOp() != OP_regassign) { + return kPredNoPrediction; + } + auto *rhs = static_cast(def)->GetRHS(); + ASSERT_NOT_NULL(rhs); + if (rhs->GetMeOp() != kMeOpConst) { + return kPredNoPrediction; + } + auto *constVal = static_cast(rhs); + if (constVal->GetPrimType() == PTY_ref) { + // nullptr is usually not returned. + if (constVal->IsZero()) { + prediction = kNotTaken; + return kPredNullReturn; + } + } else if (IsPrimitiveInteger(constVal->GetPrimType())) { + // Negative return values are often used to indicate errors. + if (constVal->GetIntValue() < 0) { + prediction = kNotTaken; + return kPredNegativeReturn; + } + // Constant return values seems to be commonly taken.Zero/one often represent + // booleans so exclude them from the heuristics. + if (!constVal->IsZero() && !constVal->IsOne()) { + prediction = kNotTaken; + return kPredConstReturn; + } + } + return kPredNoPrediction; +} + +// Predict edge E with the given PROBABILITY. +void MePrediction::PredictEdge(Edge &edge, Predictor predictor, int probability) { + if (&edge.src != func->GetCommonEntryBB() && edge.src.GetSucc().size() > 1) { + const BB &src = edge.src; + auto *newEdgePred = tmpAlloc.GetMemPool()->New(edge); + EdgePrediction *bbPred = bbPredictions[src.GetBBId()]; + newEdgePred->epNext = bbPred; + bbPredictions[src.GetBBId()] = newEdgePred; + newEdgePred->epProbability = probability; + newEdgePred->epPredictor = predictor; + } +} + +// Predict edge by given predictor if possible. +void MePrediction::PredEdgeDef(Edge &edge, Predictor predictor, Prediction taken) { + int probability = predictorInfo[static_cast(predictor)].hitRate; + if (taken != kTaken) { + probability = kProbBase - probability; + } + PredictEdge(edge, predictor, probability); +} + +// Look for basic block that contains unlikely to happen events +// (such as noreturn calls) and mark all paths leading to execution +// of this basic blocks as unlikely. +void MePrediction::BBLevelPredictions() { + RetMeStmt *retStmt = nullptr; + for (BB *bb : func->GetCommonExitBB()->GetPred()) { + MeStmt *lastMeStmt = to_ptr(bb->GetMeStmts().rbegin()); + if (lastMeStmt != nullptr && lastMeStmt->GetOp() == OP_return) { + retStmt = static_cast(lastMeStmt); + break; + } + } + CHECK_NULL_FATAL(retStmt); + if (retStmt->NumMeStmtOpnds() == 0) { + return; + } + MeExpr *retVal = retStmt->GetOpnd(0); + CHECK_NULL_FATAL(retVal); + if (retVal->GetMeOp() != kMeOpReg) { + return; + } + auto *reg = static_cast(retVal); + if (reg->GetDefBy() != kDefByPhi) { + return; + } + auto &defPhi = reg->GetDefPhi(); + const size_t defPhiOpndSize = defPhi.GetOpnds().size(); + CHECK_FATAL(defPhiOpndSize > 0, "container check"); + Prediction direction; + Predictor pred = ReturnPrediction(defPhi.GetOpnd(0), direction); + // Avoid the degenerate case where all return values form the function + // belongs to same category (ie they are all positive constants) + // so we can hardly say something about them. + size_t phiNumArgs = defPhi.GetOpnds().size(); + for (size_t i = 0; i < phiNumArgs; ++i) { + pred = ReturnPrediction(defPhi.GetOpnd(i), direction); + if (pred != kPredNoPrediction) { + BB *dest = defPhi.GetDefBB(); + BB *src = dest->GetPred(i); + Edge *findEdgeResult = FindEdge(*src, *dest); + ASSERT_NOT_NULL(findEdgeResult); + PredEdgeDef(*findEdgeResult, pred, direction); + } + } +} + +// Make edges for all bbs in the cfg. +void MePrediction::Init() { + bbPredictions.resize(func->GetAllBBs().size()); + edges.resize(func->GetAllBBs().size()); + bbVisited.resize(func->GetAllBBs().size()); + for (auto *bb : func->GetAllBBs()) { + BBId idx = bb->GetBBId(); + bbVisited[idx] = true; + bbPredictions[idx] = nullptr; + edges[idx] = nullptr; + for (auto *it : bb->GetSucc()) { + Edge *edge = tmpAlloc.GetMemPool()->New(*bb, *it); + edge->next = edges[idx]; + edges[idx] = edge; + } + } + if (func->GetCommonEntryBB() != func->GetFirstBB()) { + bbVisited[func->GetCommonEntryBB()->GetBBId()] = true; + } + if (func->GetCommonExitBB() != func->GetLastBB()) { + bbVisited[func->GetCommonExitBB()->GetBBId()] = true; + } +} + +// Return true if edge is predicated by one of loop heuristics. +bool MePrediction::PredictedByLoopHeuristic(const BB &bb) const { + EdgePrediction *pred = bbPredictions[bb.GetBBId()]; + while (pred != nullptr) { + if (pred->epPredictor == kPredLoopExit) { + return true; + } + pred = pred->epNext; + } + return false; +} + +// Sort loops first so that hanle innermost loop first in EstimateLoops. +void MePrediction::SortLoops() { + size_t size = meLoop->GetMeLoops().size(); + for (size_t i = 0; i < size; ++i) { + for (size_t j = 1; j < size - i; ++j) { + LoopDesc *loopPred = meLoop->GetMeLoops()[j - 1]; + LoopDesc *loop = meLoop->GetMeLoops()[j]; + if (loopPred->nestDepth < loop->nestDepth) { + LoopDesc *temp = loopPred; + meLoop->SetMeLoop(j - 1, *loop); + meLoop->SetMeLoop(j, *temp); + } + } + } +} + +void MePrediction::PredictLoops() { + constexpr uint32 minBBNumRequired = 2; + for (auto *loop : meLoop->GetMeLoops()) { + MapleSet &loopBBs = loop->loopBBs; + // Find loop exit bbs. + MapleVector exits(tmpAlloc.Adapter()); + for (auto &bbID : loopBBs) { + BB *bb = func->GetAllBBs().at(bbID); + if (bb->GetSucc().size() < minBBNumRequired) { + continue; + } + for (auto *it : bb->GetSucc()) { + ASSERT_NOT_NULL(it); + if (!loop->Has(*it)) { + Edge *edge = FindEdge(*bb, *it); + exits.push_back(edge); + break; + } + } + } + // predicate loop exit. + if (exits.empty()) { + return; + } + for (auto &exit : exits) { + // Loop heuristics do not expect exit conditional to be inside + // inner loop. We predict from innermost to outermost loop. + if (PredictedByLoopHeuristic(exit->src)) { + continue; + } + int32 probability = kProbBase - predictorInfo[kPredLoopExit].hitRate; + PredictEdge(*exit, kPredLoopExit, probability); + } + } +} + +// Predict using opcode of the last statement in basic block. +void MePrediction::PredictByOpcode(const BB *bb) { + if (bb == nullptr || bb->GetMeStmts().empty() || !bb->GetMeStmts().back().IsCondBr()) { + return; + } + auto &condStmt = static_cast(bb->GetMeStmts().back()); + bool isTrueBr = condStmt.GetOp() == OP_brtrue; + MeExpr *testExpr = condStmt.GetOpnd(); + MeExpr *op0 = nullptr; + MeExpr *op1 = nullptr; + // Only predict MeOpOp operands now. + if (testExpr->GetMeOp() != kMeOpOp) { + return; + } + auto *cmpExpr = static_cast(testExpr); + op0 = cmpExpr->GetOpnd(0); + op1 = cmpExpr->GetOpnd(1); + Opcode cmp = testExpr->GetOp(); + Edge *e0 = edges[bb->GetBBId()]; + Edge *e1 = e0->next; + Edge *thenEdge; + if (isTrueBr) { + thenEdge = (e0->dest.GetBBLabel() == condStmt.GetOffset()) ? e0 : e1; + } else { + thenEdge = (e0->dest.GetBBLabel() == condStmt.GetOffset()) ? e1 : e0; + } + PrimType pty = op0->GetPrimType(); + // Try "pointer heuristic." A comparison ptr == 0 is predicted as false. + // Similarly, a comparison ptr1 == ptr2 is predicted as false. + if (pty == PTY_ptr || pty == PTY_ref) { + if (cmp == OP_eq) { + PredEdgeDef(*thenEdge, kPredPointer, kNotTaken); + } else if (cmp == OP_ne) { + PredEdgeDef(*thenEdge, kPredPointer, kTaken); + } + } else { + // Try "opcode heuristic." EQ tests are usually false and NE tests are usually true. Also, + // most quantities are positive, so we can make the appropriate guesses + // about signed comparisons against zero. + switch (cmp) { + case OP_eq: + case OP_ne: { + Prediction taken = ((cmp == OP_eq) ? kNotTaken : kTaken); + // identify that a comparerison of an integer equal to a const or floating point numbers + // are equal to be not taken + if (IsPrimitiveFloat(pty) || (IsPrimitiveInteger(pty) && (op1->GetMeOp() == kMeOpConst))) { + PredEdgeDef(*thenEdge, kPredOpcodeNonEqual, taken); + } + break; + } + case OP_lt: + case OP_le: + case OP_gt: + case OP_ge: { + if (op1->GetMeOp() == kMeOpConst) { + auto *constVal = static_cast(op1); + if (constVal->IsZero() || constVal->IsOne()) { + Prediction taken = ((cmp == OP_lt || cmp == OP_le) ? kNotTaken : kTaken); + PredEdgeDef(*thenEdge, kPredOpcodePositive, taken); + } + } + break; + } + default: + break; + } + } +} + +void MePrediction::EstimateBBProb(const BB &bb) { + for (size_t i = 0; i < bb.GetSucc().size(); ++i) { + const BB *dest = bb.GetSucc(i); + // try fallthrou if taken. + if (!bb.GetMeStmts().empty() && bb.GetMeStmts().back().GetOp() == OP_try && i == 0) { + PredEdgeDef(*FindEdge(bb, *dest), kPredTry, kTaken); + } else if (!dest->GetMeStmts().empty() && dest->GetMeStmts().back().GetOp() == OP_return) { + PredEdgeDef(*FindEdge(bb, *dest), kPredEarlyReturn, kNotTaken); + } else if (dest != func->GetCommonExitBB() && dest != &bb && dom->Dominate(bb, *dest) && + !dom->PostDominate(*dest, bb)) { + for (const MeStmt &stmt : dest->GetMeStmts()) { + if (stmt.GetOp() == OP_call || stmt.GetOp() == OP_callassigned) { + auto &callMeStmt = static_cast(stmt); + const MIRFunction &callee = callMeStmt.GetTargetFunction(); + // call heuristic : exceptional calls not taken. + if (!callee.IsPure()) { + PredEdgeDef(*FindEdge(bb, *dest), kPredCall, kNotTaken); + } else { + // call heristic : normal call taken. + PredEdgeDef(*FindEdge(bb, *dest), kPredCall, kTaken); + } + break; + } + } + } + } + PredictByOpcode(&bb); +} + +void MePrediction::ClearBBPredictions(const BB &bb) { + bbPredictions[bb.GetBBId()] = nullptr; +} + +// Combine predictions into single probability and store them into CFG. +// Remove now useless prediction entries. +void MePrediction::CombinePredForBB(const BB &bb) { + // When there is no successor or only one choice, prediction is easy. + // When we have a basic block with more than 2 successors, the situation + // is more complicated as DS theory cannot be used literally. + // More precisely, let's assume we predicted edge e1 with probability p1, + // thus: m1({b1}) = p1. As we're going to combine more than 2 edges, we + // need to find probability of e.g. m1({b2}), which we don't know. + // The only approximation is to equally distribute 1-p1 to all edges + // different from b1. + constexpr uint32 succNumForComplicatedSituation = 2; + if (bb.GetSucc().size() != succNumForComplicatedSituation) { + MapleSet unlikelyEdges(tmpAlloc.Adapter()); + // Identify all edges that have a probability close to very unlikely. + EdgePrediction *preds = bbPredictions[bb.GetBBId()]; + if (preds != nullptr) { + EdgePrediction *pred = nullptr; + for (pred = preds; pred != nullptr; pred = pred->epNext) { + if (pred->epProbability <= kProbVeryUnlikely) { + unlikelyEdges.insert(&pred->epEdge); + } + } + } + uint32 all = kProbAlways; + uint32 nEdges = 0; + uint32 unlikelyCount = 0; + Edge *edge = edges[bb.GetBBId()]; + for (Edge *e = edge; e != nullptr; e = e->next) { + if (e->probability > 0) { + CHECK_FATAL(e->probability <= all, "e->probability is greater than all"); + all -= e->probability; + } else { + nEdges++; + if (!unlikelyEdges.empty() && unlikelyEdges.find(edge) != unlikelyEdges.end()) { + CHECK_FATAL(all >= kProbVeryUnlikely, "all is lesser than kProbVeryUnlikely"); + all -= kProbVeryUnlikely; + e->probability = kProbVeryUnlikely; + unlikelyCount++; + } + } + } + if (unlikelyCount == nEdges) { + unlikelyEdges.clear(); + ClearBBPredictions(bb); + return; + } + uint32 total = 0; + for (Edge *e = edge; e != nullptr; e = e->next) { + if (e->probability == kProbUninitialized) { + e->probability = all / (nEdges - unlikelyCount); + total += e->probability; + } + if (predictDebug) { + LogInfo::MapleLogger() << "Predictions for bb " << bb.GetBBId() << " \n"; + if (unlikelyEdges.empty()) { + LogInfo::MapleLogger() << nEdges << " edges in bb " << bb.GetBBId() << + " predicted to even probabilities.\n"; + } else { + LogInfo::MapleLogger() << nEdges << " edges in bb " << bb.GetBBId() << + " predicted with some unlikely edges\n"; + } + } + } + if (total != all) { + edge->probability += all - total; + } + ClearBBPredictions(bb); + return; + } + if (predictDebug) { + LogInfo::MapleLogger() << "Predictions for bb " << bb.GetBBId() << " \n"; + } + int nunknown = 0; + Edge *first = nullptr; + Edge *second = nullptr; + for (Edge *edge = edges[bb.GetBBId()]; edge != nullptr; edge = edge->next) { + if (first == nullptr) { + first = edge; + } else if (second == nullptr) { + second = edge; + } + if (edge->probability == kProbUninitialized) { + nunknown++; + } + } + // If we have only one successor which is unknown, we can compute missing probablity. + if (nunknown == 1) { + int32 prob = kProbAlways; + Edge *missing = nullptr; + for (Edge *edge = edges[bb.GetBBId()]; edge != nullptr; edge = edge->next) { + if (edge->probability > 0) { + prob -= edge->probability; + } else if (missing == nullptr) { + missing = edge; + } else { + CHECK_FATAL(false, "unreachable"); + } + } + CHECK_FATAL(missing != nullptr, "null ptr check"); + missing->probability = prob; + return; + } + EdgePrediction *preds = bbPredictions[bb.GetBBId()]; + int combinedProbability = kProbBase / static_cast(kScaleDownFactor); + int denominator = 0; + if (preds != nullptr) { + // use DS Theory. + for (EdgePrediction *pred = preds; pred != nullptr; pred = pred->epNext) { + int probability = pred->epProbability; + if (&pred->epEdge != first) { + probability = kProbBase - probability; + } + denominator = (combinedProbability * probability + (kProbBase - combinedProbability) * (kProbBase - probability)); + // Use FP math to avoid overflows of 32bit integers. + if (denominator == 0) { + // If one probability is 0% and one 100%, avoid division by zero. + combinedProbability = kProbBase / kScaleDownFactor; + } else { + combinedProbability = + static_cast(static_cast(combinedProbability) * probability * kProbBase / denominator); + } + } + } + if (predictDebug) { + CHECK_FATAL(first != nullptr, "null ptr check"); + constexpr int hundredPercent = 100; + LogInfo::MapleLogger() << "combined heuristics of edge BB" << bb.GetBBId() << "->BB" << first->dest.GetBBId() << + ":" << (combinedProbability * hundredPercent / kProbBase) << "%\n"; + if (preds != nullptr) { + for (EdgePrediction *pred = preds; pred != nullptr; pred = pred->epNext) { + Predictor predictor = pred->epPredictor; + int probability = pred->epProbability; + LogInfo::MapleLogger() << predictorInfo[predictor].name << " heuristics of edge BB" << + pred->epEdge.src.GetBBId() << "->BB" << pred->epEdge.dest.GetBBId() << + ":" << (probability * hundredPercent / kProbBase) << "%\n"; + } + } + } + ClearBBPredictions(bb); + CHECK_FATAL(first != nullptr, "null ptr check"); + first->probability = combinedProbability; + CHECK_FATAL(second != nullptr, "null ptr check"); + second->probability = kProbBase - combinedProbability; +} + +void MePrediction::PropagateFreq(BB &head, BB &bb) { + if (bbVisited[bb.GetBBId()]) { + return; + } + // 1. find bfreq(bb) + if (&bb == &head) { + head.SetFrequency(kFreqBase); + } else { + for (size_t i = 0; i < bb.GetPred().size(); ++i) { + BB *pred = bb.GetPred(i); + if (!bbVisited[pred->GetBBId()] && pred != &bb && !IsBackEdge(*FindEdge(*pred, bb))) { + if (predictDebug) { + LogInfo::MapleLogger() << "BB" << bb.GetBBId() << " can't be estimated because it's predecessor BB" << + pred->GetBBId() << " hasn't be estimated yet\n"; + if (bb.GetAttributes(kBBAttrIsInLoop) && + (bb.GetAttributes(kBBAttrIsTry) || bb.GetAttributes(kBBAttrIsCatch) || + pred->GetAttributes(kBBAttrIsTry) || pred->GetAttributes(kBBAttrIsCatch))) { + LogInfo::MapleLogger() << "BB" << bb.GetBBId() << + " can't be recognized as loop head/tail because of eh.\n"; + } + } + return; + } + } + uint32 freq = 0; + double cyclicProb = 0; + for (BB *pred : bb.GetPred()) { + Edge *edge = FindEdge(*pred, bb); + if (IsBackEdge(*edge) && &edge->dest == &head) { + cyclicProb += backEdgeProb[edge]; + } else { + freq += edge->frequency; + } + } + if (cyclicProb > (1 - std::numeric_limits::epsilon())) { + cyclicProb = 1 - std::numeric_limits::epsilon(); + } + bb.SetFrequency(static_cast(freq / (1 - cyclicProb))); + } + // 2. calculate frequencies of bb's out edges + if (predictDebug) { + LogInfo::MapleLogger() << "Estimate Frequency of BB" << bb.GetBBId() << "\n"; + } + bbVisited[bb.GetBBId()] = true; + uint32 tmp = 0; + uint32 total = 0; + Edge *bestEdge = nullptr; + for (size_t i = 0; i < bb.GetSucc().size(); ++i) { + Edge *edge = FindEdge(bb, *bb.GetSucc(i)); + if (i == 0) { + bestEdge = edge; + tmp = edge->probability; + } else { + CHECK_NULL_FATAL(edge); + if (edge->probability > tmp) { + tmp = edge->probability; + bestEdge = edge; + } + } + edge->frequency = edge->probability * bb.GetFrequency() / kProbBase; + total += edge->frequency; + if (&edge->dest == &head) { + backEdgeProb[edge] = static_cast(edge->probability) * bb.GetFrequency() / (kProbBase * kFreqBase); + } + } + if (bestEdge != nullptr && total != bb.GetFrequency()) { + bestEdge->frequency += bb.GetFrequency() - total; + } + // 3. propagate to successor blocks + for (auto *succ : bb.GetSucc()) { + if (!bbVisited[succ->GetBBId()]) { + PropagateFreq(head, *succ); + } + } +} + +void MePrediction::EstimateLoops() { + for (auto *loop : meLoop->GetMeLoops()) { + MapleSet &loopBBs = loop->loopBBs; + backEdges.push_back(FindEdge(*loop->tail, *loop->head)); + for (auto &bbId : loopBBs) { + bbVisited[bbId] = false; + } + PropagateFreq(*loop->head, *loop->head); + } + // Now propagate the frequencies through all the blocks. + std::fill(bbVisited.begin(), bbVisited.end(), false); + if (func->GetCommonEntryBB() != func->GetFirstBB()) { + bbVisited[func->GetCommonEntryBB()->GetBBId()] = false; + } + if (func->GetCommonExitBB() != func->GetLastBB()) { + bbVisited[func->GetCommonExitBB()->GetBBId()] = false; + } + func->GetCommonEntryBB()->SetFrequency(kFreqBase); + for (BB *bb : func->GetCommonEntryBB()->GetSucc()) { + PropagateFreq(*bb, *bb); + } +} + +void MePrediction::EstimateBBFrequencies() { + BB *entry = func->GetCommonEntryBB(); + edges[entry->GetBBId()]->probability = kProbAlways; + double backProb = 0.0; + for (size_t i = 0; i < func->GetAllBBs().size(); ++i) { + Edge *edge = edges[i]; + while (edge != nullptr) { + if (edge->probability > 0) { + backProb = edge->probability; + } else { + backProb = kProbBase / kScaleDownFactor; + } + backProb = backProb / kProbBase; + (void)backEdgeProb.insert(std::make_pair(edge, backProb)); + edge = edge->next; + } + } + // First compute frequencies locally for each loop from innermost + // to outermost to examine frequencies for back edges. + EstimateLoops(); +} + +// Main function +void MePrediction::EstimateProbability() { + Init(); + BBLevelPredictions(); + if (!meLoop->GetMeLoops().empty()) { + // innermost loop in the first place for EstimateFrequencies. + SortLoops(); + PredictLoops(); + } + + MapleVector &bbVec = func->GetAllBBs(); + for (auto *bb : bbVec) { + EstimateBBProb(*bb); + } + for (auto *bb : bbVec) { + CombinePredForBB(*bb); + } + for (size_t i = 0; i < func->GetAllBBs().size(); ++i) { + int32 all = 0; + for (Edge *edge = edges[i]; edge != nullptr; edge = edge->next) { + if (predictDebug) { + constexpr uint32 hundredPercent = 100; + LogInfo::MapleLogger() << "probability for edge BB" << edge->src.GetBBId() << "->BB" << + edge->dest.GetBBId() << " is " << (edge->probability / hundredPercent) << "%\n"; + } + all += edge->probability; + } + if (edges[i] != nullptr) { + CHECK_FATAL(all == kProbBase, "total probability is not 1"); + } + } + EstimateBBFrequencies(); +} + +void MePrediction::SetPredictDebug(bool val) { + predictDebug = val; +} + +// Estimate the execution frequecy for all bbs. +AnalysisResult *MeDoPredict::Run(MeFunction *func, MeFuncResultMgr *m, ModuleResultMgr*) { + auto *hMap = static_cast(m->GetAnalysisResult(MeFuncPhase_IRMAPBUILD, func)); + CHECK_FATAL(hMap != nullptr, "hssamap is nullptr"); + auto *dom = static_cast(m->GetAnalysisResult(MeFuncPhase_DOMINANCE, func)); + CHECK_FATAL(dom != nullptr, "dominance phase has problem"); + m->InvalidAnalysisResult(MeFuncPhase_MELOOP, func); + auto *meLoop = static_cast(m->GetAnalysisResult(MeFuncPhase_MELOOP, func)); + CHECK_FATAL(meLoop != nullptr, "meloop has problem"); + MemPool *mePredMp = NewMemPool(); + MePrediction *mePredict = mePredMp->New(*mePredMp, *NewMemPool(), *func, *dom, *meLoop, *hMap); + if (DEBUGFUNC(func)) { + mePredict->SetPredictDebug(true); + } + mePredict->EstimateProbability(); + if (DEBUGFUNC(func)) { + LogInfo::MapleLogger() << "\n============== Prediction =============" << '\n'; + func->Dump(false); + } + return mePredict; +} +} // namespace maple diff --git a/src/mapleall/maple_me/src/me_profile_use.cpp b/src/mapleall/maple_me/src/me_profile_use.cpp index a8f4d2fc1e258e081af7191087e83a0a56913a10..3c4c523a1201e5be83fd9213ace87242932fdcbc 100644 --- a/src/mapleall/maple_me/src/me_profile_use.cpp +++ b/src/mapleall/maple_me/src/me_profile_use.cpp @@ -258,6 +258,9 @@ void MeProfUse::SetFuncEdgeInfo() { } func->SetProfValid(); func->SetFrequency(func->GetCommonEntryBB()->GetFrequency()); + if (Options::genPGOReport) { + func->GetMIRModule().GetProfile().SetFuncStatus(func->GetName(), true); + } } void MeProfUse::DumpFuncCFGEdgeFreq() const { diff --git a/src/mapleall/maple_me/src/me_prop.cpp b/src/mapleall/maple_me/src/me_prop.cpp index 086e73097f6322577d8bea5de726be819fcb9f93..9b80e870bba052e5e61d4c39a43aae140553643f 100644 --- a/src/mapleall/maple_me/src/me_prop.cpp +++ b/src/mapleall/maple_me/src/me_prop.cpp @@ -23,6 +23,13 @@ // Copy propagation works by conducting a traversal over the program. When it // encounters a variable reference, it uses its SSA representation to look up // its assigned value and try to do the substitution. +namespace { +const std::set propWhiteList { +#define PROPILOAD(funcname) #funcname, +#include "propiloadlist.def" +#undef PROPILOAD +}; +} namespace maple { AnalysisResult *MeDoMeProp::Run(MeFunction *func, MeFuncResultMgr *m, ModuleResultMgr*) { @@ -32,6 +39,16 @@ AnalysisResult *MeDoMeProp::Run(MeFunction *func, MeFuncResultMgr *m, ModuleResu auto *hMap = static_cast(m->GetAnalysisResult(MeFuncPhase_IRMAPBUILD, func)); CHECK_NULL_FATAL(hMap); bool propIloadRef = MeOption::propIloadRef; + if (!propIloadRef) { + MIRSymbol *fnSt = GlobalTables::GetGsymTable().GetSymbolFromStidx(func->GetMirFunc()->GetStIdx().Idx()); + const std::string &funcName = fnSt->GetName(); + propIloadRef = propWhiteList.find(funcName) != propWhiteList.end(); + if (DEBUGFUNC(func)) { + if (propIloadRef) { + LogInfo::MapleLogger() << "propiloadref enabled because function is in white list"; + } + } + } MeProp meProp(*hMap, *dom, *NewMemPool(), Prop::PropConfig { MeOption::propBase, propIloadRef, MeOption::propGlobalRef, MeOption::propFinaliLoadRef, MeOption::propIloadRefNonParm, MeOption::propAtPhi }); meProp.TraversalBB(*func->GetCommonEntryBB()); diff --git a/src/mapleall/maple_me/src/me_rc_lowering.cpp b/src/mapleall/maple_me/src/me_rc_lowering.cpp index e62f840097a73af081853f9cea747d148987cf35..9d8a4ca0d2cace838799981bba32757a2fea8248 100644 --- a/src/mapleall/maple_me/src/me_rc_lowering.cpp +++ b/src/mapleall/maple_me/src/me_rc_lowering.cpp @@ -21,6 +21,9 @@ // based on previous analyze results. RC intrinsic will later be lowered // in Code Generation namespace { +const std::set whiteListFunc { +#include "rcwhitelist.def" +}; } namespace maple { @@ -41,7 +44,10 @@ void RCLowering::Prepare() { LogInfo::MapleLogger() << "Handling function " << mirFunction->GetName() << '\n'; } func.SetHints(func.GetHints() | kRcLowered); - isAnalyzed = (func.GetHints() & kAnalyzeRCed) != 0; + isAnalyzed = (func.GetHints() & (kAnalyzeRCed | kPlacementRCed)) != 0; + rcCheckReferent = (mirFunction->GetName() == + "Ljava_2Flang_2Fref_2FReference_3B_7C_3Cinit_3E_7C_" + "28Ljava_2Flang_2FObject_3BLjava_2Flang_2Fref_2FReferenceQueue_3B_29V"); } void RCLowering::PreRCLower() { @@ -55,6 +61,10 @@ void RCLowering::PreRCLower() { MarkAllRefOpnds(); CreateCleanupIntrinsics(); + auto *bb = func.GetCommonEntryBB(); + CHECK_FATAL(bb != nullptr, "null ptr check"); + UpdateRefVarVersions(*bb); + UnmarkNotNeedDecRefOpnds(); } void RCLowering::MarkLocalRefVar() { @@ -96,6 +106,111 @@ void RCLowering::MarkAllRefOpnds() { } } +// Mark the statement that needs incref or decref +void RCLowering::UpdateRefVarVersions(BB &bb) { + std::map savedStackSize; + RecordVarPhiVersions(savedStackSize, bb); + + // traverse the BB stmts + TraverseAllStmts(bb); + + // recursive call in preorder traversal of dominator tree + ASSERT(bb.GetBBId() < dominance->GetDomChildrenSize(), "index out of range"); + const MapleSet &domChildren = dominance->GetDomChildren(bb.GetBBId()); + for (const auto &id : domChildren) { + UpdateRefVarVersions(*func.GetAllBBs().at(id)); + } + + // restore the stacks to their size at entry to this function invocation + RestoreVersionRecords(savedStackSize); +} + +void RCLowering::RecordVarPhiVersions(std::map &savedStackSize, const BB &bb) { + for (const auto &item : varOStMap) { + if (!item.second->IsLocal()) { + continue; + } + // record stack size + savedStackSize[item.second->GetIndex()] = varVersions[item.second->GetIndex()].size(); + // if there is a phi, push stack + auto it = bb.GetMePhiList().find(item.second->GetIndex()); + if (it != bb.GetMePhiList().end()) { + varVersions[item.second->GetIndex()].push_back((*it).second->GetLHS()); + } + } +} + +void RCLowering::TraverseAllStmts(BB &bb) { + MeStmts &stmts = bb.GetMeStmts(); + if (stmts.empty()) { + return; + } + + for (auto &stmt : stmts) { + MeExpr *lhsRef = stmt.GetLHSRef(false); + if (lhsRef == nullptr) { + continue; + } + OStIdx ostIdx(0); + if (lhsRef->GetMeOp() == kMeOpVar) { + ostIdx = static_cast(lhsRef)->GetOstIdx(); + } else { + ASSERT(lhsRef->GetMeOp() == kMeOpIvar, "PreRCLower: Not Expected meop"); + auto *ivar = static_cast(lhsRef); + if (ivar->GetMu() != nullptr) { + ostIdx = ivar->GetMu()->GetOstIdx(); + } else { + ASSERT(ivar->GetDefStmt() != nullptr, "PreRCLower: ivar with mu==nullptr has no defStmt"); + IassignMeStmt *iass = ivar->GetDefStmt(); + ASSERT(!iass->GetChiList()->empty(), "PreRCLower: ivar with mu==nullptr has empty chiList at its def"); + ostIdx = iass->GetChiList()->begin()->second->GetLHS()->GetOstIdx(); + } + } + ASSERT(ostIdx != 0, "PreRCLower: cannot get ostIdx"); + if (varOStMap.find(ostIdx) != varOStMap.end()) { + if (!varVersions[ostIdx].empty()) { + decOpnds[&stmt] = varVersions[ostIdx].back(); + } else { + decOpnds[&stmt] = irMap.GetOrCreateZeroVersionVarMeExpr(*varOStMap[ostIdx]); + } + } else if (stmt.GetOp() == OP_intrinsiccall && + static_cast(stmt).GetIntrinsic() == INTRN_MPL_CLEANUP_LOCALREFVARS) { + auto &intrn = static_cast(stmt); + for (size_t i = 0; i < intrn.NumMeStmtOpnds(); ++i) { + auto *varMeExpr = static_cast(intrn.GetOpnd(i)); + if (!varVersions[ostIdx].empty()) { + intrn.SetOpnd(i, varVersions[varMeExpr->GetOstIdx()].back()); + } + } + } + varVersions[ostIdx].push_back(lhsRef); + } +} + +void RCLowering::RestoreVersionRecords(std::map &savedStackSize) { + for (const auto &item : varOStMap) { + if (!item.second->IsLocal()) { + continue; + } + size_t lastSize = savedStackSize[item.second->GetIndex()]; + while (varVersions[item.second->GetIndex()].size() > lastSize) { + varVersions[item.second->GetIndex()].pop_back(); + } + } +} + +void RCLowering::UnmarkNotNeedDecRefOpnds() { + for (auto item : decOpnds) { + if (item.first->GetLHSRef(false)->GetMeOp() == kMeOpVar) { + auto *var = static_cast(item.second); + OriginalSt *ost = varOStMap[var->GetOstIdx()]; + if (ost->IsLocal() && !ost->IsFormal() && (var->IsZeroVersion() || var->GetDefBy() == kDefByNo)) { + item.first->DisableNeedDecref(); + } + } + } +} + void RCLowering::CreateCleanupIntrinsics() { for (BB *bb : func.GetCommonExitBB()->GetPred()) { MeStmt *lastMeStmt = to_ptr(bb->GetMeStmts().rbegin()); @@ -155,8 +270,10 @@ IntrinsiccallMeStmt *RCLowering::GetVarRHSHandleStmt(const MeStmt &stmt) { std::vector opnds; bool isVolatile = var->IsVolatile(); MIRIntrinsicID rcCallID = INTRN_UNDEFINED; - rcCallID = isVolatile ? PrepareVolatileCall(stmt, INTRN_MCCLoadRefSVol) : INTRN_MCCLoadRefS; - opnds.push_back(irMap.CreateAddrofMeExpr(*var)); + if (!MeOption::strictNaiveRC || isVolatile) { + rcCallID = isVolatile ? PrepareVolatileCall(stmt, INTRN_MCCLoadRefSVol) : INTRN_MCCLoadRefS; + opnds.push_back(irMap.CreateAddrofMeExpr(*var)); + } // rhs is not special, skip if (rcCallID == INTRN_UNDEFINED) { @@ -196,10 +313,12 @@ void RCLowering::HandleAssignMeStmtRHS(MeStmt &stmt) { MeExpr *rhs = stmt.GetRHS(); CHECK_FATAL(rhs != nullptr, "rhs is nullptr in RCLowering::HandleAssignMeStmtRHS"); IntrinsiccallMeStmt *loadCall = nullptr; + bool isRCWeak = false; std::vector opnds; if (rhs->GetMeOp() == kMeOpVar) { loadCall = GetVarRHSHandleStmt(stmt); } else if (rhs->GetMeOp() == kMeOpIvar) { + isRCWeak = static_cast(rhs)->IsRCWeak(); loadCall = GetIvarRHSHandleStmt(stmt); } // rhs is not special, skip @@ -208,7 +327,7 @@ void RCLowering::HandleAssignMeStmtRHS(MeStmt &stmt) { } if (stmt.GetOp() == OP_regassign) { stmt.GetBB()->ReplaceMeStmt(&stmt, loadCall); - if (rhs->IsVolatile()) { + if (rhs->IsVolatile() && !isRCWeak) { stmt.SetOpnd(1, loadCall->GetMustDefList()->front().GetLHS()); } } else { @@ -243,7 +362,17 @@ void RCLowering::HandleCallAssignedMeStmt(MeStmt &stmt, MeExpr *pendingDec) { if (retSym == nullptr) { return; } + // rcunowned needs special handling + if (retSym->IgnoreRC() && !retSym->GetAttr(ATTR_rcunowned)) { + return; + } assignedPtrSym.insert(retSym); + if (retSym->GetAttr(ATTR_rcunowned)) { + // if retSym is rcunowned, we need to introduce a new localrefvar to decref in cleanup + MeStmt *regToTmp = irMap.CreateDassignMeStmt(*CreateNewTmpVarMeExpr(true), *lhs, *bb); + bb->InsertMeStmtAfter(&stmt, regToTmp); + return; + } if (!stmt.NeedDecref()) { return; } @@ -338,6 +467,9 @@ void RCLowering::HandleAssignMeStmtRegLHS(MeStmt &stmt) { void RCLowering::HandleAssignMeStmtVarLHS(MeStmt &stmt, MeExpr *pendingDec) { const MIRSymbol *lsym =stmt.GetVarLHS()->GetOst()->GetMIRSymbol(); + if (lsym->IgnoreRC()) { + return; + } if (lsym->IsGlobal()) { // decref could be optimized away after if null check HandleAssignToGlobalVar(stmt); @@ -494,7 +626,25 @@ void RCLowering::HandleAssignMeStmtIvarLHS(MeStmt &stmt) { fieldSet.insert(fieldID); } MeExpr *rhsInner = stmt.GetRHS(); + bool isReferent = false; + if (rcCheckReferent) { + // check if iassign field is volatile T referent; + FieldID id = mirModule.GetMIRBuilder()->GetStructFieldIDFromFieldNameParentFirst(ptype, "referent"); + if (id == iassign.GetLHSVal()->GetFieldID()) { + std::vector opnds = { &lhsInner->GetBase()->GetAddrExprBase(), rhsInner }; + IntrinsiccallMeStmt *writeReferentCall = CreateRCIntrinsic(INTRN_MCCWriteReferent, stmt, opnds); + stmt.GetBB()->InsertMeStmtAfter(&stmt, writeReferentCall); + isReferent = true; + } + } MIRIntrinsicID intrinsicID = SelectWriteBarrier(stmt); + if (isReferent) { // optimize storeload again due to referent handling + MeStmt *next = stmt.GetNext(); + if (next != nullptr) { + next = next->GetNext(); + } + CheckRemove(next, OP_membarstoreload); + } std::vector opnds = { &lhsInner->GetBase()->GetAddrExprBase(), irMap.CreateAddrofMeExpr(*lhsInner), rhsInner }; IntrinsiccallMeStmt *writeRefCall = CreateRCIntrinsic(intrinsicID, stmt, opnds); @@ -503,6 +653,7 @@ void RCLowering::HandleAssignMeStmtIvarLHS(MeStmt &stmt) { } void RCLowering::HandleAssignMeStmt(MeStmt &stmt, MeExpr *pendingDec) { + HandlePerManent(stmt); PreprocessAssignMeStmt(stmt); if (!stmt.NeedIncref() && !stmt.NeedDecref()) { return; @@ -519,6 +670,60 @@ void RCLowering::HandleAssignMeStmt(MeStmt &stmt, MeExpr *pendingDec) { } } +void RCLowering::HandlePerManent(MeStmt &stmt) { + VarMeExpr *lhs = stmt.GetVarLHS(); + if (lhs == nullptr) { + return; + } + + const MIRSymbol *sym = lhs->GetOst()->GetMIRSymbol(); + if (sym->GetType()->GetPrimType() != PTY_ref) { + return; + } + if (!sym->IsStatic() || !sym->IsFinal()) { + return; + } + + MeExpr *rhs = stmt.GetRHS(); + MeStmt *defStmt = nullptr; + if (rhs->GetMeOp() == kMeOpVar) { + auto *var = static_cast(rhs); + if (var->GetDefBy() == kDefByStmt) { + defStmt = var->GetDefStmt(); + } + } else if (rhs->GetMeOp() == kMeOpReg) { + auto *regVar = static_cast(rhs); + if (regVar->GetDefBy() == kDefByStmt) { + defStmt = regVar->GetDefStmt(); + } + } + if (defStmt != nullptr) { + MeExpr *rhsOfDefStmt = defStmt->GetRHS(); + if (rhsOfDefStmt->IsGcmalloc() && !HasCallOrBranch(*defStmt, stmt)) { + if (rhsOfDefStmt->GetOp() == OP_gcmalloc) { + rhsOfDefStmt->SetOp(OP_gcpermalloc); + } else if (rhsOfDefStmt->GetOp() == OP_gcmallocjarray) { + rhsOfDefStmt->SetOp(OP_gcpermallocjarray); + } + return; + } + } + std::vector opnds = { rhs }; + IntrinsiccallMeStmt *setPermanentCall = CreateRCIntrinsic(INTRN_MCCSetPermanent, stmt, opnds); + stmt.GetBB()->InsertMeStmtBefore(&stmt, setPermanentCall); +} + +bool RCLowering::HasCallOrBranch(const MeStmt &from, const MeStmt &to) { + if (from.GetBB() != to.GetBB()) { + return true; + } + for (const MeStmt *stmt = &from; stmt != &to; stmt = stmt->GetNextMeStmt()) { + if (kOpcodeInfo.IsCall(stmt->GetOp())) { + return true; + } + } + return false; +} // align with order in rcinsertion, otherwise missing weak volatile // note that we are generating INTRN_MCCWriteNoRC so write_barrier is supported, @@ -557,6 +762,7 @@ void RCLowering::RCLower() { if (bIt == func.common_entry() || bIt == func.common_exit()) { continue; } + EpreFixup(**bIt); BBLower(**bIt); } } @@ -615,8 +821,8 @@ void RCLowering::BBLower(BB &bb) { initializedFields.clear(); needSpecialHandleException = bb.GetAttributes(kBBAttrIsCatch); for (auto &stmt : bb.GetMeStmts()) { - if ((func.GetHints() & kAnalyzeRCed) == 0) { - pendingDec = stmt.GetLHSRef(false); + if (!isAnalyzed && decOpnds.find(&stmt) != decOpnds.end()) { + pendingDec = decOpnds[&stmt]; } Opcode opcode = stmt.GetOp(); if (opcode == OP_return) { @@ -662,6 +868,38 @@ IntrinsiccallMeStmt *FindCleanupIntrinsic(const MeStmt &ret) { return nullptr; } +// epre could have change dassign (iread) to regassign (iread) + dassign (regread) +// as a result, LoadRefField was not generated. This function fixes up the issue +// by checking rhs to see if it is regread and then try to +// propagate incref from current stmt back to regassign from iread which had no incref +void RCLowering::EpreFixup(BB &bb) { + for (auto &stmt : bb.GetMeStmts()) { + // remove decref as mpl2mpl will insert based on ref assign + if (!stmt.NeedIncref()) { + continue; + } + MeExpr *rhs = stmt.GetRHS(); + if (stmt.GetOp() != OP_dassign || rhs == nullptr || rhs->GetOp() != OP_regread) { + continue; + } + auto *rhsVar = static_cast(rhs); + if (rhsVar->GetDefBy() != kDefByStmt) { + continue; + } + MeStmt *defStmt = rhsVar->GetDefStmt(); + if (defStmt->GetBB() != stmt.GetBB()) { + continue; // we cannot fix up across bb + } + CHECK_FATAL(defStmt->GetRHS() != nullptr, "null ptr check"); + if (defStmt->NeedIncref() || defStmt->GetRHS()->GetOp() != OP_iread) { + continue; + } + // pull incref from regread stmt to regassign + defStmt->EnableNeedIncref(); + stmt.DisableNeedIncref(); + } +} + void RCLowering::HandleReturnVar(RetMeStmt &ret) { auto *retVar = static_cast(ret.GetOpnd(0)); CHECK_FATAL(retVar != nullptr, "retVal null ptr check"); @@ -680,7 +918,9 @@ void RCLowering::HandleReturnVar(RetMeStmt &ret) { // must be regreadAtReturn // checking localrefvar because some objects are meta HandleReturnRegread(ret); - } else { + } else if (!((func.GetHints() & kPlacementRCed) && sym != nullptr && sym->GetStorageClass() == kScFormal && + assignedPtrSym.count(sym) > 0)) { + // if returning formal, incref unless placementRC is used and formal is NOT reassigned HandleReturnFormal(ret); } } @@ -690,11 +930,20 @@ void RCLowering::HandleReturnGlobal(RetMeStmt &ret) { CHECK_FATAL(bb != nullptr, "bb null ptr check"); auto *retVar = static_cast(ret.GetOpnd(0)); CHECK_FATAL(retVar != nullptr, "retVal null ptr check"); - std::vector opnds = { irMap.CreateAddrofMeExpr(*retVar) }; - IntrinsiccallMeStmt *loadCall = CreateRCIntrinsic(INTRN_MCCLoadRefS, ret, opnds, true); - bb->InsertMeStmtBefore(&ret, loadCall); - ret.SetOpnd(0, loadCall->GetMustDefList()->front().GetLHS()); - + if (MeOption::strictNaiveRC) { + RegMeExpr *curTmp = irMap.CreateRegMeExpr(PTY_ref); + RegassignMeStmt *regAssStmt = irMap.CreateRegassignMeStmt(*curTmp, *retVar, *bb); + bb->InsertMeStmtBefore(&ret, regAssStmt); + std::vector opnds = { regAssStmt->GetRegLHS() }; + IntrinsiccallMeStmt *incCall = CreateRCIntrinsic(INTRN_MCCIncRef, *regAssStmt, opnds, true); + bb->InsertMeStmtBefore(&ret, incCall); + ret.SetOpnd(0, curTmp); + } else { + std::vector opnds = { irMap.CreateAddrofMeExpr(*retVar) }; + IntrinsiccallMeStmt *loadCall = CreateRCIntrinsic(INTRN_MCCLoadRefS, ret, opnds, true); + bb->InsertMeStmtBefore(&ret, loadCall); + ret.SetOpnd(0, loadCall->GetMustDefList()->front().GetLHS()); + } } void RCLowering::HandleReturnRegread(RetMeStmt &ret) { @@ -750,11 +999,20 @@ void RCLowering::HandleReturnIvar(RetMeStmt &ret) { ret.GetBB()->InsertMeStmtBefore(&ret, loadCall); ret.SetOpnd(0, loadCall->GetMustDefList()->front().GetLHS()); } else { - std::vector opnds = { &retIvar->GetBase()->GetAddrExprBase(), irMap.CreateAddrofMeExpr(*retIvar) }; - MeStmt *loadCall = CreateRCIntrinsic(INTRN_MCCLoadRef, ret, opnds, true); - ret.GetBB()->InsertMeStmtBefore(&ret, loadCall); - ret.SetOpnd(0, loadCall->GetMustDefList()->front().GetLHS()); - + if (MeOption::strictNaiveRC) { + RegMeExpr *curTmp = irMap.CreateRegMeExpr(PTY_ref); + RegassignMeStmt *regAssStmt = irMap.CreateRegassignMeStmt(*curTmp, *retIvar, *ret.GetBB()); + ret.GetBB()->InsertMeStmtBefore(&ret, regAssStmt); + std::vector opnds = { regAssStmt->GetRegLHS() }; + IntrinsiccallMeStmt *incCall = CreateRCIntrinsic(INTRN_MCCIncRef, *regAssStmt, opnds, true); + ret.GetBB()->InsertMeStmtBefore(&ret, incCall); + ret.SetOpnd(0, curTmp); + } else { + std::vector opnds = { &retIvar->GetBase()->GetAddrExprBase(), irMap.CreateAddrofMeExpr(*retIvar) }; + IntrinsiccallMeStmt *loadCall = CreateRCIntrinsic(INTRN_MCCLoadRef, ret, opnds, true); + ret.GetBB()->InsertMeStmtBefore(&ret, loadCall); + ret.SetOpnd(0, loadCall->GetMustDefList()->front().GetLHS()); + } } } @@ -844,6 +1102,10 @@ void RCLowering::HandleReturnStmt() { } void RCLowering::HandleArguments() { + // placementRC would have already addressed formals + if (func.GetHints() & kPlacementRCed) { + return; + } // handle arguments, if the formal gets modified // insert incref at entry and decref before all returns MIRFunction *mirFunc = func.GetMirFunc(); @@ -884,12 +1146,105 @@ void RCLowering::PostRCLower() { } void RCLowering::Finish() { + CheckRefs(); if (enabledDebug) { LogInfo::MapleLogger() << "\n============== After RC LOWERING =============" << '\n'; func.Dump(false); } } +void RCLowering::CheckRefs() { + ParseCheckFlag(); + if (checkRefFormal) { + CheckFormals(); + } + for (BB *bb : func.GetAllBBs()) { + if (bb == nullptr) { + continue; + } + if (checkRefAssign) { + CheckRefsInAssignStmt(*bb); + } + if (checkRefReturn) { + CheckRefReturn(*bb); + } + } +} + +void RCLowering::ParseCheckFlag() { + if (MeOption::checkRefUsedInFuncs.find(func.GetName()) != MeOption::checkRefUsedInFuncs.end() || + MeOption::checkRefUsedInFuncs.find("ALL") != MeOption::checkRefUsedInFuncs.end() || + MeOption::checkRefUsedInFuncs.find("*") != MeOption::checkRefUsedInFuncs.end()) { + checkRefFormal = true; + checkRefAssign = true; + checkRefReturn = true; + } else { + if (MeOption::checkRefUsedInFuncs.find("FORMAL") != MeOption::checkRefUsedInFuncs.end()) { + checkRefFormal = true; + } + if (MeOption::checkRefUsedInFuncs.find("ASSIGN") != MeOption::checkRefUsedInFuncs.end()) { + checkRefAssign = true; + } + if (MeOption::checkRefUsedInFuncs.find("RETURN") != MeOption::checkRefUsedInFuncs.end()) { + checkRefReturn = true; + } + } +} + +void RCLowering::CheckFormals() { + MIRFunction *mirFunc = func.GetMirFunc(); + BB *firstBB = func.GetFirstBB(); + if (firstBB->IsMeStmtEmpty()) { + return; + } + for (size_t i = 0; i < mirFunc->GetFormalCount(); ++i) { + MIRSymbol *sym = mirFunc->GetFormal(i); + if (sym == nullptr) { + continue; + } + if (sym->IgnoreRC()) { + continue; + } + MeStmt &firstMeStmt = firstBB->GetMeStmts().front(); + VarMeExpr *argVar = CreateVarMeExprFromSym(*sym); + std::vector exprs = { argVar, irMap.CreateIntConstMeExpr(++checkRCIndex, PTY_u32) }; + IntrinsiccallMeStmt *checkCall = CreateRCIntrinsic(INTRN_MCCCheck, firstMeStmt, exprs); + firstBB->InsertMeStmtBefore(&firstMeStmt, checkCall); + } +} + +void RCLowering::CheckRefsInAssignStmt(BB &bb) { + for (MeStmt &stmt : bb.GetMeStmts()) { + if (!stmt.IsAssign()) { + continue; + } + MeExpr *lhs = stmt.GetLHS(); + CHECK_NULL_FATAL(lhs); + if (lhs->GetPrimType() != PTY_ref && lhs->GetPrimType() != PTY_ptr) { + continue; + } + std::vector opnds = { lhs, irMap.CreateIntConstMeExpr(++checkRCIndex, PTY_u32) }; + IntrinsiccallMeStmt *checkCall = irMap.CreateIntrinsicCallMeStmt(INTRN_MCCCheck, opnds); + bb.InsertMeStmtAfter(&stmt, checkCall); + } +} + +void RCLowering::CheckRefReturn(BB &bb) { + if (bb.GetKind() != kBBReturn) { + return; + } + MeStmt *lastMeStmt = to_ptr(bb.GetMeStmts().rbegin()); + if (lastMeStmt == nullptr || lastMeStmt->GetOp() != OP_return || lastMeStmt->NumMeStmtOpnds() == 0) { + return; + } + MeExpr* ret = lastMeStmt->GetOpnd(0); + if (ret->GetPrimType() != PTY_ref && ret->GetPrimType() != PTY_ptr) { + return; + } + std::vector opnds = { ret }; + IntrinsiccallMeStmt *checkCall = irMap.CreateIntrinsicCallMeStmt(INTRN_MCCCheck, opnds); + bb.InsertMeStmtBefore(lastMeStmt, checkCall); +} static inline bool CheckIntrinsicID(MeStmt *stmt, MIRIntrinsicID id) { if (!CheckOp(stmt, OP_intrinsiccall)) { @@ -907,6 +1262,14 @@ static inline MeStmt *GetPrevMeStmt(const MeStmt &stmt) { return prevStmt; } +static inline MeStmt *GetNextMeStmt(const MeStmt &stmt) { + MeStmt *nextStmt = stmt.GetPrev(); + while (CheckOp(nextStmt, OP_comment)) { + nextStmt = nextStmt->GetNext(); + } + return nextStmt; +} + // iterate over stmts and find back-to-back incref/decref // and merge them into one intrinsic if needed void RCLowering::CompactRC(BB &bb) { @@ -923,6 +1286,27 @@ void RCLowering::CompactRC(BB &bb) { CompactIncAndDec(*prevStmt, stmt); } } + if ((func.GetHints() & kPlacementRCed) == 0) { + continue; + } + if (!CheckIntrinsicID(&stmt, INTRN_MCCDecRefReset)) { + continue; + } + MeStmt *prevStmt = GetPrevMeStmt(stmt); + if (CheckIntrinsicID(prevStmt, INTRN_MCCDecRefReset)) { + CompactAdjacentDecReset(*prevStmt, stmt); + } + if (CheckOp(prevStmt, OP_dassign)) { + ReplaceDecResetWithDec(*prevStmt, stmt); + } + if (CheckIntrinsicID(prevStmt, INTRN_MCCIncRef)) { + CompactIncAndDecReset(*prevStmt, stmt); + } else { + MeStmt *nextStmt = GetNextMeStmt(stmt); + if (CheckIntrinsicID(nextStmt, INTRN_MCCIncRef)) { + CompactIncAndDecReset(*nextStmt, stmt); + } + } } } @@ -1010,16 +1394,260 @@ VarMeExpr *RCLowering::CreateNewTmpVarMeExpr(bool isLocalRefVar) { return varMeExpr; } +// Fast path: Special RC handling for simple methods +// where local ref assignments can be ignored +// functions with global write cannot use fast path +void RCLowering::FastBBLower(BB &bb) { + MapleMap exceptionAllocsites(func.GetAlloc().Adapter()); + for (auto &stmt : bb.GetMeStmts()) { + if (CheckOp(&stmt, OP_incref) || CheckOp(&stmt, OP_decref) || + CheckIntrinsicID(&stmt, INTRN_MPL_CLEANUP_LOCALREFVARS)) { + // ignore RC operations inserted by analyzerc + bb.RemoveMeStmt(&stmt); + }else if (CheckOp(&stmt, OP_throw)) { + FastLowerThrowStmt(stmt, exceptionAllocsites); + }else if (CheckOp(&stmt, OP_return)) { + FastLowerRetStmt(stmt); + }else if (stmt.IsAssign()) { + MeExpr *lhs = stmt.GetLHSRef(false); + if (lhs == nullptr) { + continue; + } + if (lhs->GetMeOp() == kMeOpVar) { + FastLowerAssignToVar(stmt, exceptionAllocsites); + } else if (lhs->GetMeOp() == kMeOpIvar) { + FastLowerAssignToIvar(stmt); + } + }else if (kOpcodeInfo.IsCallAssigned(stmt.GetOp())) { + MIRType *retType = stmt.GetReturnType(); + if (retType != nullptr && retType->GetPrimType() == PTY_ref) { + FastLowerCallAssignedStmt(stmt); + } + } + } + + for (auto iter : exceptionAllocsites) { + MeStmt *stmt = iter.second; + DassignMeStmt *backup = irMap.CreateDassignMeStmt(*CreateNewTmpVarMeExpr(true), *stmt->GetLHS(), *stmt->GetBB()); + stmt->GetBB()->InsertMeStmtAfter(stmt, backup); + } +} + +void RCLowering::FastLowerThrowStmt(MeStmt &stmt, MapleMap &exceptionAllocsites) { + auto &throwMeStmt = static_cast(stmt); + // insert localrefvar for decref on throw arg + MeExpr *throwVal = throwMeStmt.GetOpnd(); + BB *bb = stmt.GetBB(); + CHECK_FATAL(bb != nullptr, "bb nullptr check"); + DassignMeStmt *backup = irMap.CreateDassignMeStmt(*CreateNewTmpVarMeExpr(true), *throwVal, *bb); + bb->InsertMeStmtBefore(&throwMeStmt, backup); + if (throwVal->GetMeOp() == kMeOpVar) { + auto *var = static_cast(throwVal); + MapleMap::iterator iter; + iter = exceptionAllocsites.find(var->GetVstIdx()); + if (iter != exceptionAllocsites.end()) { + exceptionAllocsites.erase(iter); + } + } +} + +void RCLowering::FastLowerRetStmt(MeStmt &stmt) { + auto &retMeStmt = static_cast(stmt); + const MapleVector &opnds = retMeStmt.GetOpnds(); + if (opnds.empty()) { + // function return void + return; + } + MeExpr *ret = opnds[0]; + PrimType retPtyp = ret->GetPrimType(); + if (retPtyp != PTY_ref) { + return; + } + if (ret->GetMeOp() == kMeOpVar) { + FastLowerRetVar(retMeStmt); + } else if (ret->GetMeOp() == kMeOpReg) { + FastLowerRetReg(retMeStmt); + } else { + // ret->GetMeOp() == kMeOpIvar etc + // return ivar, put into temp and IncRef + FastLowerRetIvar(retMeStmt); + } +} + +void RCLowering::FastLowerRetVar(RetMeStmt &stmt) { + auto *val = static_cast(stmt.GetOpnd(0)); + const MIRSymbol *sym = val->GetOst()->GetMIRSymbol(); + if (val->GetDefBy() == kDefByStmt && CheckOp(val->GetDefStmt(), OP_dassign)) { + // gcmalloc already has incref + ASSERT_NOT_NULL(val->GetDefStmt()->GetRHS()); + Opcode op = val->GetDefStmt()->GetRHS()->GetOp(); + if (op == OP_gcmalloc || op == OP_gcmallocjarray) { + return; + } + } + if (sym != nullptr && !sym->IgnoreRC()) { + std::vector opnds = { val }; + IntrinsiccallMeStmt *incCall = CreateRCIntrinsic(INTRN_MCCIncRef, stmt, opnds, true); + stmt.SetOpnd(0, incCall->GetMustDefList()->front().GetLHS()); + stmt.GetBB()->InsertMeStmtBefore(&stmt, incCall); + } +} + +void RCLowering::FastLowerRetIvar(RetMeStmt &stmt) { + BB *bb = stmt.GetBB(); + CHECK_NULL_FATAL(bb); + RegassignMeStmt *tmpRet = irMap.CreateRegassignMeStmt(*irMap.CreateRegMeExpr(PTY_ref), *stmt.GetOpnd(0), *bb); + bb->InsertMeStmtBefore(&stmt, tmpRet); + std::vector opnds = { tmpRet->GetRegLHS() }; + IntrinsiccallMeStmt *incCall = CreateRCIntrinsic(INTRN_MCCIncRef, stmt, opnds); + bb->InsertMeStmtBefore(&stmt, incCall); + stmt.SetOpnd(0, tmpRet->GetRegLHS()); +} + +void RCLowering::FastLowerRetReg(RetMeStmt &stmt) { + auto *regRet = static_cast(stmt.GetOpnd(0)); + if (regRet->GetDefBy() == kDefByStmt && CheckOp(regRet->GetDefStmt(), OP_regassign)) { + MeExpr *rhs = regRet->GetDefStmt()->GetRHS(); + ASSERT_NOT_NULL(rhs); + if (rhs->GetOp() == OP_gcmalloc || rhs->GetOp() == OP_gcmallocjarray) { + return; + } + } + std::vector opnds = { regRet }; + IntrinsiccallMeStmt *incCall = CreateRCIntrinsic(INTRN_MCCIncRef, stmt, opnds); + stmt.GetBB()->InsertMeStmtBefore(&stmt, incCall); +} + +void RCLowering::FastLowerAssignToVar(MeStmt &stmt, MapleMap &exceptionAllocsites) { + VarMeExpr *lhs = stmt.GetVarLHS(); + ASSERT_NOT_NULL(lhs); + if (stmt.NeedIncref() || stmt.NeedDecref()) { + const MIRSymbol *lSym = lhs->GetOst()->GetMIRSymbol(); + if (lSym->IgnoreRC()) { + return; + } + ASSERT(!lSym->IsGlobal(), "Write to global not expected"); + } + if (stmt.GetOp() != OP_dassign) { + return; + } + ASSERT_NOT_NULL(stmt.GetRHS()); + if (!(stmt.GetRHS()->IsGcmalloc())) { + return; + } + auto *rhs = static_cast(stmt.GetRHS()); + MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(rhs->GetTyIdx()); + Klass *klass = klassHierarchy.GetKlassFromStrIdx(type->GetNameStrIdx()); + CHECK_FATAL(klass != nullptr, "null ptr check"); + if (klass->IsExceptionKlass()) { + exceptionAllocsites[lhs->GetVstIdx()] = &stmt; + } else { + // add a localrefvar temp to compensate incref with new object + BB *bb = stmt.GetBB(); + CHECK_FATAL(bb != nullptr, "bb nullptr check"); + DassignMeStmt *backup = irMap.CreateDassignMeStmt(*CreateNewTmpVarMeExpr(true), *lhs, *bb); + bb->InsertMeStmtAfter(&stmt, backup); + } +} + +void RCLowering::FastLowerAssignToIvar(MeStmt &stmt) { + // only handle lhs + MeExpr *rhs = stmt.GetRHS(); + ASSERT_NOT_NULL(rhs); + bool incWithLHS = stmt.NeedIncref(); + bool decWithLHS = stmt.NeedDecref(); + if (!incWithLHS && (rhs->GetOp() == OP_regread)) { + // check for regread + auto *rhsVar = static_cast(rhs); + if (rhsVar->GetDefBy() == kDefByStmt) { + incWithLHS = rhsVar->GetDefStmt()->NeedIncref(); + } else { + // callassign is fine as IncRef has been done inside call, just skip + ASSERT(rhsVar->GetDefBy() == kDefByMustDef, "not supported yet"); + } + } + if (!incWithLHS && !decWithLHS) { + return; + } + HandleAssignMeStmtRHS(stmt); + rhs = stmt.GetRHS(); + IvarMeExpr *lhs = (static_cast(stmt)).GetLHSVal(); + BB *bb = stmt.GetBB(); + CHECK_FATAL(bb != nullptr, "bb nullptr check"); + if (lhs->IsVolatile()) { + CheckRemove(stmt.GetPrev(), OP_membarrelease); + CheckRemove(stmt.GetNext(), OP_membarstoreload); + } + std::vector opnds = { &lhs->GetBase()->GetAddrExprBase(), irMap.CreateAddrofMeExpr(*lhs), rhs }; + IntrinsiccallMeStmt *writeRefCall = CreateRCIntrinsic(SelectWriteBarrier(stmt), stmt, opnds); + bb->ReplaceMeStmt(&stmt, writeRefCall); + CheckArrayStore(*writeRefCall); +} + +void RCLowering::FastLowerCallAssignedStmt(MeStmt &stmt) { + MapleVector *mustDefs = stmt.GetMustDefList(); + ASSERT_NOT_NULL(mustDefs); + + BB *bb = stmt.GetBB(); + CHECK_FATAL(bb != nullptr, "bb null ptr check"); + if (mustDefs->empty()) { + // introduce a ret and decref on it + RegMeExpr *curTmp = irMap.CreateRegMeExpr(PTY_ref); + ASSERT_NOT_NULL(stmt.GetMustDefList()); + stmt.GetMustDefList()->push_back(MustDefMeNode(curTmp, &stmt)); + std::vector opnds = { curTmp }; + IntrinsiccallMeStmt *decRefCall = CreateRCIntrinsic(INTRN_MCCDecRef, stmt, opnds); + bb->InsertMeStmtAfter(&stmt, decRefCall); + } else { + CHECK_FATAL(mustDefs->size() == 1, "return val count check"); + MeExpr *lhs = mustDefs->front().GetLHS(); + if (lhs->GetMeOp() != kMeOpVar) { + return; + } + const OriginalSt *ost = static_cast(lhs)->GetOst(); + if (!ost->IsSymbolOst()) { + return; + } + const MIRSymbol *retSym = ost->GetMIRSymbol(); + // if retSym is null, that means we do not need decref + // to offset the incref before function return, just break + if (retSym == nullptr || retSym->IgnoreRC()) { + return; + } + // insert localrefvar for decref on ret + DassignMeStmt *backup = irMap.CreateDassignMeStmt(*CreateNewTmpVarMeExpr(true), *lhs, *bb); + bb->InsertMeStmtAfter(&stmt, backup); + } +} + AnalysisResult *MeDoRCLowering::Run(MeFunction *func, MeFuncResultMgr *funcResMgr, ModuleResultMgr *moduleResMgr) { + auto *kh = static_cast(moduleResMgr->GetAnalysisResult(MoPhase_CHA, &func->GetMIRModule())); + ASSERT_NOT_NULL(kh); if (func->GetIRMap() == nullptr) { auto *hmap = static_cast(funcResMgr->GetAnalysisResult(MeFuncPhase_IRMAPBUILD, func)); CHECK_FATAL(hmap != nullptr, "hssamap has problem"); func->SetIRMap(hmap); } CHECK_FATAL(func->GetMeSSATab() != nullptr, "ssatab has problem"); - RCLowering rcLowering(*func, DEBUGFUNC(func)); + RCLowering rcLowering(*func, *kh, DEBUGFUNC(func)); rcLowering.Prepare(); + if (!rcLowering.GetIsAnalyzed()) { + auto *dom = static_cast(funcResMgr->GetAnalysisResult(MeFuncPhase_DOMINANCE, func)); + CHECK_FATAL(dom != nullptr, "dominance phase has problem"); + rcLowering.SetDominance(*dom); + } + MIRFunction *mirFunction = func->GetMirFunc(); + if (whiteListFunc.find(mirFunction->GetName()) != whiteListFunc.end() || + mirFunction->GetAttr(FUNCATTR_rclocalunowned)) { + auto eIt = func->valid_end(); + for (auto bIt = func->valid_begin(); bIt != eIt; ++bIt) { + auto *bb = *bIt; + rcLowering.FastBBLower(*bb); + } + rcLowering.Finish(); + return nullptr; + } rcLowering.PreRCLower(); rcLowering.RCLower(); // handle all the extra RC work diff --git a/src/mapleall/maple_me/src/me_scalar_analysis.cpp b/src/mapleall/maple_me/src/me_scalar_analysis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..10986995afa8e9d93b8c88de067dd717e25b121c --- /dev/null +++ b/src/mapleall/maple_me/src/me_scalar_analysis.cpp @@ -0,0 +1,1109 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "me_scalar_analysis.h" +#include +#include +#include "me_loop_analysis.h" + +namespace maple { +bool LoopScalarAnalysisResult::enableDebug = false; +constexpr int kNumOpnds = 2; + +CRNode *CR::GetPolynomialsValueAtITerm(CRNode &iterCRNode, size_t num, LoopScalarAnalysisResult &scalarAnalysis) const { + if (num == 1) { + return &iterCRNode; + } + // BC(It, K) = (It * (It - 1) * ... * (It - K + 1)) / K!; + size_t factorialOfNum = 1; + // compute K! + for (size_t i = 2; i <= num; ++i) { + factorialOfNum *= i; + } + CRConstNode factorialOfNumCRNode = CRConstNode(nullptr, factorialOfNum); + CRNode *result = &iterCRNode; + for (size_t i = 1; i != num; ++i) { + std::vector crAddNodes; + crAddNodes.push_back(&iterCRNode); + CRConstNode constNode = CRConstNode(nullptr, i); + CRNode *negetive2Mul = scalarAnalysis.ChangeNegative2MulCRNode(*static_cast(&constNode)); + crAddNodes.push_back(negetive2Mul); + CRNode *addResult = scalarAnalysis.GetCRAddNode(nullptr, crAddNodes); + std::vector crMulNodes; + crMulNodes.push_back(result); + crMulNodes.push_back(addResult); + result = scalarAnalysis.GetCRMulNode(nullptr, crMulNodes); + } + return scalarAnalysis.GetOrCreateCRDivNode(nullptr, *result, *static_cast(&factorialOfNumCRNode)); +} + +CRNode *CR::ComputeValueAtIteration(uint32 i, LoopScalarAnalysisResult &scalarAnalysis) const { + CRConstNode iterCRNode(nullptr, i); + CRNode *result = opnds[0]; + CRNode *subResult = nullptr; + for (size_t j = 1; j < opnds.size(); ++j) { + subResult = GetPolynomialsValueAtITerm(iterCRNode, j, scalarAnalysis); + CHECK_NULL_FATAL(subResult); + std::vector crMulNodes; + crMulNodes.push_back(opnds[j]); + crMulNodes.push_back(subResult); + CRNode *mulResult = scalarAnalysis.GetCRMulNode(nullptr, crMulNodes); + std::vector crAddNodes; + crAddNodes.push_back(result); + crAddNodes.push_back(mulResult); + result = scalarAnalysis.GetCRAddNode(nullptr, crAddNodes); + } + return result; +} + +MeExpr *LoopScalarAnalysisResult::TryToResolveVar(MeExpr &expr, std::set &visitedPhi, + MeExpr &dummyExpr) { + CHECK_FATAL(expr.GetMeOp() == kMeOpVar, "must be"); + auto *var = static_cast(&expr); + if (var->GetDefBy() == kDefByStmt && !var->GetDefStmt()->GetRHS()->IsLeaf()) { + return nullptr; + } + if (var->GetDefBy() == kDefByStmt && var->GetDefStmt()->GetRHS()->GetMeOp() == kMeOpConst) { + return var->GetDefStmt()->GetRHS(); + } + if (var->GetDefBy() == kDefByStmt) { + CHECK_FATAL(var->GetDefStmt()->GetRHS()->GetMeOp() == kMeOpVar, "must be"); + return TryToResolveVar(*(var->GetDefStmt()->GetRHS()), visitedPhi, dummyExpr); + } + + if (var->GetDefBy() == kDefByPhi) { + MePhiNode *phi = &(var->GetDefPhi()); + if (visitedPhi.find(phi) != visitedPhi.end()) { + return &dummyExpr; + } + visitedPhi.insert(phi); + std::set constRes; + for (auto *phiOpnd : phi->GetOpnds()) { + MeExpr *tmp = TryToResolveVar(*phiOpnd, visitedPhi, dummyExpr); + if (tmp == nullptr) { + return nullptr; + } + if (tmp != &dummyExpr) { + constRes.insert(tmp); + } + } + if (constRes.size() == 1) { + return *(constRes.begin()); + } else { + return nullptr; + } + } + return nullptr; +} + +void LoopScalarAnalysisResult::VerifyCR(const CRNode &crNode) { + constexpr uint32 verifyTimes = 10; // Compute top ten iterations result of crNode. + for (uint32 i = 0; i < verifyTimes; ++i) { + if (crNode.GetCRType() != kCRNode) { + continue; + } + const CRNode *r = static_cast(&crNode)->ComputeValueAtIteration(i, *this); + if (r->GetCRType() == kCRConstNode) { + std::cout << static_cast(r)->GetConstValue() << std::endl; + } + } +} + + +void LoopScalarAnalysisResult::Dump(const CRNode &crNode) { + switch (crNode.GetCRType()) { + case kCRConstNode: { + LogInfo::MapleLogger() << static_cast(&crNode)->GetConstValue(); + return; + } + case kCRVarNode: { + CHECK_FATAL(crNode.GetExpr() != nullptr, "crNode must has expr"); + const MeExpr *meExpr = crNode.GetExpr(); + const VarMeExpr *varMeExpr = nullptr; + std::string name; + if (meExpr->GetMeOp() == kMeOpVar) { + varMeExpr = static_cast(meExpr); + } else if (meExpr->GetMeOp() == kMeOpIvar) { + const auto *ivarMeExpr = static_cast(meExpr); + const MeExpr *base = ivarMeExpr->GetBase(); + if (base->GetMeOp() == kMeOpVar) { + varMeExpr = static_cast(base); + } else { + name = "ivar" + std::to_string(ivarMeExpr->GetExprID()); + LogInfo::MapleLogger() << name; + return; + } + } + MIRSymbol *sym = irMap->GetSSATab().GetMIRSymbolFromID(varMeExpr->GetOstIdx()); + name = sym->GetName() + "_mx" + std::to_string(meExpr->GetExprID()); + LogInfo::MapleLogger() << name; + return; + } + case kCRAddNode: { + const CRAddNode *crAddNode = static_cast(&crNode); + CHECK_FATAL(crAddNode->GetOpndsSize() > 1, "crAddNode must has more than one opnd"); + Dump(*crAddNode->GetOpnd(0)); + for (size_t i = 1; i < crAddNode->GetOpndsSize(); ++i) { + LogInfo::MapleLogger() << " + "; + Dump(*crAddNode->GetOpnd(i)); + } + return; + } + case kCRMulNode: { + const CRMulNode *crMulNode = static_cast(&crNode); + CHECK_FATAL(crMulNode->GetOpndsSize() > 1, "crMulNode must has more than one opnd"); + if (crMulNode->GetOpnd(0)->GetCRType() != kCRConstNode && crMulNode->GetOpnd(0)->GetCRType() != kCRVarNode) { + LogInfo::MapleLogger() << "("; + Dump(*crMulNode->GetOpnd(0)); + LogInfo::MapleLogger() << ")"; + } else { + Dump(*crMulNode->GetOpnd(0)); + } + + for (size_t i = 1; i < crMulNode->GetOpndsSize(); ++i) { + LogInfo::MapleLogger() << " * "; + if (crMulNode->GetOpnd(i)->GetCRType() != kCRConstNode && crMulNode->GetOpnd(i)->GetCRType() != kCRVarNode) { + LogInfo::MapleLogger() << "("; + Dump(*crMulNode->GetOpnd(i)); + LogInfo::MapleLogger() << ")"; + } else { + Dump(*crMulNode->GetOpnd(i)); + } + } + return; + } + case kCRDivNode: { + const CRDivNode *crDivNode = static_cast(&crNode); + if (crDivNode->GetLHS()->GetCRType() != kCRConstNode && crDivNode->GetLHS()->GetCRType() != kCRVarNode) { + LogInfo::MapleLogger() << "("; + Dump(*crDivNode->GetLHS()); + LogInfo::MapleLogger() << ")"; + } else { + Dump(*crDivNode->GetLHS()); + } + LogInfo::MapleLogger() << " / "; + if (crDivNode->GetRHS()->GetCRType() != kCRConstNode && crDivNode->GetRHS()->GetCRType() != kCRVarNode) { + LogInfo::MapleLogger() << "("; + Dump(*crDivNode->GetRHS()); + LogInfo::MapleLogger() << ")"; + } else { + Dump(*crDivNode->GetRHS()); + } + return; + } + case kCRNode: { + const CR *cr = static_cast(&crNode); + CHECK_FATAL(cr->GetOpndsSize() > 1, "cr must has more than one opnd"); + LogInfo::MapleLogger() << "{"; + Dump(*cr->GetOpnd(0)); + for (size_t i = 1; i < cr->GetOpndsSize(); ++i) { + LogInfo::MapleLogger() << ", + ,"; + Dump(*cr->GetOpnd(i)); + } + LogInfo::MapleLogger() << "}"; + return; + } + default: + LogInfo::MapleLogger() << crNode.GetExpr()->GetExprID() << "@@@" << crNode.GetCRType(); + CHECK_FATAL(false, "can not support"); + } +} + +CRNode *LoopScalarAnalysisResult::GetOrCreateCRConstNode(MeExpr *expr, int32 value) { + if (expr == nullptr) { + std::unique_ptr constNode = std::make_unique(nullptr, value); + CRConstNode *constPtr = constNode.get(); + allCRNodes.insert(std::move(constNode)); + return constPtr; + } + auto it = expr2CR.find(expr); + if (it != expr2CR.end()) { + return it->second; + } + + std::unique_ptr constNode = std::make_unique(expr, value); + CRConstNode *constPtr = constNode.get(); + allCRNodes.insert(std::move(constNode)); + InsertExpr2CR(*expr, constPtr); + return constPtr; +} + +CRNode *LoopScalarAnalysisResult::GetOrCreateCRVarNode(MeExpr &expr) { + auto it = expr2CR.find(&expr); + if (it != expr2CR.end()) { + return it->second; + } + + std::unique_ptr varNode = std::make_unique(&expr); + CRVarNode *varPtr = varNode.get(); + allCRNodes.insert(std::move(varNode)); + InsertExpr2CR(expr, varPtr); + return varPtr; +} + +CRNode *LoopScalarAnalysisResult::GetOrCreateLoopInvariantCR(MeExpr &expr) { + if (expr.GetMeOp() == kMeOpConst && static_cast(expr).GetConstVal()->GetKind() == kConstInt) { + return GetOrCreateCRConstNode(&expr, static_cast(static_cast(expr).GetIntValue())); + } + if (expr.GetMeOp() == kMeOpVar) { + // Try to resolve Var is assigned from Const + MeExpr *varExpr = &expr; + std::set visitedPhi; + ConstMeExpr dummyExpr(kInvalidExprID, nullptr, PTY_unknown); + varExpr = TryToResolveVar(*varExpr, visitedPhi, dummyExpr); + if (varExpr != nullptr && varExpr != &dummyExpr) { + CHECK_FATAL(varExpr->GetMeOp() == kMeOpConst, "must be"); + return GetOrCreateCRConstNode(&expr, static_cast(static_cast(varExpr)->GetIntValue())); + } + return GetOrCreateCRVarNode(expr); + } + if (expr.GetMeOp() == kMeOpIvar) { + return GetOrCreateCRVarNode(expr); + } + CHECK_FATAL(false, "only support kMeOpConst, kMeOpVar, kMeOpIvar"); + return nullptr; +} + +CRNode* LoopScalarAnalysisResult::GetOrCreateCRAddNode(MeExpr *expr, std::vector &crAddNodes) { + if (expr == nullptr) { + std::unique_ptr crAdd = std::make_unique(nullptr); + CRAddNode *crPtr = crAdd.get(); + allCRNodes.insert(std::move(crAdd)); + crPtr->SetOpnds(crAddNodes); + return crPtr; + } + auto it = expr2CR.find(expr); + if (it != expr2CR.end()) { + return it->second; + } + std::unique_ptr crAdd = std::make_unique(expr); + CRAddNode *crAddPtr = crAdd.get(); + allCRNodes.insert(std::move(crAdd)); + crAddPtr->SetOpnds(crAddNodes); + // can not insert crAddNode to expr2CR map + return crAddPtr; +} + +CRNode *LoopScalarAnalysisResult::GetOrCreateCR(MeExpr &expr, CRNode &start, CRNode &stride) { + auto it = expr2CR.find(&expr); + if (it != expr2CR.end() && (it->second == nullptr || it->second->GetCRType() != kCRUnKnown)) { + return it->second; + } + std::unique_ptr cr = std::make_unique(&expr); + CR *crPtr = cr.get(); + allCRNodes.insert(std::move(cr)); + InsertExpr2CR(expr, crPtr); + crPtr->PushOpnds(start); + if (stride.GetCRType() == kCRNode) { + crPtr->InsertOpnds(static_cast(&stride)->GetOpnds().begin(), static_cast(&stride)->GetOpnds().end()); + return crPtr; + } + crPtr->PushOpnds(stride); + return crPtr; +} + +CRNode *LoopScalarAnalysisResult::GetOrCreateCR(MeExpr *expr, std::vector &crNodes) { + auto it = expr2CR.find(expr); + if (it != expr2CR.end()) { + return it->second; + } + std::unique_ptr cr = std::make_unique(expr); + CR *crPtr = cr.get(); + allCRNodes.insert(std::move(cr)); + crPtr->SetOpnds(crNodes); + if (expr != nullptr) { + InsertExpr2CR(*expr, crPtr); + } + return crPtr; +} + +CRNode *LoopScalarAnalysisResult::GetCRAddNode(MeExpr *expr, std::vector &crAddOpnds) { + if (crAddOpnds.size() == 1) { + return crAddOpnds[0]; + } + std::sort(crAddOpnds.begin(), crAddOpnds.end(), CompareCRNode()); + // merge constCRNode + // 1 + 2 + 3 + X -> 6 + X + size_t index = 0; + if (crAddOpnds[0]->GetCRType() == kCRConstNode) { + CRConstNode *constLHS = static_cast(crAddOpnds[0]); + ++index; + while (index < crAddOpnds.size() && crAddOpnds[index]->GetCRType() == kCRConstNode) { + CRConstNode *constRHS = static_cast(crAddOpnds[index]); + crAddOpnds[0] = GetOrCreateCRConstNode(nullptr, constLHS->GetConstValue() + constRHS->GetConstValue()); + if (crAddOpnds.size() == kNumOpnds) { + return crAddOpnds[0]; + } + crAddOpnds.erase(crAddOpnds.begin() + 1); + constLHS = static_cast(crAddOpnds[0]); + } + // After merge constCRNode, if crAddOpnds[0] is 0, delete it from crAddOpnds vector + // 0 + X -> X + if (constLHS->GetConstValue() == 0) { + crAddOpnds.erase(crAddOpnds.begin()); + --index; + } + if (crAddOpnds.size() == 1) { + return crAddOpnds[0]; + } + } + + // if the crType of operand is CRAddNode, unfold the operand + // 1 + (X + Y) -> 1 + X + Y + size_t addCRIndex = index; + while (addCRIndex < crAddOpnds.size() && crAddOpnds[addCRIndex]->GetCRType() != kCRAddNode) { + ++addCRIndex; + } + if (addCRIndex < crAddOpnds.size()) { + while (crAddOpnds[addCRIndex]->GetCRType() == kCRAddNode) { + crAddOpnds.insert(crAddOpnds.end(), + static_cast(crAddOpnds[addCRIndex])->GetOpnds().begin(), + static_cast(crAddOpnds[addCRIndex])->GetOpnds().end()); + crAddOpnds.erase(crAddOpnds.begin() + addCRIndex); + } + return GetCRAddNode(expr, crAddOpnds); + } + + // merge cr + size_t crIndex = index; + while (crIndex < crAddOpnds.size() && crAddOpnds[crIndex]->GetCRType() != kCRNode) { + ++crIndex; + } + if (crIndex < crAddOpnds.size()) { + // X + { Y, + , Z } -> { X + Y, + , Z } + if (crIndex != 0) { + std::vector startOpnds(crAddOpnds.begin(), crAddOpnds.begin() + crIndex); + crAddOpnds.erase(crAddOpnds.begin(), crAddOpnds.begin() + crIndex); + startOpnds.push_back(static_cast(crAddOpnds[crIndex])->GetOpnd(0)); + CRNode *start = GetCRAddNode(nullptr, startOpnds); + std::vector newCROpnds{ start }; + newCROpnds.insert(newCROpnds.end(), static_cast(crAddOpnds[crIndex])->GetOpnds().begin() + 1, + static_cast(crAddOpnds[crIndex])->GetOpnds().end()); + CR *newCR = static_cast(GetOrCreateCR(expr, newCROpnds)); + if (crAddOpnds.size() == 1) { + return static_cast(newCR); + } + crAddOpnds[0] = static_cast(newCR); + crIndex = 0; + } + // { X1 , + , Y1, + , ... , + , Z1 } + { X2 , + , Y2, + , ... , + , Z2 } + // -> + // { X1 + X2, + , Y1 + Y2, + , ... , + , Z1 + Z2 } + ++crIndex; + CR *crLHS = static_cast(crAddOpnds[0]); + while (crIndex < crAddOpnds.size() && crAddOpnds[crIndex]->GetCRType() == kCRNode) { + CR *crRHS = static_cast(crAddOpnds[crIndex]); + crAddOpnds[0] = static_cast(AddCRWithCR(*crLHS, *crRHS)); + if (crAddOpnds.size() == kNumOpnds) { + return crAddOpnds[0]; + } + crAddOpnds.erase(crAddOpnds.begin() + 1); + crLHS = static_cast(crAddOpnds[0]); + } + if (crAddOpnds.size() == 1) { + return crAddOpnds[0]; + } + } + return GetOrCreateCRAddNode(expr, crAddOpnds); +} + +CRNode *LoopScalarAnalysisResult::GetCRMulNode(MeExpr *expr, std::vector &crMulOpnds) { + if (crMulOpnds.size() == 1) { + return crMulOpnds[0]; + } + std::sort(crMulOpnds.begin(), crMulOpnds.end(), CompareCRNode()); + // merge constCRNode + // 1 * 2 * 3 * X -> 6 * X + size_t index = 0; + if (crMulOpnds[0]->GetCRType() == kCRConstNode) { + CRConstNode *constLHS = static_cast(crMulOpnds[0]); + ++index; + while (index < crMulOpnds.size() && crMulOpnds[index]->GetCRType() == kCRConstNode) { + CRConstNode *constRHS = static_cast(crMulOpnds[index]); + crMulOpnds[0] = GetOrCreateCRConstNode(nullptr, constLHS->GetConstValue() * constRHS->GetConstValue()); + if (crMulOpnds.size() == kNumOpnds) { + return crMulOpnds[0]; + } + crMulOpnds.erase(crMulOpnds.begin() + 1); + constLHS = static_cast(crMulOpnds[0]); + } + // After merge constCRNode, if crMulOpnds[0] is 1, delete it from crMulOpnds vector + // 1 * X -> X + if (constLHS->GetConstValue() == 1) { + crMulOpnds.erase(crMulOpnds.begin()); + --index; + } + // After merge constCRNode, if crMulOpnds[0] is 0, return crMulOpnds[0] + // 0 * X -> 0 + if (constLHS->GetConstValue() == 0) { + return crMulOpnds[0]; + } + if (crMulOpnds.size() == 1) { + return crMulOpnds[0]; + } + } + + // if the crType of operand is CRAddNode, unfold the operand + // 2 * (X * Y) -> 2 * X * Y + size_t mulCRIndex = index; + while (mulCRIndex < crMulOpnds.size() && crMulOpnds[mulCRIndex]->GetCRType() != kCRMulNode) { + ++mulCRIndex; + } + if (mulCRIndex < crMulOpnds.size()) { + while (crMulOpnds[mulCRIndex]->GetCRType() == kCRMulNode) { + crMulOpnds.insert(crMulOpnds.end(), + static_cast(crMulOpnds[mulCRIndex])->GetOpnds().begin(), + static_cast(crMulOpnds[mulCRIndex])->GetOpnds().end()); + crMulOpnds.erase(crMulOpnds.begin() + mulCRIndex); + } + return GetCRMulNode(expr, crMulOpnds); + } + + // merge cr + size_t crIndex = index; + while (crIndex < crMulOpnds.size() && crMulOpnds[crIndex]->GetCRType() != kCRNode) { + ++crIndex; + } + if (crIndex < crMulOpnds.size()) { + // X * { Y, + , Z } -> { X * Y, + , X * Z } + if (crIndex != 0) { + std::vector newCROpnds; + CR *currCR = static_cast(crMulOpnds[crIndex]); + std::vector crOpnds(crMulOpnds.begin(), crMulOpnds.begin() + crIndex); + crMulOpnds.erase(crMulOpnds.begin(), crMulOpnds.begin() + crIndex); + for (size_t i = 0; i < currCR->GetOpndsSize(); ++i) { + std::vector currOpnds(crOpnds); + currOpnds.push_back(currCR->GetOpnd(i)); + CRNode *start = GetCRMulNode(nullptr, currOpnds); + newCROpnds.push_back(start); + } + CR *newCR = static_cast(GetOrCreateCR(expr, newCROpnds)); + if (crMulOpnds.size() == 1) { + return static_cast(newCR); + } + crMulOpnds[0] = static_cast(newCR); + crIndex = 0; + } + // { X1 , + , Y1, + , ... , + , Z1 } * { X2 , + , Y2, + , ... , + , Z2 } + // -> + // { X1 + X2, + , Y1 + Y2, + , ... , + , Z1 + Z2 } + ++crIndex; + CR *crLHS = static_cast(crMulOpnds[0]); + while (crIndex < crMulOpnds.size() && crMulOpnds[crIndex]->GetCRType() == kCRNode) { + CR *crRHS = static_cast(crMulOpnds[crIndex]); + crMulOpnds[0] = static_cast(MulCRWithCR(*crLHS, *crRHS)); + if (crMulOpnds.size() == kNumOpnds) { + return crMulOpnds[0]; + } + crMulOpnds.erase(crMulOpnds.begin() + 1); + crLHS = static_cast(crMulOpnds[0]); + } + if (crMulOpnds.size() == 1) { + return crMulOpnds[0]; + } + } + return GetOrCreateCRMulNode(expr, crMulOpnds); +} + +CRNode *LoopScalarAnalysisResult::GetOrCreateCRMulNode(MeExpr *expr, std::vector &crMulNodes) { + std::unique_ptr crMul = std::make_unique(expr); + CRMulNode *crMulPtr = crMul.get(); + allCRNodes.insert(std::move(crMul)); + crMulPtr->SetOpnds(crMulNodes); + return crMulPtr; +} + +CRNode *LoopScalarAnalysisResult::GetOrCreateCRDivNode(MeExpr *expr, CRNode &lhsCRNode, CRNode &rhsCRNode) { + if (lhsCRNode.GetCRType() == kCRConstNode && rhsCRNode.GetCRType() == kCRConstNode) { + CRConstNode *lhsConst = static_cast(&lhsCRNode); + CRConstNode *rhsConst = static_cast(&rhsCRNode); + CHECK_FATAL(rhsConst->GetConstValue() != 0, "rhs is zero"); + if (lhsConst->GetConstValue() % rhsConst->GetConstValue() == 0) { + std::unique_ptr constNode = + std::make_unique(expr, lhsConst->GetConstValue() / rhsConst->GetConstValue()); + CRConstNode *constPtr = constNode.get(); + allCRNodes.insert(std::move(constNode)); + return constPtr; + } + } + std::unique_ptr divNode = std::make_unique(expr, lhsCRNode, rhsCRNode); + CRDivNode *divPtr = divNode.get(); + allCRNodes.insert(std::move(divNode)); + return divPtr; +} + +// -expr => -1 * expr +CRNode *LoopScalarAnalysisResult::ChangeNegative2MulCRNode(CRNode &crNode) { + std::unique_ptr constNode = std::make_unique(nullptr, -1); + CRConstNode *constPtr = constNode.get(); + allCRNodes.insert(std::move(constNode)); + std::vector crMulNodes; + crMulNodes.push_back(constPtr); + crMulNodes.push_back(&crNode); + return GetCRMulNode(nullptr, crMulNodes); +} + + +CR *LoopScalarAnalysisResult::AddCRWithCR(CR &lhsCR, CR &rhsCR) { + std::unique_ptr cr = std::make_unique(nullptr); + CR *crPtr = cr.get(); + allCRNodes.insert(std::move(cr)); + size_t len = lhsCR.GetOpndsSize() < rhsCR.GetOpndsSize() ? lhsCR.GetOpndsSize() : rhsCR.GetOpndsSize(); + std::vector crOpnds; + size_t i = 0; + for (; i < len; ++i) { + std::vector crAddOpnds{lhsCR.GetOpnd(i), rhsCR.GetOpnd(i)}; + crOpnds.push_back(GetCRAddNode(nullptr, crAddOpnds)); + } + if (i < lhsCR.GetOpndsSize()) { + crOpnds.insert(crOpnds.end(), lhsCR.GetOpnds().begin() + i, lhsCR.GetOpnds().end()); + } else if (i < rhsCR.GetOpndsSize()) { + crOpnds.insert(crOpnds.end(), rhsCR.GetOpnds().begin() + i, rhsCR.GetOpnds().end()); + } + crPtr->SetOpnds(crOpnds); + return crPtr; +} + +// support later +CR *LoopScalarAnalysisResult::MulCRWithCR(const CR &lhsCR, const CR &rhsCR) const { + CHECK_FATAL(lhsCR.GetCRType() == kCRNode, "must be kCRNode"); + CHECK_FATAL(rhsCR.GetCRType() == kCRNode, "must be kCRNode"); + CHECK_FATAL(false, "NYI"); +} + +CRNode *LoopScalarAnalysisResult::ComputeCRNodeWithOperator(MeExpr &expr, CRNode &lhsCRNode, + CRNode &rhsCRNode, Opcode op) { + switch (op) { + case OP_add: { + std::vector crAddNodes; + crAddNodes.push_back(&lhsCRNode); + crAddNodes.push_back(&rhsCRNode); + return GetCRAddNode(&expr, crAddNodes); + } + case OP_sub: { + std::vector crAddNodes; + crAddNodes.push_back(&lhsCRNode); + crAddNodes.push_back(ChangeNegative2MulCRNode(rhsCRNode)); + return GetCRAddNode(&expr, crAddNodes); + } + case OP_mul: { + std::vector crMulNodes; + crMulNodes.push_back(&lhsCRNode); + crMulNodes.push_back(&rhsCRNode); + return GetCRMulNode(&expr, crMulNodes); + } + case OP_div: { + return GetOrCreateCRDivNode(&expr, lhsCRNode, rhsCRNode); + } + default: + return nullptr; + } +} + +bool LoopScalarAnalysisResult::HasUnknownCRNode(CRNode &crNode, CRNode *&result) { + switch (crNode.GetCRType()) { + case kCRConstNode: { + return false; + } + case kCRVarNode: { + return false; + } + case kCRAddNode: { + CRAddNode *crAddNode = static_cast(&crNode); + CHECK_FATAL(crAddNode->GetOpndsSize() > 1, "crAddNode must has more than one opnd"); + for (size_t i = 0; i < crAddNode->GetOpndsSize(); ++i) { + if (HasUnknownCRNode(*crAddNode->GetOpnd(i), result)) { + return true; + } + } + return false; + } + case kCRMulNode: { + CRMulNode *crMulNode = static_cast(&crNode); + CHECK_FATAL(crMulNode->GetOpndsSize() > 1, "crMulNode must has more than one opnd"); + for (size_t i = 0; i < crMulNode->GetOpndsSize(); ++i) { + if (HasUnknownCRNode(*crMulNode->GetOpnd(i), result)) { + return true; + } + } + return false; + } + case kCRDivNode: { + CRDivNode *crDivNode = static_cast(&crNode); + return HasUnknownCRNode(*crDivNode->GetLHS(), result) || HasUnknownCRNode(*crDivNode->GetLHS(), result); + } + case kCRNode: { + CR *cr = static_cast(&crNode); + CHECK_FATAL(cr->GetOpndsSize() > 1, "cr must has more than one opnd"); + for (size_t i = 0; i < cr->GetOpndsSize(); ++i) { + if (HasUnknownCRNode(*cr->GetOpnd(i), result)) { + return true; + } + } + return false; + } + case kCRUnKnown: + result = &crNode; + return true; + default: + CHECK_FATAL(false, "impossible !"); + } + return true; +} + +// a = phi(b, c) +// c = a + d +// b and d is loopInvarirant +CRNode *LoopScalarAnalysisResult::CreateSimpleCRForPhi(MePhiNode &phiNode, + VarMeExpr &startExpr, const VarMeExpr &backEdgeExpr) { + if (backEdgeExpr.GetDefBy() != kDefByStmt) { + return nullptr; + } + MeExpr *rhs = backEdgeExpr.GetDefStmt()->GetRHS(); + if (rhs == nullptr) { + return nullptr; + } + if (rhs->GetMeOp() == kMeOpConst && startExpr.GetDefBy() == kDefByStmt) { + MeExpr *rhs2 = startExpr.GetDefStmt()->GetRHS(); + if (rhs2->GetMeOp() == kMeOpConst && + (static_cast(rhs)->GetIntValue() == static_cast(rhs2)->GetIntValue())) { + return GetOrCreateLoopInvariantCR(*rhs); + } + } + if (rhs->GetMeOp() != kMeOpOp || static_cast(rhs)->GetOp() != OP_add) { + return nullptr; + } + OpMeExpr *opMeExpr = static_cast(rhs); + MeExpr *opnd1 = opMeExpr->GetOpnd(0); + MeExpr *opnd2 = opMeExpr->GetOpnd(1); + CRNode *stride = nullptr; + MeExpr *strideExpr = nullptr; + if (opnd1->GetMeOp() == kMeOpVar && static_cast(opnd1)->GetDefBy() == kDefByPhi && + &(static_cast(opnd1)->GetDefPhi()) == &phiNode) { + strideExpr = opnd2; + } else if (opnd2->GetMeOp() == kMeOpVar && static_cast(opnd2)->GetDefBy() == kDefByPhi && + &(static_cast(opnd2)->GetDefPhi()) == &phiNode) { + strideExpr = opnd1; + } + if (strideExpr == nullptr) { + return nullptr; + } + switch (strideExpr->GetMeOp()) { + case kMeOpConst: { + stride = GetOrCreateLoopInvariantCR(*strideExpr); + break; + } + case kMeOpVar: { + if (static_cast(strideExpr)->DefByBB() != nullptr && + !loop->Has(*static_cast(strideExpr)->DefByBB())) { + stride = GetOrCreateLoopInvariantCR(*strideExpr); + } + break; + } + case kMeOpIvar: { + if (static_cast(strideExpr)->GetDefStmt() != nullptr && + static_cast(strideExpr)->GetDefStmt()->GetBB() != nullptr && + !loop->Has(*static_cast(strideExpr)->GetDefStmt()->GetBB())) { + stride = GetOrCreateLoopInvariantCR(*strideExpr); + } + break; + } + default: { + return nullptr; + } + } + if (stride == nullptr) { + return nullptr; + } + CRNode *start = GetOrCreateLoopInvariantCR(startExpr); + return GetOrCreateCR(*phiNode.GetLHS(), *start, *stride); +} + +CRNode *LoopScalarAnalysisResult::CreateCRForPhi(MePhiNode &phiNode) { + auto *opnd1 = static_cast(phiNode.GetOpnd(0)); + auto *opnd2 = static_cast(phiNode.GetOpnd(1)); + VarMeExpr *startExpr = nullptr; + VarMeExpr *backEdgeExpr = nullptr; + if (opnd1->DefByBB() == nullptr || opnd2->DefByBB() == nullptr) { + return nullptr; + } + if (!loop->Has(*opnd1->DefByBB()) && loop->Has(*opnd2->DefByBB())) { + startExpr = opnd1; + backEdgeExpr = opnd2; + } else if (loop->Has(*opnd1->DefByBB()) && !loop->Has(*opnd2->DefByBB())) { + startExpr = opnd2; + backEdgeExpr = opnd1; + } else { + return nullptr; + } + if (startExpr == nullptr || backEdgeExpr == nullptr) { + return nullptr; + } + if (auto *cr = CreateSimpleCRForPhi(phiNode, *startExpr, *backEdgeExpr)) { + return cr; + } + std::unique_ptr phiUnKnown = std::make_unique(static_cast(phiNode.GetLHS())); + CRUnKnownNode *phiUnKnownPtr = phiUnKnown.get(); + allCRNodes.insert(std::move(phiUnKnown)); + InsertExpr2CR(*(static_cast(phiNode.GetLHS())), static_cast(phiUnKnownPtr)); + CRNode *backEdgeCRNode = GetOrCreateCRNode(*backEdgeExpr); + if (backEdgeCRNode == nullptr) { + InsertExpr2CR(*(static_cast(phiNode.GetLHS())), nullptr); + return nullptr; + } + if (backEdgeCRNode->GetCRType() == kCRAddNode) { + size_t index = static_cast(backEdgeCRNode)->GetOpndsSize() + 1; + for (size_t i = 0; i < static_cast(backEdgeCRNode)->GetOpndsSize(); ++i) { + if (static_cast(backEdgeCRNode)->GetOpnd(i) == phiUnKnownPtr) { + index = i; + break; + } + } + if (index == (static_cast(backEdgeCRNode)->GetOpndsSize() + 1)) { + InsertExpr2CR(*(static_cast(phiNode.GetLHS())), nullptr); + return nullptr; + } + std::vector crNodes; + for (size_t i = 0; i < static_cast(backEdgeCRNode)->GetOpndsSize(); ++i) { + if (i != index) { + crNodes.push_back(static_cast(backEdgeCRNode)->GetOpnd(i)); + } + } + CRNode *start = GetOrCreateLoopInvariantCR(*(static_cast(startExpr))); + CRNode *stride = GetCRAddNode(nullptr, crNodes); + if (stride == nullptr) { + InsertExpr2CR(*(static_cast(phiNode.GetLHS())), nullptr); + return nullptr; + } + CRNode *crNode = nullptr; + if (HasUnknownCRNode(*stride, crNode)) { + CHECK_NULL_FATAL(crNode); + CHECK_FATAL(crNode->GetCRType() == kCRUnKnown, "must be kCRUnKnown!"); + InsertExpr2CR(*(static_cast(phiNode.GetLHS())), nullptr); + return nullptr; + } + CR *cr = static_cast(GetOrCreateCR(*phiNode.GetLHS(), *start, *stride)); + return cr; + } else { + InsertExpr2CR(*(static_cast(phiNode.GetLHS())), nullptr); + return nullptr; + } +} + +CRNode *LoopScalarAnalysisResult::GetOrCreateCRNode(MeExpr &expr) { + if (IsAnalysised(expr)) { + return expr2CR[&expr]; + } + // Only support expr is kMeOpConst, kMeOpVar, kMeOpIvar + switch (expr.GetMeOp()) { + case kMeOpConst: { + return GetOrCreateLoopInvariantCR(expr); + } + case kMeOpVar: { + VarMeExpr *varExpr = static_cast(&expr); + if (varExpr->DefByBB() != nullptr && !loop->Has(*varExpr->DefByBB())) { + return GetOrCreateLoopInvariantCR(expr); + } + switch (varExpr->GetDefBy()) { + case kDefByStmt: { + MeExpr *rhs = varExpr->GetDefStmt()->GetRHS(); + switch (rhs->GetMeOp()) { + case kMeOpConst: { + return GetOrCreateLoopInvariantCR(expr); + } + case kMeOpVar: { + return GetOrCreateCRNode(*rhs); + } + case kMeOpOp: { + OpMeExpr *opMeExpr = static_cast(rhs); + switch (opMeExpr->GetOp()) { + case OP_add: + case OP_sub: + case OP_mul: + case OP_div: { + CHECK_FATAL(opMeExpr->GetNumOpnds() == kNumOpnds, "must be"); + MeExpr *opnd1 = opMeExpr->GetOpnd(0); + MeExpr *opnd2 = opMeExpr->GetOpnd(1); + CRNode *lhsCR = GetOrCreateCRNode(*opnd1); + CRNode *rhsCR = GetOrCreateCRNode(*opnd2); + if (lhsCR == nullptr || rhsCR == nullptr) { + return nullptr; + } + return ComputeCRNodeWithOperator(expr, *lhsCR, *rhsCR, opMeExpr->GetOp()); + } + default: + InsertExpr2CR(expr, nullptr); + return nullptr; + } + } + default: + InsertExpr2CR(expr, nullptr); + return nullptr; + } + } + case kDefByPhi: { + MePhiNode *phiNode = &(varExpr->GetDefPhi()); + if (phiNode->GetOpnds().size() == kNumOpnds) { + return CreateCRForPhi(*phiNode); + } else { + InsertExpr2CR(expr, nullptr); + return nullptr; + } + } + case kDefByChi: { + ChiMeNode *chiNode = &(varExpr->GetDefChi()); + if (!loop->Has(*chiNode->GetBase()->GetBB())) { + return GetOrCreateLoopInvariantCR(expr); + } else { + InsertExpr2CR(expr, nullptr); + return nullptr; + } + } + case kDefByNo: { + return GetOrCreateLoopInvariantCR(expr); + } + default: + InsertExpr2CR(expr, nullptr); + return nullptr; + } + } + case kMeOpIvar: { + if (static_cast(&expr)->GetDefStmt() != nullptr && + static_cast(&expr)->GetDefStmt()->GetBB() != nullptr && + !loop->Has(*static_cast(&expr)->GetDefStmt()->GetBB())) { + return GetOrCreateLoopInvariantCR(expr); + } else { + InsertExpr2CR(expr, nullptr); + return nullptr; + } + } + default: + InsertExpr2CR(expr, nullptr); + return nullptr; + } +} + +bool IsLegal(MeStmt &meStmt) { + CHECK_FATAL(meStmt.IsCondBr(), "must be"); + auto *brMeStmt = static_cast(&meStmt); + MeExpr *meCmp = brMeStmt->GetOpnd(); + if (meCmp->GetMeOp() != kMeOpOp) { + return false; + } + auto *opMeExpr = static_cast(meCmp); + CHECK_FATAL(opMeExpr->GetNumOpnds() == kNumOpnds, "must be"); + if (opMeExpr->GetOp() != OP_ge && opMeExpr->GetOp() != OP_le && + opMeExpr->GetOp() != OP_lt && opMeExpr->GetOp() != OP_gt && + opMeExpr->GetOp() != OP_eq) { + return false; + } + MeExpr *opnd1 = opMeExpr->GetOpnd(0); + MeExpr *opnd2 = opMeExpr->GetOpnd(1); + if (!IsPrimitivePureScalar(opnd1->GetPrimType()) || !IsPrimitivePureScalar(opnd2->GetPrimType())) { + return false; + } + return true; +} + + +// need consider min and max integer +uint32 LoopScalarAnalysisResult::ComputeTripCountWithCR(const CR &cr, const OpMeExpr &opMeExpr, int32 value) { + uint32 tripCount = 0; + for (uint32 i = 0; ; ++i) { + CRNode *result = cr.ComputeValueAtIteration(i, *this); + switch (opMeExpr.GetOp()) { + case OP_ge: { // < + if (static_cast(result)->GetConstValue() < value) { + ++tripCount; + } else { + return tripCount; + } + break; + } + case OP_le: { + if (static_cast(result)->GetConstValue() > value) { + ++tripCount; + } else { + return tripCount; + } + break; + } + case OP_gt: { // <= + if (static_cast(result)->GetConstValue() <= value) { + ++tripCount; + } else { + return tripCount; + } + break; + } + case OP_lt: { + if (static_cast(result)->GetConstValue() >= value) { + ++tripCount; + } else { + return tripCount; + } + break; + } + case OP_eq: { + if (static_cast(result)->GetConstValue() != value) { + ++tripCount; + } else { + return tripCount; + } + break; + } + default: + CHECK_FATAL(false, "operator must be >=, <=, >, <, !="); + } + } +} + +uint32 LoopScalarAnalysisResult::ComputeTripCountWithSimpleConstCR(const OpMeExpr &opMeExpr, int32 value, + int32 start, int32 stride) const { + constexpr int32 javaIntMinValue = -2147483648; // -8fffffff + constexpr int32 javaIntMaxValue = 2147483647; // 7fffffff + CHECK_FATAL(stride != 0, "stride must not be zero"); + if (value == start) { + return 0; + } + if (stride < 0) { + stride = -stride; + } + int32 times = (value < start) ? ((start - value) / stride) : ((value - start) / stride); + if (times <= 0) { + return 0; + } + uint32 remainder = (value < start) ? ((start - value) % stride) : ((value - start) % stride); + switch (opMeExpr.GetOp()) { + case OP_ge: { // < + if (start >= value || start - stride >= value) { + return 0; + } + return (remainder == 0) ? times : (times + 1); + } + case OP_le: { // > + if (start <= value || start - stride <= value) { + return 0; + } + return (remainder == 0) ? times : (times + 1); + } + case OP_gt: { // <= + if (start > value || start - stride > value || (start < value && value == javaIntMaxValue)) { + return 0; + } + return times + 1; + } + case OP_lt: { // >= + if (start < value || start - stride < value || (start > value && value == javaIntMinValue)) { + return 0; + } + return times + 1; + } + case OP_eq: { // != + if (start == value || start - stride == value) { + return 0; + } + return (remainder == 0) ? times : 0; + } + default: + CHECK_FATAL(false, "operator must be >=, <=, >, <, !="); + } +} + +void LoopScalarAnalysisResult::DumpTripCount(const CR &cr, int32 value, const MeExpr *expr) { + LogInfo::MapleLogger() << "==========Dump CR=========\n"; + Dump(cr); + if (expr == nullptr) { + LogInfo::MapleLogger() << "\n" << "value: " << value << "\n"; + } else { + LogInfo::MapleLogger() << "\n" << "value: mx_" << expr->GetExprID() << "\n"; + } + + VerifyCR(cr); + LogInfo::MapleLogger() << "==========Dump CR End=========\n"; +} + +TripCountType LoopScalarAnalysisResult::ComputeTripCount(MeFunction &func, uint32 &tripCountResult, + CRNode *&conditionCRNode, CR *&itCR) { + enableDebug = false; + BB *exitBB = func.GetBBFromID(loop->inloopBB2exitBBs.begin()->first); + if (exitBB->GetKind() == kBBCondGoto && IsLegal(*(exitBB->GetLastMe()))) { + auto *brMeStmt = static_cast(exitBB->GetLastMe()); + BB *brTarget = exitBB->GetSucc(1); + CHECK_FATAL(brMeStmt->GetOffset() == brTarget->GetBBLabel(), "must be"); + auto *opMeExpr = static_cast(brMeStmt->GetOpnd()); + MeExpr *opnd1 = opMeExpr->GetOpnd(0); + MeExpr *opnd2 = opMeExpr->GetOpnd(1); + if (opnd1->GetPrimType() != PTY_i32 || opnd2->GetPrimType() != PTY_i32) { + return kCouldNotComputeCR; + } + CRNode *crNode1 = GetOrCreateCRNode(*opnd1); + CRNode *crNode2 = GetOrCreateCRNode(*opnd2); + CR *cr = nullptr; + CRConstNode *constNode = nullptr; + if (crNode1 != nullptr && crNode2 != nullptr) { + if (crNode1->GetCRType() == kCRNode && crNode2->GetCRType() == kCRConstNode) { + cr = static_cast(crNode1); + constNode = static_cast(crNode2); + } else if (crNode2->GetCRType() == kCRNode && crNode1->GetCRType() == kCRConstNode) { + cr = static_cast(crNode2); + constNode = static_cast(crNode1); + } else if (crNode1->GetCRType() == kCRNode && crNode2->GetCRType() == kCRNode) { + return kCouldNotUnroll; // can not compute tripcount + } else if (crNode1->GetCRType() == kCRNode || crNode2->GetCRType() == kCRNode) { + if (crNode1->GetCRType() == kCRNode) { + conditionCRNode = crNode2; + itCR = static_cast(crNode1); + } else if (crNode2->GetCRType() == kCRNode) { + conditionCRNode = crNode1; + itCR = static_cast(crNode2); + } else { + CHECK_FATAL(false, "impossible"); + } + if (enableDebug) { + DumpTripCount(*itCR, 0, conditionCRNode->GetExpr()); + } + return kVarCondition; + } else { + return kCouldNotComputeCR; + } + } else { + return kCouldNotComputeCR; + } + if (enableDebug) { + DumpTripCount(*cr, constNode->GetConstValue(), nullptr); + } + for (auto opnd : cr->GetOpnds()) { + if (opnd->GetCRType() != kCRConstNode) { + conditionCRNode = constNode; + itCR = cr; + return kVarCR; + } + } + CHECK_FATAL(cr->GetOpndsSize() > 1, "impossible"); + if (cr->GetOpndsSize() == 2) { // cr has two opnds like {1, + 1} + tripCountResult = ComputeTripCountWithSimpleConstCR(*opMeExpr, constNode->GetConstValue(), + static_cast(cr->GetOpnd(0))->GetConstValue(), + static_cast(cr->GetOpnd(1))->GetConstValue()); + return kConstCR; + } else { + CHECK_FATAL(false, "NYI"); + tripCountResult = ComputeTripCountWithCR(*cr, *opMeExpr, constNode->GetConstValue()); + return kConstCR; + } + return kConstCR; + } + return kCouldNotUnroll; +} +} // namespace maple diff --git a/src/mapleall/maple_me/src/me_ssa_devirtual.cpp b/src/mapleall/maple_me/src/me_ssa_devirtual.cpp index d03f480ada932f34227d88ecfdf17997e0ef846b..d44a7bdecc1be90c395e6fd2805a08895cb3c70c 100644 --- a/src/mapleall/maple_me/src/me_ssa_devirtual.cpp +++ b/src/mapleall/maple_me/src/me_ssa_devirtual.cpp @@ -26,6 +26,10 @@ AnalysisResult *MeDoSSADevirtual::Run(MeFunction *func, MeFuncResultMgr *frm, Mo auto *kh = static_cast(mrm->GetAnalysisResult(MoPhase_CHA, &func->GetMIRModule())); ASSERT(kh != nullptr, "KlassHierarchy has problem"); bool skipReturnTypeOpt = false; + // If not in ipa and ignoreInferredRetType is enabled, ssadevirt will ignore inferred return type of any function + if (!func->GetMIRModule().IsInIPA() && MeOption::ignoreInferredRetType) { + skipReturnTypeOpt = true; + } MeSSADevirtual meSSADevirtual(*NewMemPool(), func->GetMIRModule(), *func, *irMap, *kh, *dom, skipReturnTypeOpt); if (Options::O2) { Clone *clone = static_cast(mrm->GetAnalysisResult(MoPhase_CLONE, &func->GetMIRModule())); diff --git a/src/mapleall/maple_me/src/me_ssu_pre.cpp b/src/mapleall/maple_me/src/me_ssu_pre.cpp index 8a9f4cb0d36abee47824f271263eadf4cfb25449..37f17aeae16ef28eb75328cc65fa6defc362e543 100644 --- a/src/mapleall/maple_me/src/me_ssu_pre.cpp +++ b/src/mapleall/maple_me/src/me_ssu_pre.cpp @@ -529,7 +529,7 @@ void MeSSUPre::CreateSortedOccs() { void MeSSUPre::ApplySSUPre() { BuildWorkListBB(func->GetCommonExitBB()); - if (preKind != kSecondDecrefPre) { // #0 build worklist + if (!MeOption::gcOnly && preKind != kSecondDecrefPre) { // #0 build worklist CreateEmptyCleanupIntrinsics(); } if (enabledDebug) { diff --git a/src/mapleall/maple_me/src/me_stmt_pre.cpp b/src/mapleall/maple_me/src/me_stmt_pre.cpp index 7755d95889dbb1743346389e51195f9d2583e45f..e94360741f35b51c1a93ef2fc3d640b42ce7fcb1 100644 --- a/src/mapleall/maple_me/src/me_stmt_pre.cpp +++ b/src/mapleall/maple_me/src/me_stmt_pre.cpp @@ -24,6 +24,22 @@ // accumulate the BBs that are in the iterated dominance frontiers of bb in // the set dfset, visiting each BB only once namespace maple { +static bool IsParaAndRetTypeRefOrPtr(const CallMeStmt &stmt) { + const MIRFunction &func = stmt.GetTargetFunction(); + if (func.GetName() == "MCC_GetOrInsertLiteral") { + return false; + } + for (auto it : stmt.GetOpnds()) { + if (it->GetPrimType() == PTY_ref || it->GetPrimType() == PTY_ptr) { + return true; + } + } + const MeExpr *expr = stmt.GetAssignedLHS(); + if (expr != nullptr && (expr->GetPrimType() == PTY_ref || expr->GetPrimType() == PTY_ptr)) { + return true; + } + return false; +} void MeStmtPre::GetIterDomFrontier(const BB &bb, MapleSet &dfSet, std::vector &visitedMap) const { CHECK_FATAL(bb.GetBBId() < visitedMap.size(), "index out of range in MeStmtPre::GetIterDomFrontier"); @@ -988,6 +1004,45 @@ void MeStmtPre::BuildWorkListBB(BB *bb) { case OP_callassigned: { auto &callAss = static_cast(stmt); VersionStackChiListUpdate(*callAss.GetChiList()); + MIRFunction &callee = callAss.GetTargetFunction(); + if (!callAss.GetChiList()->empty() || !callee.IsPure() || !callee.IsNoThrowException()) { + break; + } + if (IsParaAndRetTypeRefOrPtr(callAss)) { + break; + } + + bool allOperandsAreLeafAndPure = true; + for (MeExpr *o : callAss.GetOpnds()) { + if (!o->IsLeaf() || !o->Pure()) { + allOperandsAreLeafAndPure = false; + break; + } + } + if (!allOperandsAreLeafAndPure) { + break; + } + if (callAss.GetMustDefList()->empty()) { + (void)CreateStmtRealOcc(stmt, static_cast(seqStmt)); + break; + } + VarMeExpr &varMeExpr = utils::ToRef(safe_cast(callAss.GetMustDefList()->front().GetLHS())); + const OriginalSt *ost = ssaTab->GetOriginalStFromID(varMeExpr.GetOstIdx()); + if (ost->IsFinal()) { + PreStmtWorkCand *stmtWkCand = CreateStmtRealOcc(stmt, seqStmt); + stmtWkCand->SetLHSIsFinal(true); + } else { + bool allOperandFeasible = true; + for (MeExpr *o : callAss.GetOpnds()) { + if (o->SymAppears(varMeExpr.GetOstIdx())) { + allOperandFeasible = false; + break; + } + } + if (allOperandFeasible && NoPriorUseInBB(&varMeExpr, &stmt)) { + (void)CreateStmtRealOcc(stmt, static_cast(seqStmt)); + } + } break; } default: diff --git a/src/mapleall/maple_me/src/me_subsum_rc.cpp b/src/mapleall/maple_me/src/me_subsum_rc.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8cb8b6eecbe337d52c44e5e16d12bac6f6e5b7b6 --- /dev/null +++ b/src/mapleall/maple_me/src/me_subsum_rc.cpp @@ -0,0 +1,345 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "me_subsum_rc.h" + +namespace maple { +void SubsumRC::SetCantSubsum() { + for (BB *bb : func->GetAllBBs()) { + if (bb == nullptr) { + continue; + } + for (auto it : bb->GetMePhiList()) { + const OriginalSt *ost = ssaTab->GetOriginalStFromID(it.first); + if (!ost->IsSymbolOst() || ost->GetIndirectLev() != 0) { + continue; + } + MePhiNode *phi = it.second; + if (!phi->GetIsLive()) { + continue; + } + for (auto *phiOpnd : phi->GetOpnds()) { + verstCantSubsum[phiOpnd->GetVstIdx()] = true; + } + } + } +} +// Return true if there is an occ of the lhs is post-dominated by rhs occ. +bool SubsumRC::IsRhsPostDominateLhs(const SOcc &rhsOcc, const VarMeExpr &lhs) const { + for (SOcc *occ : allOccs) { + if (occ->GetOccTy() == kSOccReal) { + auto *realOcc = static_cast(occ); + if (realOcc->GetVar() == &lhs && rhsOcc.IsPostDominate(dom, occ)) { + return true; + } + } + } + return false; +} + +// ================ Step 6: Code Motion ================ +void SubsumRC::SubsumeRC(MeStmt &stmt) { + ASSERT(stmt.GetOp() == OP_dassign, "work_cand should be a dassign stmt"); + auto *dass = static_cast(&stmt); + auto *lhs = static_cast(stmt.GetLHSRef(false)); + auto *rhsVar = dass->GetRHS(); + bool lhsFound = false; + for (SOcc *occ : allOccs) { + if (occ->GetOccTy() == kSOccReal) { + auto *realOcc = static_cast(occ); + if (realOcc->GetVar() == lhs && !realOcc->GetRedundant()) { + lhsFound = true; + break; + } else if (realOcc->GetVar() == rhsVar && realOcc->GetRedundant()) { + // if there is a decref of rhs is just post-dominate that of the lhs, + // it can't do subsum either. + if (IsRhsPostDominateLhs(*realOcc, *lhs)) { + lhsFound = true; + break; + } + } + } + } + if (!lhsFound) { + ASSERT_NOT_NULL(lhs); + auto mItem = irMap->FindDecrefItem(*lhs); + MapleSet *stmts = (*mItem).second; + for (auto it = stmts->begin(); it != stmts->end(); ++it) { + MeStmt *stmtTemp = *it; + stmtTemp->GetBB()->RemoveMeStmt(stmtTemp); + if (enabledDebug) { + LogInfo::MapleLogger() << "Remove decrefreset stmt in BB" << stmtTemp->GetBB()->GetBBId() << ":\n"; + stmtTemp->Dump(irMap); + } + } + stmt.DisableNeedIncref(); + if (enabledDebug) { + LogInfo::MapleLogger() << "Remove the incref of stmt: "; + stmt.Dump(irMap); + } + // Replace the localvar of the lhs with a register., in case it throws excption just after + // the dassign stmt, because we ignore the incref of the lhs. + RegMeExpr *regTemp = irMap->CreateRegRefMeExpr(*lhs); + RegassignMeStmt *rass = irMap->CreateRegassignMeStmt(*regTemp, *dass->GetRHS(), *stmt.GetBB()); + regTemp->SetDefByStmt(*rass); + if (enabledDebug) { + LogInfo::MapleLogger() << "Replace dassign stmt:"; + stmt.Dump(irMap); + LogInfo::MapleLogger() << "with regassign stmt:"; + rass->Dump(irMap); + } + stmt.GetBB()->ReplaceMeStmt(&stmt, rass); + rass->DisableNeedIncref(); + ReplaceExpr(*stmt.GetBB(), *lhs, *regTemp); + for (size_t i = 0; i < bbVisited.size(); ++i) { + bbVisited[i] = false; + } + } else { + // check the special case. + auto *rhs = static_cast(dass->GetRHS()); + ASSERT_NOT_NULL(irMap); + auto mItem = irMap->FindDecrefItem(*rhs); + MapleSet *stmts = (*mItem).second; + MeStmt *decRef = stmt.GetNextMeStmt(); + if (decRef != nullptr && decRef->GetOp() == OP_decrefreset && stmts->find(decRef) != stmts->end()) { + ASSERT_NOT_NULL(lhs); + lhs->SetNoDelegateRC(true); + stmt.GetBB()->RemoveMeStmt(decRef); + stmt.DisableNeedIncref(); + VarMeExpr *tempVar = irMap->CreateVarMeExprVersion(*rhs); + MeExpr *zeroExpr = irMap->CreateIntConstMeExpr(0, PTY_ref); + DassignMeStmt *newDass = irMap->CreateDassignMeStmt(*tempVar, *zeroExpr, *stmt.GetBB()); + stmt.GetBB()->InsertMeStmtAfter(&stmt, newDass); + if (enabledDebug) { + LogInfo::MapleLogger() << "last subsum for stmt:"; + stmt.Dump(irMap); + } + } + } +} + +void SubsumRC::ReplaceExpr(BB &bb, const MeExpr &var, MeExpr ®) { + if (bbVisited[bb.GetBBId()]) { + return; + } + bbVisited[bb.GetBBId()] = true; + auto &meStmts = bb.GetMeStmts(); + for (auto itStmt = meStmts.rbegin(); itStmt != meStmts.rend(); ++itStmt) { + MeStmt *stmt = to_ptr(itStmt); + if (stmt->NumMeStmtOpnds() == 0) { + continue; + } + ASSERT_NOT_NULL(irMap); + (void)irMap->ReplaceMeExprStmt(*stmt, var, reg); + } + for (BB *succ : bb.GetSucc()) { + ReplaceExpr(*succ, var, reg); + } +} + +// ================ Step 0: collect occurrences ================ +// create realoccurence decRef of varX, meStmt is the work candidate. +void SubsumRC::CreateRealOcc(VarMeExpr &varX, DassignMeStmt &meStmt, MeStmt &decRef) { + SpreWorkCand *wkCand = nullptr; + auto mapIt = candMap.find(&meStmt); + if (mapIt != candMap.end()) { + wkCand = mapIt->second; + } else { + OriginalSt *ost = ssaTab->GetSymbolOriginalStFromID(varX.GetOstIdx()); + wkCand = spreMp->New(spreAllocator, *ost); + candMap[&meStmt] = wkCand; + } + if (wkCand->GetTheVar() == nullptr) { + wkCand->SetTheVar(varX); + } + SRealOcc *newOcc = spreMp->New(decRef, varX); + wkCand->GetRealOccs().push_back(newOcc); +} + +// collect occurenc in postdominator preorder. +void SubsumRC::BuildRealOccs(MeStmt &stmt, BB &bb) { + ASSERT(stmt.GetOp() == OP_dassign, "stmt should be dassign."); + auto *dass = static_cast(&stmt); + auto *lhs = static_cast(stmt.GetLHSRef(false)); + auto *rhs = static_cast(dass->GetRHS()); + ASSERT(lhs != nullptr, "lhs should be var"); + ASSERT(rhs != nullptr, "rhs should be var"); + auto mItemLhs = irMap->FindDecrefItem(*lhs); + MapleSet *stmtsLhs = (*mItemLhs).second; + auto mItemRhs = irMap->FindDecrefItem(*rhs); + MapleSet *stmtsRhs = (*mItemRhs).second; + auto &meStmts = bb.GetMeStmts(); + for (auto itStmt = meStmts.rbegin(); itStmt != meStmts.rend(); ++itStmt) { + if (itStmt->GetOp() != OP_decrefreset) { + continue; + } + MeStmt *st = to_ptr(itStmt); + if (stmtsLhs->find(st) != stmtsLhs->end()) { + if (enabledDebug) { + LogInfo::MapleLogger() << "Create realocc for stmt lhs in BB" << st->GetBB()->GetBBId() << ":\n"; + st->Dump(irMap); + } + CreateRealOcc(*lhs, *dass, *st); + } else if (stmtsRhs->find(st) != stmtsRhs->end()) { + if (enabledDebug) { + LogInfo::MapleLogger() << "Create realocc for stmt rhs in BB" << st->GetBB()->GetBBId() << ":\n"; + st->Dump(irMap); + } + CreateRealOcc(*rhs, *dass, *st); + } + } + // recurse on child BBs in post-dominator tree + for (BBId bbId : dom->GetPdomChildrenItem(bb.GetBBId())) { + BuildRealOccs(stmt, *func->GetBBFromID(bbId)); + } +} + +void SubsumRC::BuildWorkListBB(BB *bb) { + if (bb == nullptr) { + return; + } + // traverse statements backwards + auto &meStmts = bb->GetMeStmts(); + for (auto itStmt = meStmts.rbegin(); itStmt != meStmts.rend(); ++itStmt) { + if (itStmt->GetOp() != OP_dassign) { + continue; + } + // skip identity assignments + auto *dass = static_cast(to_ptr(itStmt)); + ASSERT_NOT_NULL(dass->GetLHS()); + if (dass->GetLHS()->IsUseSameSymbol(*dass->GetRHS())) { + continue; + } + if (!dass->NeedIncref()) { + continue; + } + if (dass->GetRHS() == nullptr || dass->GetRHS()->GetMeOp() != kMeOpVar || + dass->GetRHS()->GetPrimType() != PTY_ref) { + continue; + } + // look for real occurrence of y = x; + auto *lhs = static_cast(dass->GetLHSRef(false)); + if (lhs == nullptr) { + continue; + } + if (verstCantSubsum[lhs->GetVstIdx()] || lhs->GetNoSubsumeRC()) { + if (enabledDebug) { + dass->Dump(irMap); + verstCantSubsum[lhs->GetVstIdx()] ? LogInfo::MapleLogger() << "thelhs is phiopnd." << '\n' + : LogInfo::MapleLogger() << "thelhs is nosubsumed." << '\n'; + } + continue; + } + const OriginalSt *lhsOst = ssaTab->GetSymbolOriginalStFromID(lhs->GetOstIdx()); + if (lhsOst->IsLocal() || lhsOst->IsEPreLocalRefVar()) { + auto mItemLhs = irMap->FindDecrefItem(*lhs); + if (mItemLhs == irMap->GetDecrefsEnd()) { + continue; + } + auto *rhs = static_cast(dass->GetRHS()); + auto mItemRhs = irMap->FindDecrefItem(*rhs); + if (mItemRhs == irMap->GetDecrefsEnd()) { + continue; + } + MapleSet *lhsStmts = (*mItemLhs).second; + MapleSet *rhsStmts = (*mItemRhs).second; + if (lhsStmts == nullptr || rhsStmts == nullptr) { + if (enabledDebug) { + LogInfo::MapleLogger() << "thelhs is decefreseted in cleanup.\n"; + } + continue; + } + if (enabledDebug) { + LogInfo::MapleLogger() << "Create realocc for stmt:"; + dass->Dump(irMap); + } + BuildRealOccs(*dass, *(func->GetCommonExitBB())); + } + } + if (bb->GetAttributes(kBBAttrIsEntry)) { + CreateEntryOcc(*bb); + } + // recurse on child BBs in post-dominator tree + for (BBId bbId : dom->GetPdomChildrenItem(bb->GetBBId())) { + BuildWorkListBB(func->GetBBFromID(bbId)); + } +} + +void SubsumRC::RunSSUPre() { + SetCantSubsum(); + BuildWorkListBB(func->GetCommonExitBB()); + if (enabledDebug) { + LogInfo::MapleLogger() << "------ worklist initial size " << candMap.size() << '\n'; + } + size_t candNum = 0; + for (std::pair wkCandPair : candMap) { + workCand = wkCandPair.second; + MeStmt *stmt = wkCandPair.first; + ASSERT(stmt->GetOp() == OP_dassign, "work_cand should be a dassign stmt"); + auto *dass = static_cast(stmt); + // Because SubsumeRC may replace lvar by reg. + if (dass->GetRHS()->GetMeOp() != kMeOpVar) { + if (enabledDebug) { + LogInfo::MapleLogger() << "candidate " << candNum << "has been changed to:" << '\n'; + stmt->Dump(irMap); + LogInfo::MapleLogger() << "do nothing for it.\n"; + } + continue; + } + + if (enabledDebug) { + LogInfo::MapleLogger() << "Subsum candidate " << candNum << " in BB " << stmt->GetBB()->GetBBId() << ":"; + stmt->Dump(irMap); + } + // #1 insert lambdas; results in allOccs and lambdaOccs + FormLambdas(); // result put in the set lambda_bbs + CreateSortedOccs(); + // #2 rename + Rename(); + if (!lambdaOccs.empty()) { + // #3 UpSafety + ComputeUpsafe(); + // #4 CanBeAnt + ComputeCanBeFullyAnt(); + ComputeEarlier(); + } + // #5 Finalize + Finalize(); + // #6 Code Mmotion + ASSERT_NOT_NULL(workCand); + if (!workCand->GetHasCriticalEdge()) { + SubsumeRC(*stmt); + } + ++candNum; + } +} + +AnalysisResult *MeDoSubsumRC::Run(MeFunction *func, MeFuncResultMgr *funcMgr, ModuleResultMgr*) { + if (!(func->GetHints() & kPlacementRCed)) { + return nullptr; + } + if (MeOption::subsumRC == false) { + return nullptr; + } + auto *dom = static_cast(funcMgr->GetAnalysisResult(MeFuncPhase_DOMINANCE, func)); + ASSERT(dom != nullptr, "dominance phase has problem"); + SubsumRC subsumRC(*func, *dom, *NewMemPool(), DEBUGFUNC(func)); + subsumRC.RunSSUPre(); + if (DEBUGFUNC(func)) { + LogInfo::MapleLogger() << "\n============== After SUBSUM RC =============\n"; + func->Dump(false); + } + return nullptr; +} +} // namespace maple diff --git a/src/mapleall/maple_me/src/meconstprop.cpp b/src/mapleall/maple_me/src/meconstprop.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b4cf638c664c9c637998fb7f9372b3f1333f6eb1 --- /dev/null +++ b/src/mapleall/maple_me/src/meconstprop.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "meconstprop.h" +#include +#include +#include "clone.h" +#include "constantfold.h" +#include "mir_nodes.h" +#include "me_function.h" +#include "ssa_mir_nodes.h" +#include "mir_builder.h" + +namespace maple { +void MeConstProp::IntraConstProp() const {} + +void MeConstProp::InterConstProp() const {} + +AnalysisResult *MeDoIntraConstProp::Run(MeFunction*, MeFuncResultMgr*, ModuleResultMgr*) { + return nullptr; +} + +AnalysisResult *MeDoInterConstProp::Run(MeFunction*, MeFuncResultMgr*, ModuleResultMgr*) { + return nullptr; +} +} // namespace maple diff --git a/src/mapleall/maple_me/src/prop.cpp b/src/mapleall/maple_me/src/prop.cpp index 8ad951ae38db2be1e9e41bbe44380dd12062eb4d..64f95341a8c2970b66a800ae908de63b108072dd 100644 --- a/src/mapleall/maple_me/src/prop.cpp +++ b/src/mapleall/maple_me/src/prop.cpp @@ -15,6 +15,7 @@ #include "prop.h" #include "me_irmap.h" #include "dominance.h" +#include "constantfold.h" using namespace maple; diff --git a/src/mapleall/maple_me/src/ssa_devirtual.cpp b/src/mapleall/maple_me/src/ssa_devirtual.cpp index 6e88723455b3da3d12dbcc4dcc3ad3254bb07670..bebcaef0cd371ab47a8a30ef312fe40477db5fa7 100644 --- a/src/mapleall/maple_me/src/ssa_devirtual.cpp +++ b/src/mapleall/maple_me/src/ssa_devirtual.cpp @@ -24,6 +24,20 @@ // We can devirtual the b.foo() to be Derived::foo(). namespace maple { bool SSADevirtual::debug = false; +static bool NonNullRetValue(const MIRFunction &called) { + static const std::unordered_set nonNullRetValueFuncs = { + "Ljava_2Futil_2FArrayList_3B_7Citerator_7C_28_29Ljava_2Futil_2FIterator_3B", + "Ljava_2Futil_2FHashSet_3B_7Citerator_7C_28_29Ljava_2Futil_2FIterator_3B", + "Lsun_2Fsecurity_2Fjca_2FProviderList_24ServiceList_3B_7Citerator_7C_28_29Ljava_2Futil_2FIterator_3B", + "Ljava_2Futil_2FServiceLoader_3B_7Citerator_7C_28_29Ljava_2Futil_2FIterator_3B", + "Ljava_2Futil_2FCollections_24UnmodifiableCollection_3B_7Citerator_7C_28_29Ljava_2Futil_2FIterator_3B", + "Ljava_2Futil_2FAbstractList_3B_7Citerator_7C_28_29Ljava_2Futil_2FIterator_3B", + "Ljava_2Futil_2FTreeSet_3B_7Citerator_7C_28_29Ljava_2Futil_2FIterator_3B", + "Ljava_2Futil_2Fconcurrent_2FConcurrentSkipListMap_24KeySet_3B_7Citerator_7C_28_29Ljava_2Futil_2FIterator_3B", + "Ljava_2Futil_2FCollections_24CheckedCollection_3B_7Citerator_7C_28_29Ljava_2Futil_2FIterator_3B" + }; + return nonNullRetValueFuncs.find(called.GetName()) != nonNullRetValueFuncs.end(); +} static bool MaybeNull(const MeExpr &expr) { if (expr.GetMeOp() == kMeOpVar) { @@ -605,6 +619,9 @@ void SSADevirtual::TraversalMeStmt(MeStmt &meStmt) { MIRFunction &called = callMeStmt->GetTargetFunction(); if (called.GetInferredReturnTyIdx() != 0u) { lhsVar->SetInferredTyIdx(called.GetInferredReturnTyIdx()); + if (NonNullRetValue(called)) { + lhsVar->SetMaybeNull(false); + } if (SSADevirtual::debug) { MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(lhsVar->GetInferredTyIdx()); LogInfo::MapleLogger() << "[SSA-DEVIRT] [TYPE-INFERRING] mx" << lhsVar->GetExprID() << " "; diff --git a/src/mapleall/maple_me/src/ssa_epre.cpp b/src/mapleall/maple_me/src/ssa_epre.cpp index a2cc61a99fb29dd32cbcf7db1ccf6f4c21ca6811..3bb519474bdc05aebf129a1aaa517fe750f21969 100644 --- a/src/mapleall/maple_me/src/ssa_epre.cpp +++ b/src/mapleall/maple_me/src/ssa_epre.cpp @@ -120,12 +120,32 @@ void SSAEPre::GenerateSaveRealOcc(MeRealOcc &realOcc) { // replace realOcc->GetMeStmt()'s occ with regOrVar bool isReplaced = irMap->ReplaceMeExprStmt(*realOcc.GetMeStmt(), *realOcc.GetMeExpr(), *regOrVar); // rebuild worklist - if (isReplaced) { + if (isReplaced && !ReserveCalFuncAddrForDecouple(*realOcc.GetMeExpr())) { BuildWorkListStmt(*realOcc.GetMeStmt(), realOcc.GetSequence(), true, regOrVar); } realOcc.SetSavedExpr(*regOrVar); } +#ifdef USE_32BIT_REF +static constexpr int kFieldIDOfFuncAddrInClassMeta = 8; +#else +static constexpr int kFieldIDOfFuncAddrInClassMeta = 6; +#endif +bool SSAEPre::ReserveCalFuncAddrForDecouple(MeExpr &meExpr) const { + if (!Options::buildApp) { + return false; + } + bool virtualFuncAddr = false; + if (meExpr.GetMeOp() == kMeOpIvar) { + auto &ivar = static_cast(meExpr); + auto ptrTyIdx = ivar.GetTyIdx(); + auto *ptrType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ptrTyIdx); + virtualFuncAddr = + (static_cast(ptrType)->GetPointedType()->GetName() == namemangler::kClassMetadataTypeName) && + (ivar.GetFieldID() == kFieldIDOfFuncAddrInClassMeta); + } + return virtualFuncAddr; +} void SSAEPre::GenerateReloadRealOcc(MeRealOcc &realOcc) { CHECK_FATAL(!realOcc.IsLHS(), "GenerateReloadRealOcc: cannot be LHS occurrence"); @@ -152,7 +172,7 @@ void SSAEPre::GenerateReloadRealOcc(MeRealOcc &realOcc) { // replace realOcc->GetMeStmt()'s occ with regOrVar bool isReplaced = irMap->ReplaceMeExprStmt(*realOcc.GetMeStmt(), *realOcc.GetMeExpr(), *regOrVar); // update worklist - if (isReplaced) { + if (isReplaced && !ReserveCalFuncAddrForDecouple(*realOcc.GetMeExpr())) { BuildWorkListStmt(*realOcc.GetMeStmt(), realOcc.GetSequence(), true, regOrVar); } } diff --git a/src/mapleall/maple_me/src/sync_select.cpp b/src/mapleall/maple_me/src/sync_select.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c5a47c578f46d2b6a22eca16eff58222459c58db --- /dev/null +++ b/src/mapleall/maple_me/src/sync_select.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "sync_select.h" +#include "safe_cast.h" +#include "mpl_logging.h" + +namespace { +using namespace maple; + +enum class SyncKind : uint8 { + kSpinLock = 0, + kDefault = 2, + kSysCall = 3 +}; + +class SyncSelect { + public: + explicit SyncSelect(MeFunction &func) + : func(func) { + } + ~SyncSelect() = default; + + void SyncOptimization() { + // deal with func white list where all syncenter use same version + auto it = syncMap.find(func.GetName()); + if (it != syncMap.end()) { + SetAllSyncKind(it->second); + } + } + + private: + void AddFunc(uint8 kind, const std::string &funcName) { + syncMap[funcName] = static_cast(kind); + } + + void SetAllSyncKind(SyncKind kind) { + for (auto bIt = func.valid_begin(), eIt = func.valid_end(); bIt != eIt; ++bIt) { + for (auto &stmt : (*bIt)->GetStmtNodes()) { + if (stmt.GetOpCode() == OP_syncenter) { + SetSyncKind(stmt, kind); + } + } + } + } + + void SetSyncKind(StmtNode &stmt, SyncKind kind) const { + CHECK_FATAL(stmt.GetOpCode() == OP_syncenter, "expect syncenter in SetSyncKind"); + auto &nd = static_cast(stmt); + CHECK_FATAL(nd.GetNopndSize() > 1, "access nd->nOpnd failed"); + auto *cst = static_cast(nd.GetNopndAt(1)); + auto *intConst = safe_cast(cst->GetConstVal()); + utils::ToRef(intConst).SetValue(static_cast(kind)); + } + + MeFunction &func; + std::map syncMap; +}; +} + +namespace maple { +AnalysisResult *MeDoSyncSelect::Run(MeFunction *func, MeFuncResultMgr*, ModuleResultMgr*) { + SyncSelect(utils::ToRef(func)).SyncOptimization(); + if (DEBUGFUNC(func)) { + func->Dump(true); + } + return nullptr; +} +} // namespace maple diff --git a/src/mapleall/maple_util/include/factory.h b/src/mapleall/maple_util/include/factory.h index d8ab899e6e4dd783563436a853e7e55ea9ca7e5d..fe97390af3a5ecbcf1d139f2360d1de812344ac9 100644 --- a/src/mapleall/maple_util/include/factory.h +++ b/src/mapleall/maple_util/include/factory.h @@ -17,6 +17,8 @@ #include #include #include +#include +#include "thread_env.h" namespace maple { template @@ -77,6 +79,8 @@ class FunctionFactory final { using creator_type = std::function; void Register(const key_type &key, creator_type func) { + static std::mutex mtx; + ParallelGuard guard(mtx, ThreadEnv::IsMeParallel()); if (creator.find(key) == creator.end()) { creator[key] = func; } diff --git a/src/mapleall/maple_util/include/reflection_list.def b/src/mapleall/maple_util/include/reflection_list.def new file mode 100644 index 0000000000000000000000000000000000000000..3f339ba88b2bb683695282bdcfa2e4f7362ae70c --- /dev/null +++ b/src/mapleall/maple_util/include/reflection_list.def @@ -0,0 +1,30 @@ +"Ljava_2Flang_2FClass_3B_7CfindInterfaceMethod_7C_28Ljava_2Flang_2FString_3BALjava_2Flang_2FClass_3B_29Ljava_2Flang_2Freflect_2FMethod_3B", +"Ljava_2Flang_2FClass_3B_7CgetAccessFlags_7C_28_29I", +"Ljava_2Flang_2FClass_3B_7CgetClasses_7C_28_29ALjava_2Flang_2FClass_3B", +"Ljava_2Flang_2FClass_3B_7CgetClassLoader_7C_28_29Ljava_2Flang_2FClassLoader_3B", +"Ljava_2Flang_2FClass_3B_7CgetComponentType_7C_28_29Ljava_2Flang_2FClass_3B", +"Ljava_2Flang_2FClass_3B_7CgetConstructor_7C_28ALjava_2Flang_2FClass_3B_29Ljava_2Flang_2Freflect_2FConstructor_3B", +"Ljava_2Flang_2FClass_3B_7CgetConstructors_7C_28_29ALjava_2Flang_2Freflect_2FConstructor_3B", +"Ljava_2Flang_2FClass_3B_7CgetDeclaredConstructor_7C_28ALjava_2Flang_2FClass_3B_29Ljava_2Flang_2Freflect_2FConstructor_3B", +"Ljava_2Flang_2FClass_3B_7CgetDeclaredConstructors_7C_28_29ALjava_2Flang_2Freflect_2FConstructor_3B", +"Ljava_2Flang_2FClass_3B_7CgetDeclaredMethod_7C_28Ljava_2Flang_2FString_3BALjava_2Flang_2FClass_3B_29Ljava_2Flang_2Freflect_2FMethod_3B", +"Ljava_2Flang_2FClass_3B_7CgetDeclaredMethods_7C_28_29ALjava_2Flang_2Freflect_2FMethod_3B", +"Ljava_2Flang_2FClass_3B_7CgetField_7C_28Ljava_2Flang_2FString_3B_29Ljava_2Flang_2Freflect_2FField_3B", +"Ljava_2Flang_2FClass_3B_7CgetFields_7C_28_29ALjava_2Flang_2Freflect_2FField_3B", +"Ljava_2Flang_2FClass_3B_7CgetInstanceMethod_7C_28Ljava_2Flang_2FString_3BALjava_2Flang_2FClass_3B_29Ljava_2Flang_2Freflect_2FMethod_3B", +"Ljava_2Flang_2FClass_3B_7CgetInterfaces_7C_28_29ALjava_2Flang_2FClass_3B", +"Ljava_2Flang_2FClass_3B_7CgetMethod_7C_28Ljava_2Flang_2FString_3BALjava_2Flang_2FClass_3B_29Ljava_2Flang_2Freflect_2FMethod_3B", +"Ljava_2Flang_2FClass_3B_7CgetMethods_7C_28_29ALjava_2Flang_2Freflect_2FMethod_3B", +"Ljava_2Flang_2FClass_3B_7CgetModifiers_7C_28_29I", +"Ljava_2Flang_2FClass_3B_7CgetName_7C_28_29Ljava_2Flang_2FString_3B", +"Ljava_2Flang_2FClass_3B_7CgetPublicFieldsRecursive_7C_28Ljava_2Futil_2FList_3B_29V", +"Ljava_2Flang_2FClass_3B_7CgetPublicMethodsInternal_7C_28Ljava_2Futil_2FList_3B_29V", +"Ljava_2Flang_2FClass_3B_7CgetSuperclass_7C_28_29Ljava_2Flang_2FClass_3B", +"Ljava_2Flang_2FClass_3B_7CisAssignableFrom_7C_28Ljava_2Flang_2FClass_3B_29Z", +"Ljava_2Flang_2FClass_3B_7CisInterface_7C_28_29Z", +"Ljava_2Flang_2FClass_3B_7CisPrimitive_7C_28_29Z", +"Ljava_2Flang_2FClass_3B_7CisProxy_7C_28_29Z", +"Ljava_2Flang_2FClass_3B_7CisMemberClass_7C_28_29Z", +"Ljava_2Flang_2FClass_3B_7CisLocalClass_7C_28_29Z", +"Ljava_2Flang_2Fref_2FReference_3B_7Cget_7C_28_29Ljava_2Flang_2FObject_3B", +"Ljava_2Flang_2Fref_2FReference_3B_7Cclear_7C_28_29V", diff --git a/src/mapleall/maple_util/include/white_list.def b/src/mapleall/maple_util/include/white_list.def new file mode 100644 index 0000000000000000000000000000000000000000..7ea27fede38d15e6317f912915c2880a3aac8d00 --- /dev/null +++ b/src/mapleall/maple_util/include/white_list.def @@ -0,0 +1,496 @@ +/* + * Copyright (c) [2019-2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ +CLASS_PREFIX(Ljava_2Flang_2FOutOfMemoryError_3B) +CLASS_PREFIX(Ljava_2Flang_2FThreadGroup_3B) +CLASS_PREFIX(Ljava_2Flang_2FThread_3B) +CLASS_PREFIX(Llibcore_2Futil_2FEmptyArray_3B) +CLASS_PREFIX(Ljava_2Futil_2FCollections_3B) +CLASS_PREFIX(Ljava_2Flang_2FFloat_3B) +CLASS_PREFIX(Ljava_2Fnio_2FDirectByteBuffer_3B) +CLASS_PREFIX(Ldalvik_2Fsystem_2FVMRuntime_3B) +CLASS_PREFIX(Ljava_2Futil_2FProperties_3B) +CLASS_PREFIX(Ljava_2Flang_2FDouble_3B) +CLASS_PREFIX(Ljava_2Flang_2FMath_3B) +CLASS_PREFIX(Llibcore_2Fio_2FLibcore_3B) +CLASS_PREFIX(Llibcore_2Ficu_2FICU_3B) +CLASS_PREFIX(Ljava_2Flang_2FAndroidHardcodedSystemProperties_3B) +CLASS_PREFIX(Ljava_2Flang_2Fref_2FReferenceQueue_3B) +CLASS_PREFIX(Ljava_2Futil_2FArrayList_3B) +CLASS_PREFIX(Ljava_2Flang_2FRuntime_3B) +CLASS_PREFIX(Landroid_2Fsystem_2FOsConstants_3B) +CLASS_PREFIX(Ljava_2Flang_2FInteger_3B) +CLASS_PREFIX(Lsun_2Fmisc_2FUnsafe_3B) +//CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2FConcurrentHashMap_3B) +//CLASS_PREFIX(Lsun_2Futil_2Flocale_2FBaseLocale_3B) +CLASS_PREFIX(Lsun_2Futil_2Flocale_2FBaseLocale_24Key_3B) +//CLASS_PREFIX(Ljava_2Futil_2FLocale_3B) +CLASS_PREFIX(Lsun_2Futil_2Flocale_2FLanguageTag_3B) +CLASS_PREFIX(Lsun_2Futil_2Flocale_2FInternalLocaleBuilder_3B) +CLASS_PREFIX(Lsun_2Fmisc_2FVersion_3B) +CLASS_PREFIX(Ljava_2Fio_2FFileDescriptor_3B) +CLASS_PREFIX(Ldalvik_2Fsystem_2FCloseGuard_3B) +CLASS_PREFIX(Ljava_2Flang_2FEnum_3B) +CLASS_PREFIX(Llibcore_2Fio_2FIoTracker_24Mode_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicReferenceFieldUpdater_24AtomicReferenceFieldUpdaterImpl_3B) +CLASS_PREFIX(Ljava_2Fio_2FBufferedInputStream_3B) +CLASS_PREFIX(Lsun_2Fmisc_2FVM_3B) +CLASS_PREFIX(Ljava_2Flang_2FSystem_3B) +CLASS_PREFIX(Ljava_2Fio_2FFileSystem_3B) +CLASS_PREFIX(Ljava_2Fio_2FUnixFileSystem_3B) +CLASS_PREFIX(Ljava_2Fio_2FFile_3B) +CLASS_PREFIX(Ljava_2Futil_2Fregex_2FPattern_3B) +CLASS_PREFIX(Ljava_2Fio_2FFile_24PathStatus_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicInteger_3B) +CLASS_PREFIX(Ljava_2Flang_2FThreadLocal_3B) +CLASS_PREFIX(Ldalvik_2Fsystem_2FBlockGuard_3B) +CLASS_PREFIX(Ljava_2Flang_2FString_3B) +CLASS_PREFIX(Ldalvik_2Fsystem_2FBaseDexClassLoader_3B) +CLASS_PREFIX(Ljava_2Flang_2FClassLoader_24SystemClassLoader_3B) +CLASS_PREFIX(Ljava_2Flang_2FByte_3B) +CLASS_PREFIX(Ljava_2Flang_2FInteger_24IntegerCache_3B) +CLASS_PREFIX(Ljava_2Futil_2FUUID_3B) +CLASS_PREFIX(Ljava_2Futil_2FHashSet_3B) +CLASS_PREFIX(Lsun_2Fnio_2Fcs_2FStreamDecoder_3B) +CLASS_PREFIX(Ljava_2Fnio_2Fcharset_2FCharset_3B) +CLASS_PREFIX(Llibcore_2Ficu_2FNativeConverter_3B) +CLASS_PREFIX(Ljava_2Fnio_2Fcharset_2FCodingErrorAction_3B) +CLASS_PREFIX(Lsun_2Fmisc_2FCleaner_3B) +CLASS_PREFIX(Ljava_2Fnio_2FByteOrder_3B) +CLASS_PREFIX(Ljava_2Fnio_2FBits_3B) +CLASS_PREFIX(Ljava_2Fio_2FBufferedReader_3B) +CLASS_PREFIX(Ljava_2Fnio_2Fcharset_2FCoderResult_3B) +CLASS_PREFIX(Ljava_2Flang_2FLong_3B) +CLASS_PREFIX(Ljava_2Flang_2FShort_3B) +CLASS_PREFIX(Ljava_2Flang_2FCharacter_3B) +CLASS_PREFIX(Ljava_2Flang_2FBoolean_3B) +CLASS_PREFIX(Ljava_2Flang_2FStringBuffer_3B) +CLASS_PREFIX(Lorg_2Fapache_2Fharmony_2Fdalvik_2Fddmc_2FChunkHandler_3B) +CLASS_PREFIX(Lorg_2Fapache_2Fharmony_2Fdalvik_2Fddmc_2FDdmServer_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicBoolean_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FCacheValue_24Strength_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FCacheValue_3B) +CLASS_PREFIX(Ljava_2Futil_2FLocale_24NoImagePreloadHolder_3B) +CLASS_PREFIX(Landroid_2Ficu_2Futil_2FULocale_24Category_3B) +CLASS_PREFIX(Ljava_2Futil_2FLocale_24Category_3B) +CLASS_PREFIX(Landroid_2Ficu_2Futil_2FULocale_24JDKLocaleHelper_3B) +CLASS_PREFIX(Landroid_2Ficu_2Futil_2FULocale_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FDecimalFormatSymbols_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FNumberingSystem_3B) +CLASS_PREFIX(Ljava_2Futil_2FResourceBundle_3B) +CLASS_PREFIX(Landroid_2Ficu_2Futil_2FUResourceBundle_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2FConcurrentHashMap_24TreeBin_3B) +CLASS_PREFIX(Landroid_2Ficu_2Futil_2FVersionInfo_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FICUDebug_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FICUResourceBundle_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FICUResourceBundle_24OpenType_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FICUResourceBundleReader_3B) +CLASS_PREFIX(Ljava_2Fnet_2FURI_3B) +CLASS_PREFIX(Ljava_2Futil_2Fzip_2FZipFile_3B) +CLASS_PREFIX(Ljava_2Futil_2Fjar_2FJarFile_3B) +CLASS_PREFIX(Ljava_2Fnio_2Fcharset_2FStandardCharsets_3B) +CLASS_PREFIX(Ljava_2Futil_2FWeakHashMap_3B) +CLASS_PREFIX(Ljava_2Futil_2FArrayDeque_3B) +CLASS_PREFIX(Ljava_2Flang_2FVMClassLoader_3B) +CLASS_PREFIX(Ljava_2Fnio_2Fcharset_2FCharsetEncoder_3B) +CLASS_PREFIX(Ljava_2Fnio_2Fcharset_2FCharsetEncoderICU_3B) +CLASS_PREFIX(Ljava_2Futil_2FBitSet_3B) +CLASS_PREFIX(Lsun_2Fnet_2Fwww_2FParseUtil_3B) +CLASS_PREFIX(Ljava_2Fnet_2FURL_3B) +CLASS_PREFIX(Ljava_2Flang_2FCaseMapper_3B) +CLASS_PREFIX(Ljava_2Fnet_2FURLConnection_3B) +CLASS_PREFIX(Ljava_2Futil_2Fzip_2FInflater_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FICUConfig_3B) +CLASS_PREFIX(Ljava_2Fnio_2Fchannels_2FFileChannel_3B) +CLASS_PREFIX(Lsun_2Fnio_2Fch_2FFileChannelImpl_3B) +CLASS_PREFIX(Lsun_2Fnio_2Fch_2FNativeThreadSet_3B) +CLASS_PREFIX(Ljava_2Fnio_2Fchannels_2FFileChannel_24MapMode_3B) +CLASS_PREFIX(Lsun_2Fnio_2Fch_2FFileChannelImpl_24Unmapper_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FICUBinary_24DatPackageReader_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FICUBinary_3B) +CLASS_PREFIX(Ljava_2Fnio_2FByteBufferAsCharBuffer_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FICUResourceBundleReader_24ResourceCache_3B) +CLASS_PREFIX(Landroid_2Ficu_2Futil_2FUResourceBundle_24RootType_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FUResource_24Key_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FCurrencyData_3B) +CLASS_PREFIX(Ljava_2Futil_2FTreeSet_3B) +CLASS_PREFIX(Ljava_2Futil_2FTreeMap_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FBMPSet_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FUnicodeSet_3B) +CLASS_PREFIX(Landroid_2Ficu_2Futil_2FMeasureUnit_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FLocaleIDs_3B) +CLASS_PREFIX(Landroid_2Ficu_2Futil_2FCurrency_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2Flocale_2FBaseLocale_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FUtility_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FCurrencyMetaInfo_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FCurrencyMetaInfo_24CurrencyFilter_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FCurrencyData_24CurrencySpacingInfo_24SpacingType_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FCurrencyData_24CurrencySpacingInfo_24SpacingPattern_3B) +CLASS_PREFIX(Ljava_2Flang_2FVoid_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FCurrencyData_24CurrencySpacingInfo_3B) +CLASS_PREFIX(Ljava_2Flang_2FThread_24State_3B) +CLASS_PREFIX(Llibcore_2Freflect_2FAnnotationMember_24DefaultValues_3B) +CLASS_PREFIX(Llibcore_2Freflect_2FAnnotationMember_3B) +CLASS_PREFIX(Ljava_2Flang_2Fannotation_2FAnnotation_3B) +CLASS_PREFIX(Llibcore_2Freflect_2FAnnotationFactory_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicLong_3B) +//CLASS_PREFIX(Ljava_2Flang_2Freflect_2FProxy_24ProxyClassFactory_3B) +CLASS_PREFIX(Ljava_2Flang_2Freflect_2FProxy_3B) +//CLASS_PREFIX(Ljava_2Flang_2Freflect_2FWeakCache_24CacheKey_3B) +CLASS_PREFIX(Ljava_2Flang_2Freflect_2FWeakCache_24Factory_3B) +CLASS_PREFIX(Ljava_2Futil_2FTimSort_3B) +CLASS_PREFIX(Ljava_2Flang_2Freflect_2FMethod_3B) +CLASS_PREFIX(Ljava_2Futil_2FHashMap_24TreeNode_3B) +CLASS_PREFIX(Ljava_2Futil_2FCollections_24EmptyIterator_3B) +CLASS_PREFIX(Landroid_2Ficu_2Flang_2FUScript_24ScriptUsage_3B) +CLASS_PREFIX(Landroid_2Ficu_2Flang_2FUScript_3B) +CLASS_PREFIX(Ljava_2Fnio_2FByteBufferAsIntBuffer_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FUPropertyAliases_3B) +CLASS_PREFIX(Landroid_2Ficu_2Futil_2FBytesTrie_24Result_3B) +CLASS_PREFIX(Landroid_2Ficu_2Flang_2FUScript_24ScriptMetadata_3B) +CLASS_PREFIX(Lorg_2Fxmlpull_2Fv1_2FXmlPullParser_3B) +//CLASS_PREFIX(Lorg_2Fkxml2_2Fio_2FKXmlParser_3B) +//CLASS_PREFIX(Lorg_2Fkxml2_2Fio_2FKXmlParser_24ValueContext_3B) +CLASS_PREFIX(Ljava_2Futil_2Fregex_2FMatcher_3B) +CLASS_PREFIX(Lsun_2Fmisc_2FFloatingDecimal_24ExceptionalBinaryToASCIIBuffer_3B) +CLASS_PREFIX(Lsun_2Fmisc_2FFloatingDecimal_24BinaryToASCIIBuffer_3B) +CLASS_PREFIX(Lsun_2Fmisc_2FFloatingDecimal_3B) +CLASS_PREFIX(Lsun_2Fmisc_2FFloatingDecimal_24ASCIIToBinaryBuffer_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FCaseMapImpl_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FTrie_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FCharTrie_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FICUCache_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FICUResourceBundleReader_24ResourceCache_24Level_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FICUService_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FStringPrep_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FStringPrepDataReader_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FTrie2_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FTrie2_24ValueWidth_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FUCharacterProperty_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FUBiDiProps_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FIDNA2003_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FNorm2AllModes_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FNormalizer2Impl_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FNorm2AllModes_24NFKCSingleton_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FPatternProps_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FStandardPlural_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FPluralRulesLoader_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2FUCaseProps_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fmath_2FMathContext_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fmath_2FBigDecimal_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FBreakIterator_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2Flocks_2FReentrantReadWriteLock_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2Flocks_2FAbstractQueuedSynchronizer_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FBreakIteratorFactory_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FCaseMap_24Upper_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FNumberFormat_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FDecimalFormat_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FDisplayContext_24Type_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FDisplayContext_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FNormalizer_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FNormalizer_24NFKDModeImpl_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FNumberFormat_24Field_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FPluralRules_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FPluralRules_24Operand_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FPluralRules_24PluralType_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FPluralRules_24SampleType_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FPluralRules_24SimpleTokenizer_3B) +//CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FRBBIDataWrapper_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FRuleBasedBreakIterator_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FRuleBasedBreakIterator_24LookAheadResults_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FStringPrepParseException_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FTimeZoneNames_24NameType_3B) +CLASS_PREFIX(Landroid_2Ficu_2Futil_2FCurrency_24CurrencyUsage_3B) +CLASS_PREFIX(Ljava_2Futil_2FEnumMap_3B) +//CLASS_PREFIX(Lsun_2Fnet_2Fspi_2FDefaultProxySelector_3B) +CLASS_PREFIX(Ljava_2Fnet_2FProxySelector_3B) +CLASS_PREFIX(Ljavax_2Fnet_2Fssl_2FSSLSocketFactory_3B) +CLASS_PREFIX(Landroid_2Fsystem_2FUnixSocketAddress_3B) +CLASS_PREFIX(Ljava_2Flang_2FLong_24LongCache_3B) +CLASS_PREFIX(Ljava_2Futil_2Flogging_2FLevel_24KnownLevel_3B) +CLASS_PREFIX(Ljava_2Futil_2Flogging_2FLevel_3B) +CLASS_PREFIX(Ljava_2Futil_2Flogging_2FHandler_3B) +CLASS_PREFIX(Ljava_2Flang_2Fref_2FReference_3B) +CLASS_PREFIX(Ljava_2Flang_2Fref_2FWeakReference_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2FTimeUnit_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2FCopyOnWriteArrayList_3B) +CLASS_PREFIX(Llibcore_2Fnet_2Fevent_2FNetworkEventDispatcher_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2FAbstractExecutorService_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2FThreadPoolExecutor_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicReference_3B) +CLASS_PREFIX(Ljava_2Fnet_2FHttpURLConnection_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Futil_2FDebug_3B) +CLASS_PREFIX(Ljava_2Fsecurity_2FProvider_3B) +CLASS_PREFIX(Ljava_2Futil_2FCalendar_3B) +CLASS_PREFIX(Ldalvik_2Fsystem_2FSocketTagger_3B) +CLASS_PREFIX(Ldalvik_2Fsystem_2FVMDebug_3B) +CLASS_PREFIX(Ljava_2Fio_2FConsole_3B) +CLASS_PREFIX(Ljava_2Fio_2FObjectStreamConstants_3B) +CLASS_PREFIX(Ljava_2Fio_2FObjectInputStream_3B) +CLASS_PREFIX(Ljava_2Fio_2FObjectStreamClass_3B) +CLASS_PREFIX(Ljava_2Flang_2FByte_24ByteCache_3B) +CLASS_PREFIX(Ljava_2Flang_2FCharacter_24CharacterCache_3B) +CLASS_PREFIX(Ljava_2Flang_2FCharacter_24UnicodeBlock_3B) +CLASS_PREFIX(Ljava_2Flang_2FClass_24Caches_3B) +CLASS_PREFIX(Ljava_2Flang_2Fref_2FFinalizerReference_3B) +CLASS_PREFIX(Ljava_2Flang_2FDaemons_24FinalizerDaemon_3B) +CLASS_PREFIX(Ljava_2Flang_2FDaemons_24FinalizerWatchdogDaemon_3B) +CLASS_PREFIX(Ljava_2Flang_2FDaemons_24HeapTaskDaemon_3B) +CLASS_PREFIX(Ljava_2Flang_2FDaemons_24ReferenceQueueDaemon_3B) +CLASS_PREFIX(Ljava_2Futil_2FRandom_3B) +CLASS_PREFIX(Ljava_2Flang_2FMath_24RandomNumberGeneratorHolder_3B) +CLASS_PREFIX(Ljava_2Flang_2FPackage_3B) +CLASS_PREFIX(Ljava_2Flang_2FProcessBuilder_3B) +CLASS_PREFIX(Ljava_2Flang_2FProcessEnvironment_3B) +CLASS_PREFIX(Ljava_2Flang_2FShort_24ShortCache_3B) +CLASS_PREFIX(Ljava_2Flang_2FStrictMath_3B) +CLASS_PREFIX(Ljava_2Flang_2FThread_24Caches_3B) +CLASS_PREFIX(Ljava_2Flang_2FThrowable_24SentinelHolder_3B) +CLASS_PREFIX(Ljava_2Flang_2FUNIXProcess_24ProcessReaperThreadFactory_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2FSynchronousQueue_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2FSynchronousQueue_24TransferStack_3B) +CLASS_PREFIX(Ljava_2Flang_2FUNIXProcess_3B) +CLASS_PREFIX(Ljava_2Flang_2Finvoke_2FMethodHandleStatics_3B) +CLASS_PREFIX(Ljava_2Flang_2Finvoke_2FCallSite_3B) +CLASS_PREFIX(Ljava_2Flang_2Finvoke_2FMethodHandle_3B) +CLASS_PREFIX(Ljava_2Flang_2Finvoke_2FMethodHandles_24Lookup_3B) +CLASS_PREFIX(Ljava_2Flang_2Finvoke_2FMethodType_3B) +CLASS_PREFIX(Ljava_2Flang_2Finvoke_2FMethodTypeForm_3B) +CLASS_PREFIX(Ljava_2Flang_2Freflect_2FMethod_241_3B) +CLASS_PREFIX(Llibcore_2Fmath_2FMathUtils_3B) +CLASS_PREFIX(Ljava_2Fmath_2FBigInt_3B) +CLASS_PREFIX(Ljava_2Fmath_2FBigInteger_3B) +CLASS_PREFIX(Ljava_2Fmath_2FMultiplication_3B) +CLASS_PREFIX(Ljava_2Fmath_2FBigDecimal_3B) +CLASS_PREFIX(Ljava_2Fmath_2FRoundingMode_3B) +CLASS_PREFIX(Ljava_2Fnet_2FInet6AddressImpl_3B) +CLASS_PREFIX(Ljava_2Fnet_2FInetAddress_3B) +CLASS_PREFIX(Ljava_2Fnet_2FInet4Address_3B) +CLASS_PREFIX(Ljava_2Fnet_2FInet6Address_3B) +CLASS_PREFIX(Ljava_2Fnet_2FInetSocketAddress_3B) +CLASS_PREFIX(Ljava_2Fnet_2FNetworkInterface_3B) +CLASS_PREFIX(Ljava_2Fnet_2FProxy_24Type_3B) +CLASS_PREFIX(Ljava_2Fnet_2FProxy_3B) +CLASS_PREFIX(Ljava_2Fnet_2FServerSocket_3B) +CLASS_PREFIX(Ljava_2Fnet_2FSocket_3B) +CLASS_PREFIX(Ljava_2Fnet_2FSocksSocketImpl_3B) +CLASS_PREFIX(Ljava_2Fnet_2FURLEncoder_3B) +CLASS_PREFIX(Ljava_2Fnio_2FByteBufferAsDoubleBuffer_3B) +CLASS_PREFIX(Ljava_2Fnio_2FByteBufferAsFloatBuffer_3B) +CLASS_PREFIX(Ljava_2Fnio_2FByteBufferAsLongBuffer_3B) +CLASS_PREFIX(Ljava_2Fnio_2FByteBufferAsShortBuffer_3B) +CLASS_PREFIX(Ljava_2Fnio_2Fchannels_2Fspi_2FAbstractSelectableChannel_3B) +CLASS_PREFIX(Ljava_2Fnio_2Fchannels_2FSocketChannel_3B) +CLASS_PREFIX(Ljava_2Fnio_2Fcharset_2FCharsetDecoder_3B) +CLASS_PREFIX(Ljava_2Fsecurity_2FCryptoPrimitive_3B) +CLASS_PREFIX(Ljava_2Fsecurity_2FKeyFactory_3B) +CLASS_PREFIX(Ljava_2Fsecurity_2FProvider_24Service_3B) +CLASS_PREFIX(Ljava_2Fsecurity_2FSecureRandom_3B) +CLASS_PREFIX(Ljava_2Fsecurity_2FSecurity_3B) +CLASS_PREFIX(Ljava_2Fsecurity_2FSignature_3B) +CLASS_PREFIX(Ljava_2Fsecurity_2FSignature_24Delegate_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Futil_2FObjectIdentifier_3B) +CLASS_PREFIX(Ljava_2Fsecurity_2Fcert_2FX509CertSelector_3B) +CLASS_PREFIX(Ljava_2Fsecurity_2Fspec_2FECPoint_3B) +CLASS_PREFIX(Ljava_2Ftext_2FAttributedCharacterIterator_24Attribute_3B) +CLASS_PREFIX(Ljava_2Ftext_2FDateFormat_24Field_3B) +CLASS_PREFIX(Ljava_2Ftext_2FDateFormatSymbols_3B) +CLASS_PREFIX(Ljava_2Ftext_2FNumberFormat_3B) +CLASS_PREFIX(Ljava_2Ftext_2FDecimalFormat_3B) +CLASS_PREFIX(Ljava_2Ftext_2FDecimalFormatSymbols_3B) +CLASS_PREFIX(Ljava_2Ftext_2FDontCareFieldPosition_3B) +CLASS_PREFIX(Ljava_2Ftext_2FNormalizer_24Form_3B) +CLASS_PREFIX(Ljava_2Futil_2FEnumSet_3B) +CLASS_PREFIX(Ljava_2Ftext_2FSimpleDateFormat_3B) +CLASS_PREFIX(Ljava_2Futil_2FArrays_24NaturalOrder_3B) +CLASS_PREFIX(Ljava_2Futil_2FCollections_24CopiesList_3B) +CLASS_PREFIX(Ljava_2Futil_2FCollections_24EmptyEnumeration_3B) +CLASS_PREFIX(Ljava_2Futil_2FCollections_24EmptyListIterator_3B) +CLASS_PREFIX(Ljava_2Futil_2FCollections_24ReverseComparator_3B) +CLASS_PREFIX(Ljava_2Futil_2FCollections_24ReverseComparator2_3B) +CLASS_PREFIX(Ljava_2Futil_2FCollections_24UnmodifiableNavigableMap_3B) +CLASS_PREFIX(Ljava_2Futil_2FCollections_24UnmodifiableNavigableSet_3B) +CLASS_PREFIX(Ljava_2Futil_2FComparableTimSort_3B) +CLASS_PREFIX(Ljava_2Futil_2FComparators_24NaturalOrderComparator_3B) +CLASS_PREFIX(Ljava_2Futil_2FCurrency_3B) +CLASS_PREFIX(Lsun_2Futil_2Fcalendar_2FCalendarSystem_3B) +CLASS_PREFIX(Ljava_2Futil_2FDate_3B) +CLASS_PREFIX(Ljava_2Futil_2FFormatter_24Flags_3B) +CLASS_PREFIX(Ljava_2Futil_2FFormatter_24FormatSpecifier_3B) +CLASS_PREFIX(Ljava_2Futil_2FGregorianCalendar_3B) +CLASS_PREFIX(Ljava_2Futil_2FLocale_24FilteringMode_3B) +CLASS_PREFIX(Ljava_2Futil_2FSimpleTimeZone_3B) +CLASS_PREFIX(Ljava_2Futil_2FSpliterators_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2FConcurrentLinkedDeque_24Node_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2FConcurrentLinkedDeque_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2FConcurrentLinkedQueue_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2FForkJoinTask_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2FCountedCompleter_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2FExecutors_24DefaultThreadFactory_3B) +// CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2FForkJoinPool_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2FFutureTask_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2FPriorityBlockingQueue_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2FScheduledThreadPoolExecutor_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2FSynchronousQueue_24TransferStack_24SNode_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2FThreadLocalRandom_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2Fatomic_2FAtomicReferenceArray_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2Flocks_2FAbstractQueuedSynchronizer_24Node_3B) +CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2Flocks_2FLockSupport_3B) +CLASS_PREFIX(Ljava_2Futil_2Flogging_2FLogManager_24LoggerContext_3B) +//CLASS_PREFIX(Ljava_2Futil_2Flogging_2FLogManager_3B) +CLASS_PREFIX(Ljava_2Futil_2Flogging_2FLogManager_242_3B) +CLASS_PREFIX(Ljava_2Futil_2Flogging_2FLogRecord_3B) +CLASS_PREFIX(Ljava_2Futil_2Flogging_2FLogger_3B) +CLASS_PREFIX(Ljava_2Futil_2Flogging_2FLoggingProxyImpl_3B) +CLASS_PREFIX(Ljava_2Futil_2Fprefs_2FPreferences_3B) +CLASS_PREFIX(Ljava_2Futil_2Fprefs_2FAbstractPreferences_3B) +//CLASS_PREFIX(Ljava_2Futil_2Fprefs_2FFileSystemPreferences_3B) +CLASS_PREFIX(Ljava_2Futil_2Fregex_2FPatternSyntaxException_3B) +CLASS_PREFIX(Ljava_2Futil_2Fstream_2FAbstractPipeline_3B) +CLASS_PREFIX(Ljava_2Futil_2Fstream_2FStreamOpFlag_24Type_3B) +CLASS_PREFIX(Ljava_2Futil_2Fstream_2FStreamOpFlag_3B) +CLASS_PREFIX(Ljava_2Futil_2Fstream_2FStreamShape_3B) +CLASS_PREFIX(Ljava_2Futil_2Fzip_2FAdler32_3B) +CLASS_PREFIX(Ljava_2Futil_2Fzip_2FCRC32_3B) +CLASS_PREFIX(Ljava_2Futil_2Fzip_2FDeflater_3B) +CLASS_PREFIX(Ljavax_2Fcrypto_2FCipher_24InitType_3B) +CLASS_PREFIX(Ljavax_2Fcrypto_2FCipher_24NeedToSet_3B) +CLASS_PREFIX(Ljavax_2Fnet_2Fssl_2FHttpsURLConnection_3B) +CLASS_PREFIX(Ljavax_2Fnet_2Fssl_2FSNIServerName_3B) +CLASS_PREFIX(Ljavax_2Fnet_2Fssl_2FSSLServerSocketFactory_3B) +CLASS_PREFIX(Ljavax_2Fsecurity_2Fcert_2FX509Certificate_3B) +CLASS_PREFIX(Llibcore_2Ficu_2FLocaleData_3B) +//CLASS_PREFIX(Llibcore_2Fio_2FDropBox_3B) +//CLASS_PREFIX(Llibcore_2Fio_2FEventLogger_3B) +CLASS_PREFIX(Llibcore_2Fnet_2FNetworkSecurityPolicy_3B) +CLASS_PREFIX(Llibcore_2Freflect_2FListOfTypes_3B) +CLASS_PREFIX(Llibcore_2Freflect_2FTypes_3B) +CLASS_PREFIX(Llibcore_2Futil_2FZoneInfo_3B) +CLASS_PREFIX(Lorg_2Fapache_2Fharmony_2Fxml_2FExpatParser_3B) +CLASS_PREFIX(Lorg_2Fjson_2FJSONObject_3B) +CLASS_PREFIX(Lorg_2Fjson_2FJSONStringer_24Scope_3B) +CLASS_PREFIX(Lsun_2Finvoke_2Futil_2FVerifyAccess_3B) +CLASS_PREFIX(Lsun_2Finvoke_2Futil_2FWrapper_24Format_3B) +CLASS_PREFIX(Lsun_2Finvoke_2Futil_2FWrapper_3B) +CLASS_PREFIX(Lsun_2Fmisc_2FFDBigInteger_3B) +CLASS_PREFIX(Lsun_2Fmisc_2FFormattedFloatingDecimal_3B) +CLASS_PREFIX(Lsun_2Fmisc_2FFormattedFloatingDecimal_24Form_3B) +CLASS_PREFIX(Lsun_2Fnet_2Fspi_2FDefaultProxySelector_24NonProxyInfo_3B) +CLASS_PREFIX(Lsun_2Fnio_2Fch_2FDatagramChannelImpl_3B) +CLASS_PREFIX(Lsun_2Fnio_2Fch_2FFileLockImpl_3B) +CLASS_PREFIX(Lsun_2Fnio_2Fch_2FIOUtil_3B) +CLASS_PREFIX(Lsun_2Fnio_2Fch_2FNet_3B) +CLASS_PREFIX(Lsun_2Fnio_2Fch_2FServerSocketChannelImpl_3B) +CLASS_PREFIX(Lsun_2Fnio_2Fch_2FSharedFileLockTable_3B) +CLASS_PREFIX(Lsun_2Fnio_2Fch_2FSocketChannelImpl_3B) +CLASS_PREFIX(Lsun_2Fnio_2Fch_2FUtil_3B) +CLASS_PREFIX(Lsun_2Fnio_2Fch_2FUtil_24BufferCache_3B) +CLASS_PREFIX(Lsun_2Fnio_2Fcs_2FStreamEncoder_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fjca_2FProviderConfig_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fjca_2FProviderList_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fx509_2FCertificateExtensions_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fpkcs_2FPKCS9Attribute_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Futil_2FDisabledAlgorithmConstraints_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Futil_2FAlgorithmDecomposer_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Futil_2FDisabledAlgorithmConstraints_24Constraints_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fpkcs_2FSignerInfo_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fprovider_2FX509Factory_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fprovider_2Fcertpath_2FAdaptableX509CertSelector_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Futil_2FDisabledAlgorithmConstraints_24Constraint_24Operator_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fprovider_2Fcertpath_2FBasicChecker_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fprovider_2Fcertpath_2FConstraintsChecker_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fprovider_2Fcertpath_2FKeyChecker_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fprovider_2Fcertpath_2FPKIX_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fprovider_2Fcertpath_2FPKIXCertPathValidator_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fprovider_2Fcertpath_2FPKIXMasterCertPathValidator_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fprovider_2Fcertpath_2FPolicyChecker_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Futil_2FBitArray_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Futil_2FDerOutputStream_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fx509_2FAVA_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fx509_2FX500Name_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fx509_2FAVAKeyword_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fx509_2FAccessDescription_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fx509_2FAlgorithmId_3B) +CLASS_PREFIX(Ljava_2Fsecurity_2Fcert_2FCRLReason_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fx509_2FCRLReasonCodeExtension_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fx509_2FDistributionPoint_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fx509_2FExtendedKeyUsageExtension_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fx509_2FInhibitAnyPolicyExtension_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fx509_2FNetscapeCertTypeExtension_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fx509_2FPKIXExtensions_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fx509_2FOIDMap_3B) +CLASS_PREFIX(Lsun_2Fsecurity_2Fx509_2FX509CertInfo_3B) +CLASS_PREFIX(Lsun_2Futil_2Fcalendar_2FBaseCalendar_3B) +CLASS_PREFIX(Lsun_2Futil_2Flogging_2FLoggingSupport_3B) +CLASS_PREFIX(Lsun_2Futil_2Flogging_2FPlatformLogger_24Level_3B) +CLASS_PREFIX(Lsun_2Futil_2Flogging_2FPlatformLogger_3B) +CLASS_PREFIX(Ljava_2Fio_2FBufferedWriter_3B) +//CLASS_PREFIX(Lsun_2Fsecurity_2Fjca_2FProviders_3B) +//CLASS_PREFIX(Ljava_2Futil_2Fconcurrent_2FCompletableFuture_3B) +CLASS_PREFIX(Ljava_2Futil_2FScanner_3B) +CLASS_PREFIX(Ljava_2Futil_2Fstream_2FCollectors_3B) +CLASS_PREFIX(Ljava_2Futil_2Fstream_2FNodes_3B) +CLASS_PREFIX(Ljava_2Futil_2Fstream_2FReferencePipeline_3B) +CLASS_PREFIX(Ljava_2Futil_2FTaskQueue_3B) +CLASS_PREFIX(Ljava_2Futil_2FTimer_3B) +CLASS_PREFIX(Ljava_2Futil_2FTimerThread_3B) +//CLASS_PREFIX(Ljavax_2Fcrypto_2FJceSecurity_3B) +CLASS_PREFIX(Ljavax_2Fnet_2Fssl_2FSNIHostName_3B) +CLASS_PREFIX(Ljavax_2Fxml_2Fparsers_2FFilePathToURI_3B) +//CLASS_PREFIX(Llibcore_2Ficu_2FTimeZoneNames_3B) +CLASS_PREFIX(Llibcore_2Futil_2FHexEncoding_3B) +CLASS_PREFIX(Lorg_2Fapache_2Fharmony_2Fxml_2Fdom_2FCommentImpl_3B) +CLASS_PREFIX(Lorg_2Fapache_2Fharmony_2Fxml_2Fdom_2FDocumentImpl_3B) +CLASS_PREFIX(Lorg_2Fapache_2Fharmony_2Fxml_2Fdom_2FDocumentTypeImpl_3B) +CLASS_PREFIX(Lorg_2Fapache_2Fharmony_2Fxml_2Fdom_2FElementImpl_3B) +CLASS_PREFIX(Lorg_2Fapache_2Fharmony_2Fxml_2Fdom_2FTextImpl_3B) +CLASS_PREFIX(Lorg_2Fapache_2Fharmony_2Fxml_2Fparsers_2FDocumentBuilderImpl_3B) +CLASS_PREFIX(Lsun_2Fnet_2FNetProperties_3B) +CLASS_PREFIX(Lsun_2Fnet_2FProgressMonitor_3B) +CLASS_PREFIX(Lsun_2Fnet_2Fwww_2Fprotocol_2Ffile_2FFileURLConnection_3B) +CLASS_PREFIX(Lsun_2Fnio_2Ffs_2FNativeBuffer_3B) +CLASS_PREFIX(Lsun_2Fnio_2Ffs_2FNativeBuffers_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2Fcoll_2FCollationData_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2Fcoll_2FCollationDataReader_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2Fcoll_2FCollationFastLatin_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2Fcoll_2FCollationLoader_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2Fcoll_2FCollationRoot_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2Fcoll_2FCollationSettings_3B) +CLASS_PREFIX(Landroid_2Ficu_2Fimpl_2Fcoll_2FCollationTailoring_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FCollator_3B) +//CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FDigitList_3B) +CLASS_PREFIX(Landroid_2Ficu_2Ftext_2FRuleBasedCollator_3B) +CLASS_PREFIX(Landroid_2Ficu_2Futil_2FBytesTrie_3B) +CLASS_PREFIX(Landroid_2Ficu_2Futil_2FTimeUnit_3B) +CLASS_PREFIX(Ldalvik_2Fsystem_2FPathClassLoader_3B) +CLASS_PREFIX(Ljava_2Ftext_2FMessageFormat_3B) +CLASS_PREFIX(Llibcore_2Fio_2FStreams_3B) +CLASS_PREFIX(Lsun_2Fnio_2Ffs_2FUnixNativeDispatcher_3B) +CLASS_PREFIX(Lsun_2Fnio_2Ffs_2FUnixPath_3B) +CLASS_PREFIX(Lsun_2Fnio_2Ffs_2FUtil_3B) +CLASS_PREFIX(Lsun_2Futil_2Fcalendar_2FGregorian_3B) +CLASS_PREFIX(Ljava_2Flang_2FInheritableThreadLocal_3B) +CLASS_PREFIX(Ljava_2Flang_2Fref_2FPhantomReference_3B) +CLASS_PREFIX(Ljava_2Fnio_2Fcharset_2FCharsetDecoderICU_3B) +CLASS_PREFIX(Ljava_2Fnio_2Ffile_2FFiles_3B) +CLASS_PREFIX(Ljava_2Futil_2FIdentityHashMap_3B) +CLASS_PREFIX(Ljava_2Futil_2FLinkedHashSet_3B) +CLASS_PREFIX(Ljava_2Futil_2FRegularEnumSet_3B) +//CLASS_PREFIX(Llibcore_2Futil_2FZoneInfoDB_3B) +//CLASS_PREFIX(Ljava_2Flang_2FBootClassLoader_3B) +CLASS_PREFIX(Ljava_2Flang_2Finvoke_2FMethodType_3B) +CLASS_PREFIX(Ldalvik_2Fsystem_2FEmulatedStackFrame_3B) +CLASS_PREFIX(Ljava_2Flang_2FStringFactory_3B) +CLASS_PREFIX(Ljava_2Flang_2FNumber_3B) +CLASS_PREFIX(Ljava_2Futil_2FHashMap_3B) diff --git a/src/mapleall/maple_util/src/profile.cpp b/src/mapleall/maple_util/src/profile.cpp index ccfdfe9af5cb11da9069745c258d6a92b4b6fdd4..aa653705ae3def879f4399a0077557df37676df7 100644 --- a/src/mapleall/maple_util/src/profile.cpp +++ b/src/mapleall/maple_util/src/profile.cpp @@ -45,6 +45,12 @@ const std::string Profile::preClassHot[] = { "Ljava/lang/String;" }; +#ifndef HUAWEI_EXTERNAL_RELEASE_JBC +const std::string Profile::preMethodHot[] = { + "Landroid/util/ContainerHelpers;", + "Landroid/util/SparseArray;" +}; +#endif Profile::Profile() {} @@ -249,13 +255,20 @@ void Profile::ParseReflectionStr(const char *data, int32 fileNum) { } void Profile::InitPreHot() { +#ifndef HUAWEI_EXTERNAL_RELEASE_JBC + std::string frameworkDexName = "framework"; std::string coreDexName = "core-all"; - if (dexName.find(coreDexName) != std::string::npos) { + if (dexName.find(frameworkDexName) != std::string::npos) { + for (auto &item : preMethodHot) { + methodMeta.insert(item); + } + } else if (dexName.find(coreDexName) != std::string::npos) { for (auto &item : preClassHot) { classMeta.insert(item); } isCoreSo = true; } +#endif } bool Profile::DeCompress(const std::string &path, const std::string &dexNameInner, ProfileType type) { diff --git a/src/mapleall/mempool/src/mempool.cpp b/src/mapleall/mempool/src/mempool.cpp index 69b7ed00a0b429e6765265a99b62d1dff4c700da..ae3b38e2e26a15d69b8a489f17d8376e88b1106f 100644 --- a/src/mapleall/mempool/src/mempool.cpp +++ b/src/mapleall/mempool/src/mempool.cpp @@ -70,6 +70,7 @@ MemPool *MemPoolCtrler::NewMemPool(const std::string &name) { CHECK_FATAL(false, "ERROR: Can't allocate new memory pool"); return nullptr; } + ParallelGuard guard(mtx, HaveRace()); memPools.insert(memPool); return memPool; } @@ -84,6 +85,7 @@ void MemPoolCtrler::DeleteMemPool(MemPool *memPool) { return; } #endif + ParallelGuard guard(mtx, HaveRace()); // Transfer memory blocks to ctrler->freeMemBlocks stack while (!memPool->memBlockStack.empty()) { MemBlock *mb = memPool->memBlockStack.top(); @@ -113,6 +115,7 @@ void MemPoolCtrler::DeleteMemPool(MemPool *memPool) { } void MemPoolCtrler::FreeMem() { + ParallelGuard guard(mtx, HaveRace()); for (MemBlock *block : freeMemBlocks) { free(block); } @@ -141,6 +144,8 @@ MemPool::~MemPool() { // Return a pointer that points to size of memory from memory block void *MemPool::Malloc(size_t size) { + // we use the same mutex as ctrler to avoid MemPool::Malloc and MemPoolCtrler::DeleteMemPool are called meanwhile + ParallelGuard guard(ctrler.mtx, HaveRace()); #ifdef MP_DEBUG // If controller is not set, or the memory pool is invalid if (!IsValid()) { @@ -216,6 +221,7 @@ void *MemPool::Realloc(const void *ptr, size_t oldSize, size_t newSize) { } void MemPool::ReleaseContainingMem() { + ParallelGuard guard(ctrler.mtx, HaveRace()); while (!memBlockStack.empty()) { MemPoolCtrler::MemBlock *block1 = memBlockStack.top(); block1->available = block1->origSize; diff --git a/src/mapleall/mpl2mpl/BUILD.gn b/src/mapleall/mpl2mpl/BUILD.gn index ee7403de134cd9e1e875d4429b4d9a808def611e..5b68cca8de1727eb159e12c0d5c6080a8f242083 100755 --- a/src/mapleall/mpl2mpl/BUILD.gn +++ b/src/mapleall/mpl2mpl/BUILD.gn @@ -27,6 +27,7 @@ include_directories = [ src_libmpl2mpl = [ "src/class_init.cpp", "src/gen_check_cast.cpp", + "src/barrierinsertion.cpp", "src/muid_replacement.cpp", "src/reflection_analysis.cpp", "src/vtable_analysis.cpp", diff --git a/src/mapleall/mpl2mpl/include/barrierinsertion.h b/src/mapleall/mpl2mpl/include/barrierinsertion.h new file mode 100644 index 0000000000000000000000000000000000000000..f7ce34d167a827e5b3dc86810cbdb143c9ad5589 --- /dev/null +++ b/src/mapleall/mpl2mpl/include/barrierinsertion.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) [2020-2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#ifndef MPL2MPL_INCLUDE_BARRIERINSERTION_H +#define MPL2MPL_INCLUDE_BARRIERINSERTION_H +#include +#include "module_phase.h" +#include "mir_nodes.h" +#include "mir_module.h" +#include "mir_builder.h" + +namespace maple { +class BarrierInsertion : public ModulePhase { + public: + explicit BarrierInsertion(ModulePhaseID id) : ModulePhase(id) {} + + ~BarrierInsertion() = default; + + AnalysisResult *Run(MIRModule *module, ModuleResultMgr *m) override; + std::string PhaseName() const override { + return "barrierinsertion"; + } + + private: + class RunFunction; + friend RunFunction; + class RunFunction { + friend BarrierInsertion; + RunFunction(BarrierInsertion &phase, MIRModule &module, MIRFunction &func) + : phase(&phase), mirModule(&module), mirFunc(&func), builder(module.GetMIRBuilder()), backupVarCount(0) {} + + ~RunFunction() = default; + + CallNode *CreateWriteRefVarCall(BaseNode &var, BaseNode &value) const; + CallNode *CreateWriteRefFieldCall(BaseNode &obj, BaseNode &field, BaseNode &value) const; + CallNode *CreateReleaseRefVarCall(BaseNode &var) const; + // MCC_CheckObjMem(address_t obj) + CallNode *CreateMemCheckCall(BaseNode &obj) const; + void HandleBlock(BlockNode &block) const; + StmtNode *HandleStmt(StmtNode &stmt, BlockNode &block) const; + StmtNode *CheckRefRead(BaseNode *opnd, const StmtNode &stmt, BlockNode &block) const; + void InsertPrologue(); + void HandleReturn(const NaryStmtNode &retNode); + MIRSymbol *NewBackupVariable(const std::string &suffix); + void Run(); + std::string PhaseName() const { + return phase->PhaseName(); + } + + bool SkipRHS(const BaseNode &rhs) const; + BarrierInsertion *phase; + MIRModule *mirModule; + MIRFunction *mirFunc; + MIRBuilder *builder; + int backupVarCount; + std::set backupVarIndices; + std::set assignedParams; + std::set rets; // there could be multiple return in the function + }; + + void EnsureLibraryFunction(MIRModule &module, const char &name, const MIRType &retType, const ArgVector &args); + void EnsureLibraryFunctions(MIRModule &module); +}; +} // namespace maple +#endif // MPL2MPL_INCLUDE_BARRIERINSERTION_H diff --git a/src/mapleall/mpl2mpl/include/castcheck_whitelist.def b/src/mapleall/mpl2mpl/include/castcheck_whitelist.def new file mode 100644 index 0000000000000000000000000000000000000000..59ce7a414d41a17c89e96481b58b80f1b68b55cb --- /dev/null +++ b/src/mapleall/mpl2mpl/include/castcheck_whitelist.def @@ -0,0 +1,69 @@ +/* + * Copyright (c) [2021] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under the Mulan PSL v1. + * You can use this software according to the terms and conditions of the Mulan PSL v1. + * You may obtain a copy of Mulan PSL v1 at: + * + * http://license.coscl.org.cn/MulanPSL + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v1 for more details. + */ + +"Lcom_2Fandroid_2Fserver_2Fam_2FActivityManagerService_3B_7CcomputeOomAdjLocked_7C_28Lcom_2Fandroid_2Fserver_2Fam_2FProcessRecord_3BILcom_2Fandroid_2Fserver_2Fam_2FProcessRecord_3BZJ_29I", +"Ldalvik_2Fsystem_2FBlockGuard_3B_7CgetThreadPolicy_7C_28_29Ldalvik_2Fsystem_2FBlockGuard_24Policy_3B", +"Lcom_2Fandroid_2Fserver_2Fpm_2FPermissionsState_3B_7CgetPermissions_7C_28I_29Ljava_2Futil_2FSet_3B", +"Lcom_2Fandroid_2Fserver_2Fam_2FActivityManagerService_3B_7CupdateOomAdjLocked_7C_28_29V", +"Lcom_2Fandroid_2Fserver_2Fcontent_2FContentService_24ObserverNode_3B_7CremoveObserverLocked_7C_28Landroid_2Fdatabase_2FIContentObserver_3B_29Z", +"Lcom_2Fandroid_2Fserver_2Fpm_2FPermissionsState_3B_7ChasPermission_7C_28Ljava_2Flang_2FString_3BI_29Z", +"Landroid_2Fos_2FParcel_3B_7CreadParcelableCreator_7C_28Ljava_2Flang_2FClassLoader_3B_29Landroid_2Fos_2FParcelable_24Creator_3B", +"Ljava_2Flang_2FThreadLocal_24ThreadLocalMap_3B_7Cset_7C_28Ljava_2Flang_2FThreadLocal_3BLjava_2Flang_2FObject_3B_29V", +"Landroid_2Fos_2FParcel_3B_7CreadParcelable_7C_28Ljava_2Flang_2FClassLoader_3B_29Landroid_2Fos_2FParcelable_3B", +"Ljava_2Flang_2FThreadLocal_24ThreadLocalMap_3B_7CgetEntryAfterMiss_7C_28Ljava_2Flang_2FThreadLocal_3BILjava_2Flang_2FThreadLocal_24ThreadLocalMap_24Entry_3B_29Ljava_2Flang_2FThreadLocal_24ThreadLocalMap_24Entry_3B", +"Lcom_2Fandroid_2Fserver_2Fwm_2FWindowContainer_3B_7CforAllWindows_7C_28Lcom_2Fandroid_2Finternal_2Futil_2FToBooleanFunction_3BZ_29Z", +"Lcom_2Fandroid_2Fserver_2Fpm_2FPermissionsState_24PermissionData_3B_7CisGranted_7C_28I_29Z", +"Lcom_2Fandroid_2Fserver_2Fpm_2FPackageManagerService_3B_7ChasSystemFeature_7C_28Ljava_2Flang_2FString_3BI_29Z", +"Lcom_2Fandroid_2Fserver_2Fam_2FActivityManagerService_3B_7CgetRunningAppProcesses_7C_28_29Ljava_2Futil_2FList_3B", +"Lcom_2Fandroid_2Fserver_2Fwm_2FWindowContainer_3B_7CstepAppWindowsAnimation_7C_28J_29V", +"Lcom_2Fandroid_2Fserver_2Fpm_2FUserManagerService_3B_7CgetUserInfoNoChecks_7C_28I_29Landroid_2Fcontent_2Fpm_2FUserInfo_3B", +"Landroid_2Fapp_2FActivityManager_3B_7CgetService_7C_28_29Landroid_2Fapp_2FIActivityManager_3B", +"Lcom_2Fandroid_2Fserver_2Fpm_2FHwPackageManagerService_3B_7CgetCust_7C_28_29Lcom_2Fandroid_2Fserver_2Fpm_2FHwCustPackageManagerService_3B", +"Lcom_2Fandroid_2Fserver_2Fpm_2FPackageManagerService_3B_7CcheckUidPermission_7C_28Ljava_2Flang_2FString_3BI_29I", +"Lcom_2Fandroid_2Fserver_2Fam_2FActiveServices_3B_7CgetRunningServiceInfoLocked_7C_28IIIZZ_29Ljava_2Futil_2FList_3B", +"Lcom_2Fandroid_2Fserver_2Fpm_2FPermissionsState_24PermissionData_3B_7CgetPermissionState_7C_28I_29Lcom_2Fandroid_2Fserver_2Fpm_2FPermissionsState_24PermissionState_3B", +"Lcom_2Fxunmeng_2Frouter_2FRealRouter_3B_7CgetFragment_7C_28Ljava_2Flang_2FObject_3B_29Ljava_2Flang_2FObject_3B", +"Lcom_2Fandroid_2Fserver_2Fam_2FProcessRecord_3B_7CgetPackageList_7C_28_29ALjava_2Flang_2FString_3B", +"Lcom_2Fandroid_2Fserver_2Fam_2FActivityManagerService_3B_7CdispatchUidsChanged_7C_28_29V", +"Lcom_2Fandroid_2Fserver_2Fam_2FActivityManagerService_3B_7CgetLRURecordIndexForAppLocked_7C_28Landroid_2Fapp_2FIApplicationThread_3B_29I", +"Lcom_2Fandroid_2Fserver_2Fam_2FActivityManagerService_3B_7CgetRecordForAppLocked_7C_28Landroid_2Fapp_2FIApplicationThread_3B_29Lcom_2Fandroid_2Fserver_2Fam_2FProcessRecord_3B", +"Lcom_2Fandroid_2Fserver_2Fam_2FActivityDisplay_3B_7CgetChildAt_7C_28I_29Lcom_2Fandroid_2Fserver_2Fam_2FActivityStack_3B", +"Lcom_2Fandroid_2Fserver_2Fam_2FActivityStack_3B_7CgetRunningTasks_7C_28Ljava_2Futil_2FList_3BIIIZ_29V", +"Lcom_2Fandroid_2Fserver_2Fam_2FRunningTasks_3B_7CgetTasks_7C_28ILjava_2Futil_2FList_3BIILandroid_2Futil_2FSparseArray_3BIZ_29V", +"Lcom_2Fandroid_2Fserver_2Fam_2FTaskRecord_3B_7CgetTopActivity_7C_28Z_29Lcom_2Fandroid_2Fserver_2Fam_2FActivityRecord_3B", +"Lcom_2Fandroid_2Fserver_2Fpm_2FPackageManagerService_3B_7CgetInstalledApplications_7C_28II_29Landroid_2Fcontent_2Fpm_2FParceledListSlice_3B", +"Lcom_2Fandroid_2Fserver_2Fwm_2FWindowContainer_3B_7CisSelfOrChildAnimating_7C_28_29Z", +"Lcom_2Fandroid_2Fserver_2Fpm_2FPackageSettingBase_3B_7CreadUserState_7C_28I_29Landroid_2Fcontent_2Fpm_2FPackageUserState_3B", +"Lcom_2Fandroid_2Fserver_2Fpm_2Fpermission_2FPermissionsState_3B_7ChasPermission_7C_28Ljava_2Flang_2FString_3BI_29Z", +"Lcom_2Fandroid_2Fserver_2Fpm_2Fpermission_2FPermissionsState_24PermissionData_3B_7CisGranted_7C_28I_29Z", +"Lcom_2Fandroid_2Fserver_2Fdisplay_2FBackLightMonitorManager_3B_7CisParamOwner_7C_28Ljava_2Flang_2FString_3B_29Z", +"Lcom_2Fandroid_2Fserver_2Fwm_2FWindowContainer_3B_7CgetChildAt_7C_28I_29Lcom_2Fandroid_2Fserver_2Fwm_2FWindowContainer_3B", +"Lcom_2Fandroid_2Fserver_2Fwm_2FWindowContainer_3B_7CcheckCompleteDeferredRemoval_7C_28_29Z", +"Lcom_2Fandroid_2Fserver_2Fwm_2FWindowContainer_3B_7CprepareSurfaces_7C_28_29V", +"Lcom_2Fandroid_2Fserver_2Fwm_2FWindowContainer_3B_7CisAppAnimating_7C_28_29Z", +"Landroid_2Fcontent_2Fpm_2FParceledListSlice_3B_7CwriteElement_7C_28Ljava_2Flang_2FObject_3BLandroid_2Fos_2FParcel_3BI_29V", +"Landroid_2Fcontent_2Fpm_2FParceledListSlice_3B_7CwriteParcelableCreator_7C_28Ljava_2Flang_2FObject_3BLandroid_2Fos_2FParcel_3B_29V", +"Landroid_2Fcontent_2Fpm_2FPackageParser_3B_7CgeneratePackageInfo_7C_28Landroid_2Fcontent_2Fpm_2FPackageParser_24Package_3BAIIJJLjava_2Futil_2FSet_3BLandroid_2Fcontent_2Fpm_2FPackageUserState_3BI_29Landroid_2Fcontent_2Fpm_2FPackageInfo_3B", +"Landroid_2Fos_2FParcel_3B_7CwriteTypedList_7C_28Ljava_2Futil_2FList_3BI_29V", +"Lcom_2Fandroid_2Fserver_2Fsecurity_2Fsecurityprofile_2FPolicyEngine_3B_7CfindRulesAndEvaluate_7C_28Ljava_2Flang_2FString_3BLjava_2Flang_2FString_3BLjava_2Flang_2FString_3BLjava_2Flang_2FString_3BLjava_2Flang_2FString_3BZI_29Z", +"Lcom_2Fandroid_2Fserver_2Fsecurity_2Fsecurityprofile_2FSecurityProfileControllerImpl_3B_7CshouldPreventInteraction_7C_28ILjava_2Flang_2FString_3BIILjava_2Flang_2FString_3BI_29Z", +"Lcom_2Fandroid_2Finternal_2Fos_2FBinderCallsStats_3B_7CcallStarted_7C_28Landroid_2Fos_2FBinder_3BI_29Lcom_2Fandroid_2Finternal_2Fos_2FBinderCallsStats_24CallSession_3B", + +"Lcom_2Fandroid_2Fserver_2Fcontent_2FContentService_3B_7CregisterContentObserver_7C_28Landroid_2Fnet_2FUri_3BZLandroid_2Fdatabase_2FIContentObserver_3BII_29V", +"Lcom_2Fandroid_2Fserver_2Fam_2FActivityManagerService_3B_7CcomputeOomAdjLocked_7C_28Lcom_2Fandroid_2Fserver_2Fam_2FProcessRecord_3BILcom_2Fandroid_2Fserver_2Fam_2FProcessRecord_3BZJ_29Z", +"Lcom_2Fandroid_2Fserver_2Fcontent_2FContentService_3B_7CnotifyChange_7C_28Landroid_2Fnet_2FUri_3BLandroid_2Fdatabase_2FIContentObserver_3BZIII_29V", +"Lcom_2Fandroid_2Fserver_2Fcontent_2FContentService_24ObserverNode_3B_7CaddObserverLocked_7C_28Landroid_2Fnet_2FUri_3BILandroid_2Fdatabase_2FIContentObserver_3BZLjava_2Flang_2FObject_3BIII_29V", + +"Lcom_2Fandroid_2Fserver_2Fpm_2FPackageManagerService_3B_7CgetUidTargetSdkVersionLockedLPr_7C_28I_29I", diff --git a/src/mapleall/mpl2mpl/include/class_hierarchy.h b/src/mapleall/mpl2mpl/include/class_hierarchy.h index f02c0caaa21a57aa02109b32d448130d1ad6340f..4e60d4d273711d683fbe12b62a4a136b1e9591d8 100644 --- a/src/mapleall/mpl2mpl/include/class_hierarchy.h +++ b/src/mapleall/mpl2mpl/include/class_hierarchy.h @@ -352,6 +352,8 @@ class KlassHierarchy : public AnalysisResult { TyIdx GetLCA(TyIdx ty1, TyIdx ty2) const; GStrIdx GetLCA(GStrIdx str1, GStrIdx str2) const; const std::string &GetLCA(const std::string &name1, const std::string &name2) const; + // 1/0/-1: true/false/unknown + int IsSuperKlass(TyIdx superTyIdx, TyIdx baseTyIdx) const; bool IsSuperKlass(const Klass *super, const Klass *base) const; bool IsSuperKlassForInterface(const Klass *super, const Klass *base) const; bool IsInterfaceImplemented(Klass *interface, const Klass *base) const; @@ -388,6 +390,12 @@ class KlassHierarchy : public AnalysisResult { int GetFieldIDOffsetBetweenClasses(const Klass &super, const Klass &base) const; void TopologicalSortKlasses(); void MarkClassFlags(); + // Return the unique method if there is only one target virtual function. + // Return 0 if there are multiple targets or the targets are unclear. + GStrIdx GetUniqueMethod(GStrIdx) const; + bool IsDevirtualListEmpty() const; + void DumpDevirtualList(const std::string &outputFileName) const; + void ReadDevirtualList(const std::string &inputFileName); MapleAllocator alloc; MIRModule *mirModule; // Map from class name to klass. Use name as the key because the type @@ -397,6 +405,9 @@ class KlassHierarchy : public AnalysisResult { // class B extends A { void foo(); } // In this case, there is no link from B.bar to B in the maple file. MapleMap strIdx2KlassMap; + // Map from a virtual method name to its corresponding real method name + // This is used for devirtualization and has to be built with a closed-world view + MapleMap vfunc2RfuncMap; MapleVector topoWorkList; }; diff --git a/src/mapleall/mpl2mpl/include/gen_check_cast.h b/src/mapleall/mpl2mpl/include/gen_check_cast.h index ee8275400e0ebad9429f094f5eb7c659af1f9162..bd1980d477b012ce82f988841cb34526623dafdb 100644 --- a/src/mapleall/mpl2mpl/include/gen_check_cast.h +++ b/src/mapleall/mpl2mpl/include/gen_check_cast.h @@ -19,6 +19,16 @@ #include "phase_impl.h" namespace maple { +class PreCheckCast : public FuncOptimizeImpl { + public: + PreCheckCast(MIRModule &mod, KlassHierarchy *kh, bool dump); + ~PreCheckCast() {} + FuncOptimizeImpl *Clone() override { + return new PreCheckCast(*this); + } + + void ProcessFunc(MIRFunction *func) override; +}; class CheckCastGenerator : public FuncOptimizeImpl { public: @@ -38,12 +48,30 @@ class CheckCastGenerator : public FuncOptimizeImpl { void GenCheckCast(StmtNode &stmt); BaseNode *GetObjectShadow(BaseNode *opnd); MIRSymbol *GetOrCreateClassInfoSymbol(const std::string &className); + void GenAllCheckCast(bool isHotFunc); + void OptimizeInstanceof(); + void OptimizeIsAssignableFrom(); + void CheckIsAssignableFrom(BlockNode &blockNode, StmtNode &stmt, const IntrinsicopNode &intrinsicNode); + void ConvertCheckCastToIsAssignableFrom(StmtNode &stmt); + void AssignedCastValue(StmtNode &stmt); + void ConvertInstanceofToIsAssignableFrom(StmtNode &stmt, const IntrinsicopNode &intrinsicNode); + void ReplaceNoSubClassIsAssignableFrom(BlockNode &blockNode, StmtNode &stmt, const MIRPtrType &ptrType, + const IntrinsicopNode &intrinsicNode); + void ReplaceIsAssignableFromUsingCache(BlockNode &blockNode, StmtNode &stmt, const MIRPtrType &targetClassType, + const IntrinsicopNode &intrinsicNode); + bool IsDefinedConstClass(StmtNode &stmt, const MIRPtrType &targetClassType, + PregIdx &classSymPregIdx, MIRSymbol *&classSym); MIRType *pointerObjType = nullptr; MIRType *pointerClassMetaType = nullptr; MIRType *classinfoType = nullptr; MIRFunction *throwCastException = nullptr; MIRFunction *checkCastingNoArray = nullptr; MIRFunction *checkCastingArray = nullptr; + const std::unordered_set funcWithoutCastCheck{ +#include "castcheck_whitelist.def" + }; + MIRFunction *mccIsAssignableFrom = nullptr; + MIRFunction *castExceptionFunc = nullptr; }; class DoCheckCastGeneration : public ModulePhase { @@ -63,5 +91,17 @@ class DoCheckCastGeneration : public ModulePhase { } }; +class DoPreCheckCast : public ModulePhase { + public: + explicit DoPreCheckCast(ModulePhaseID id) : ModulePhase(id) {} + ~DoPreCheckCast() = default; + std::string PhaseName() const override { + return "precheckcast"; + } + AnalysisResult *Run(MIRModule *mod, ModuleResultMgr *mrm) override { + OPT_TEMPLATE(PreCheckCast); + return nullptr; + } +}; } // namespace maple #endif // MPL2MPL_INCLUDE_GEN_CHECK_CAST_H diff --git a/src/mapleall/mpl2mpl/include/java_intrn_lowering.h b/src/mapleall/mpl2mpl/include/java_intrn_lowering.h index d8551fce541d77525073805cdb8ab913641f7390..6bac3c567342adeb08b6fb6707201d5fb7b438df 100644 --- a/src/mapleall/mpl2mpl/include/java_intrn_lowering.h +++ b/src/mapleall/mpl2mpl/include/java_intrn_lowering.h @@ -30,10 +30,24 @@ class JavaIntrnLowering : public FuncOptimizeImpl { } private: + void InitTypes(); + void InitFuncs(); + void InitLists(); void ProcessStmt(StmtNode &stmt) override; void ProcessJavaIntrnMerge(StmtNode &assignNode, const IntrinsicopNode &intrinNode); BaseNode *JavaIntrnMergeToCvtType(PrimType dtyp, PrimType styp, BaseNode *src); + void LoadClassLoaderInvocation(const std::string &list); + void CheckClassLoaderInvocation(const CallNode &callNode) const; + void DumpClassLoaderInvocation(const CallNode &callNode); + void ProcessForNameClassLoader(CallNode &callnode); void ProcessJavaIntrnFillNewArray(IntrinsiccallNode &intrinCall); + std::string outFileName; + std::unordered_set clInterfaceSet; + std::multimap clInvocationMap; + MIRFunction *classForName1Func = nullptr; + MIRFunction *classForName3Func = nullptr; + MIRFunction *getCurrentClassLoaderFunc = nullptr; + MIRType *classLoaderPointerToType = nullptr; }; class DoJavaIntrnLowering : public ModulePhase { diff --git a/src/mapleall/mpl2mpl/include/native_stub_func.h b/src/mapleall/mpl2mpl/include/native_stub_func.h index 1e7fa713e1c2e14d37c6945d045bb207c977ae4c..8149e8b72b0e7940f580cb7544485bdf6dc4b4f2 100644 --- a/src/mapleall/mpl2mpl/include/native_stub_func.h +++ b/src/mapleall/mpl2mpl/include/native_stub_func.h @@ -69,6 +69,8 @@ class NativeStubFuncGeneration : public FuncOptimizeImpl { } void InitStaticBindingMethodList(); bool IsStaticBindingMethod(const std::string &methodName) const; + void LoadNativeFuncProperty(); + bool GetNativeFuncProperty(const std::string &funcName, NativeFuncProperty &property); MIRFunction &GetOrCreateDefaultNativeFunc(MIRFunction &stubFunc); void GenerateRegisteredNativeFuncCall(MIRFunction &func, const MIRFunction &nativeFunc, MapleVector &args, const MIRSymbol *ret); @@ -83,6 +85,7 @@ class NativeStubFuncGeneration : public FuncOptimizeImpl { void GenerateRegFuncTabEntryType(); void GenerateRegFuncTabEntry(); void GenerateRegFuncTab(); + std::unordered_map nativeFuncPropertyMap; // a static binding function list std::unordered_set staticBindingMethodsSet; TyIdx jstrPointerTypeIdx = TyIdx(0); diff --git a/src/mapleall/mpl2mpl/include/reflection_analysis.h b/src/mapleall/mpl2mpl/include/reflection_analysis.h index da19aac039c7e78186826d8fd7f90deb82d04229..f54e61d95d045e9cfbddc152629d0abfe756ecc4 100644 --- a/src/mapleall/mpl2mpl/include/reflection_analysis.h +++ b/src/mapleall/mpl2mpl/include/reflection_analysis.h @@ -132,6 +132,7 @@ class ReflectionAnalysis : public AnalysisResult { static TyIdx GetClassMetaDataTyIdx() { return classMetadataTyIdx; } + void DumpPGOSummary(); private: static std::unordered_map &GetStr2IdxMap() { @@ -187,8 +188,20 @@ class ReflectionAnalysis : public AnalysisResult { MIRSymbol *GenFieldOffsetData(const Klass &klass, std::pair &fieldInfo); MIRSymbol *GetMethodSignatureSymbol(std::string signature); MIRSymbol *GetParameterTypesSymbol(uint32 size, uint32 index); - MIRSymbol *GenFieldsMetaData(const Klass &klass); - MIRSymbol *GenMethodsMetaData(const Klass &klass); + MIRSymbol *GenFieldsMetaData(const Klass &klass, bool isHot); + MIRSymbol *GenMethodsMetaData(const Klass &klass, bool isHot); + MIRSymbol *GenFieldsMetaCompact(const Klass &klass, std::vector> &fieldsVector); + void GenFieldMetaCompact(const Klass &klass, MIRStructType &fieldsInfoCompactType, + std::pair &fieldInfo, MIRAggConst &aggConstCompact); + void GenMethodMetaCompact(const Klass &klass, MIRStructType &methodsInfoType, int idx, + MIRSymbol &funcSym, MIRAggConst &aggConst, + int &allDeclaringClassOffset, + std::unordered_map &baseNameMp, + std::unordered_map &fullNameMp); + MIRSymbol *GenMethodsMetaCompact(const Klass &klass, + std::vector> &methodInfoVec, + std::unordered_map &baseNameMp, + std::unordered_map &fullNameMp); MIRSymbol *GenFieldsMeta(const Klass &klass, std::vector> &fieldsVector, std::vector> &fieldHashvec); void GenFieldMeta(const Klass &klass, MIRStructType &fieldsInfoType, std::pair &fieldInfo, @@ -274,6 +287,15 @@ class ReflectionAnalysis : public AnalysisResult { static bool strTabInited; static TyIdx invalidIdx; static constexpr uint16 kNoHashBits = 6u; + // profile statistics + static uint32_t hotMethodMeta; + static uint32_t totalMethodMeta; + static uint32_t hotClassMeta; + static uint32_t totalClassMeta; + static uint32_t hotFieldMeta; + static uint32_t totalFieldMeta; + static uint32_t hotCStr; + static uint32_t totalCStr; static constexpr char annoDelimiterPrefix = '`'; static constexpr char annoDelimiter = '!'; static constexpr char annoArrayStartDelimiter = '{'; diff --git a/src/mapleall/mpl2mpl/include/vtable_impl.h b/src/mapleall/mpl2mpl/include/vtable_impl.h index cac273b011eb8d3acbf8c8e6655dfa5240dfa289..78dd8239f789387852de682f8b098ee0442de0e9 100644 --- a/src/mapleall/mpl2mpl/include/vtable_impl.h +++ b/src/mapleall/mpl2mpl/include/vtable_impl.h @@ -34,13 +34,42 @@ class VtableImpl : public FuncOptimizeImpl { FuncOptimizeImpl *Clone() override { return new VtableImpl(*this); } +#ifndef USE_ARM32_MACRO +#ifdef USE_32BIT_REF + void Finish() override; +#endif // ~USE_32BIT_REF +#endif // ~USE_ARM32_MACRO private: void ReplaceResolveInterface(StmtNode &stmt, const ResolveFuncNode &resolveNode); void ItabProcess(StmtNode &stmt, const ResolveFuncNode &resolveNode, const std::string &signature, PregIdx &pregFuncPtr, const MIRType &compactPtrType, const PrimType &compactPtrPrim); bool Intrinsify(MIRFunction &func, CallNode &cnode); +#ifndef USE_ARM32_MACRO +#ifdef USE_32BIT_REF + void InlineCacheinit(); + void GenInlineCacheTableSymbol(); + void InlineCacheProcess(StmtNode &stmt, const ResolveFuncNode &resolveNode, + const std::string &signature, PregIdx &pregFuncPtr); + void CallMrtInlineCacheFun(StmtNode &stmt, const ResolveFuncNode &resolveNode, + RegreadNode ®ReadNodeTmp, int64 hashCode, uint64 secondHashCode, + const std::string &signature, PregIdx &pregFuncPtr, IfStmtNode &ifStmt); + void ResolveInlineCacheTable(); +#endif // ~USE_32BIT_REF +#endif // ~USE_ARM32_MACRO + void DeferredVisit(CallNode &stmt, CallKind n); + void DeferredVisitCheckFloat(CallNode &stmt, const MIRFunction &mirFunc); MIRModule *mirModule; + KlassHierarchy *klassHierarchy; +#ifndef USE_ARM32_MACRO +#ifdef USE_32BIT_REF + MIRFunction *mccItabFuncInlineCache; + uint32 numOfInterfaceCallSite = 0; + MIRStructType *inlineCacheTableEntryType = nullptr; + MIRArrayType *inlineCacheTableType = nullptr; + MIRSymbol *inlineCacheTableSym = nullptr; +#endif // ~USE_32BIT_REF +#endif // ~USE_ARM32_MACRO MIRFunction *mccItabFunc; }; diff --git a/src/mapleall/mpl2mpl/src/barrierinsertion.cpp b/src/mapleall/mpl2mpl/src/barrierinsertion.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b7fca6e5dc0e39ab4c7fcc09ddb2a2201a035359 --- /dev/null +++ b/src/mapleall/mpl2mpl/src/barrierinsertion.cpp @@ -0,0 +1,440 @@ +/* + * Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved. + * + * OpenArkCompiler is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR + * FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +#include "barrierinsertion.h" +#include +#include "vtable_impl.h" +#include "mir_function.h" +#include "mir_builder.h" +#include "global_tables.h" +#include "option.h" +#include "mpl_logging.h" +#include "opcode_info.h" + +// BARDEBUG is turned on by passing -dump-phase=barrierinsertion to mpl2mpl +#define BARDEBUG (Options::dumpPhase.compare(PhaseName()) == 0) +// use this pass just for memory verification +#define MEMVERIFY + +namespace maple { +CallNode *BarrierInsertion::RunFunction::CreateWriteRefVarCall(BaseNode &var, BaseNode &value) const { + MIRFunction *callee = builder->GetOrCreateFunction("MCC_WriteRefVar", static_cast(PTY_void)); + MapleVector args(builder->GetCurrentFuncCodeMpAllocator()->Adapter()); + args.push_back(&var); + args.push_back(&value); + return builder->CreateStmtCall(callee->GetPuidx(), args); +} + +CallNode *BarrierInsertion::RunFunction::CreateWriteRefFieldCall(BaseNode &obj, BaseNode &field, + BaseNode &value) const { + MIRFunction *callee = builder->GetOrCreateFunction("MCC_WriteRefField", static_cast(PTY_void)); + MapleVector args(builder->GetCurrentFuncCodeMpAllocator()->Adapter()); + args.push_back(&obj); + args.push_back(&field); + args.push_back(&value); + return builder->CreateStmtCall(callee->GetPuidx(), args); +} + +CallNode *BarrierInsertion::RunFunction::CreateReleaseRefVarCall(BaseNode &var) const { + MIRFunction *callee = builder->GetOrCreateFunction("MCC_ReleaseRefVar", TyIdx(PTY_void)); + MapleVector args(builder->GetCurrentFuncCodeMpAllocator()->Adapter()); + args.push_back(&var); + return builder->CreateStmtCall(callee->GetPuidx(), args); +} + +CallNode *BarrierInsertion::RunFunction::CreateMemCheckCall(BaseNode &var) const { + MIRFunction *callee = builder->GetOrCreateFunction("MCC_CheckObjMem", TyIdx(PTY_void)); + MapleVector args(builder->GetCurrentFuncCodeMpAllocator()->Adapter()); + args.push_back(&var); + return builder->CreateStmtCall(callee->GetPuidx(), args); +} + +bool BarrierInsertion::RunFunction::SkipRHS(const BaseNode &rhs) const { + // only consider reference + if (rhs.GetPrimType() != PTY_ref) { + return true; + } + if (rhs.GetOpCode() == OP_conststr16) { + return true; // conststr + } + if (rhs.GetOpCode() == OP_intrinsicopwithtype) { + auto *node = static_cast(&rhs); + if (node->GetIntrinsic() == INTRN_JAVA_CONST_CLASS) { + return true; + } + } + return false; +} + +// create a backup variable symbol using a counter inside its name +MIRSymbol *BarrierInsertion::RunFunction::NewBackupVariable(const std::string &suffix) { + std::ostringstream oss; + oss << "__backup" << backupVarCount << "_" << suffix << "__"; + ++backupVarCount; + std::string name = oss.str(); + MIRSymbol *backupSym = + builder->GetOrCreateLocalDecl(name, *GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(PTY_ref))); + backupVarIndices.insert(backupSym->GetStIdx()); + return backupSym; +} + +// go through each stmt in the block, memory check for all +// iread and iassign of PTY_ref type , i.e., read/write to heap objects +void BarrierInsertion::RunFunction::HandleBlock(BlockNode &block) const { + for (StmtNode *stmt = block.GetFirst(); stmt != nullptr; stmt = stmt->GetNext()) { + stmt = HandleStmt(*stmt, block); + } +} + +GStrIdx reflectClassNameIdx; +GStrIdx reflectMethodNameIdx; +GStrIdx reflectFieldNameIdx; +// This function exams one operand of a StmtNode and insert memory check calls +// when it is iread of PTY_ref +StmtNode *BarrierInsertion::RunFunction::CheckRefRead(BaseNode *opnd, const StmtNode &stmt, BlockNode &block) const { + if (opnd == nullptr || opnd->GetPrimType() != PTY_ref) { + return nullptr; + } + if (opnd->GetOpCode() == OP_dread) { + DreadNode *val = static_cast(opnd); + MIRSymbol *sym = mirFunc->GetLocalOrGlobalSymbol((static_cast(val))->GetStIdx()); + if (sym != nullptr && sym->IgnoreRC()) { + return nullptr; + } + CallNode *checkStmt = CreateMemCheckCall(*opnd); + block.InsertBefore(&stmt, checkStmt); + return checkStmt; + } + if (opnd->GetOpCode() == OP_iread) { + IreadNode *iread = static_cast(opnd); + // after the reference value is read from heap, call for verification + MIRPtrType *ptrType = static_cast(GlobalTables::GetTypeTable().GetTypeFromTyIdx(iread->GetTyIdx())); + GStrIdx strIdx = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ptrType->GetPointedTyIdx())->GetNameStrIdx(); + if (reflectClassNameIdx == 0u) { + reflectClassNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName( + namemangler::GetInternalNameLiteral("Ljava_2Flang_2FClass_3B")); + reflectMethodNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName( + namemangler::GetInternalNameLiteral("Ljava_2Flang_2Freflect_2FMethod_3B")); + reflectFieldNameIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName( + namemangler::GetInternalNameLiteral("Ljava_2Flang_2Freflect_2FField_3B")); + } + if (strIdx == reflectClassNameIdx || strIdx == reflectMethodNameIdx || strIdx == reflectFieldNameIdx) { + return nullptr; + } + CallNode *checkStmt = CreateMemCheckCall(*opnd); + block.InsertBefore(&stmt, checkStmt); + return checkStmt; + } else if (opnd->GetOpCode() == OP_retype) { + return nullptr; + } + return nullptr; +} + +// This function exams one StmtNode and carrys out necessary operations for +// reference counting or memory verification. +// +// For barrier RC, below are the opcodes related and how they are handled: +// +// [dassign] +// Condition: 1) rhs is reference (other than conststr16, global symbols) +// 2) symbols not ignored +// 3) Not a self-assignment (dassign v (dread v)) +// Handling: 1) Replace dassign with a call to MCC_WriteRefVar. +// 2) If assigned to a formal parameter, make a backup variable in the +// prologue after processing all statements. +// +// [iassign] +// Condition: 1) rhs is not addressof symbols with names starting "__vtab__" or +// "__itab__" (vtab, itab initialization +// Handling: 1) Replace iassign with a call to CC_WriteRefField. +// +// [[|i|intrinsic]callassigned] +// Condition: 1) Return type is ref. +// Handling: 1) Assign return values to temporary variables, use +// MCC_ReleaseRefVar on the original return variable, and then +// dassign the tmp variable to the actual return var. +// +// [call] +// Condition: 1) Return type is ref. +// Handling: 1) Assign return values to temporary variables, and then call +// MCC_ReleaseRefVar on them. +// +// [return] +// Assumption: 1) If the return type is ref, assume it is the result of a dread. +// Handling: 1) If the return value is a reference, consider it as if it is +// assigned to. +// 2) Call MCC_ReleaseRefVar on all local vars except un-assigned +// parameters and the return value. this is processed after +// procesing all statements. +// +// This function returns the last stmt it generated or visited. HandleBlock +// shall continue with the next statement after the return value, if any. +StmtNode *BarrierInsertion::RunFunction::HandleStmt(StmtNode &stmt, BlockNode &block) const { + Opcode opcode = stmt.GetOpCode(); +#ifdef MEMVERIFY + // ignore decref opcode due to missing initialization in whitelist func + if (opcode != OP_decref && opcode != OP_intrinsiccall) { + for (size_t i = (opcode == OP_iassign ? 1 : 0); i < stmt.NumOpnds(); ++i) { + (void)CheckRefRead(stmt.Opnd(i), stmt, block); + } + } +#endif + switch (opcode) { + case OP_dassign: { + DassignNode *dassign = static_cast(&stmt); + BaseNode *rhs = dassign->GetRHS(); + if (SkipRHS(*rhs)) { + break; + } + MIRSymbol *refSym = mirFunc->GetLocalOrGlobalSymbol(dassign->GetStIdx()); + CHECK_FATAL(refSym != nullptr, "Symbol is nullptr"); + if (refSym->IgnoreRC()) { + break; + } + if (BARDEBUG) { + dassign->Dump(0); + } +#ifdef MEMVERIFY + DreadNode *checkObjRead = + builder->CreateExprDread(*GlobalTables::GetTypeTable().GetRef(), dassign->GetFieldID(), *refSym); + CallNode *checkStmt = CreateMemCheckCall(*checkObjRead); + block.InsertAfter(&stmt, checkStmt); + return checkStmt; +#endif + } + case OP_iassign: { + IassignNode *iassign = static_cast(&stmt); + BaseNode *rhs = iassign->GetRHS(); + if (SkipRHS(*rhs)) { + break; + } + if (rhs->GetOpCode() == OP_addrof) { + // ignore $__vtab__ such as in + // iassign <* <$LPoint_3B>> 3 (dread ptr %_this, addrof ptr $__vtab__LPoint_3B) + AddrofNode *aNode = static_cast(rhs); + MIRSymbol *curSt = mirFunc->GetLocalOrGlobalSymbol(aNode->GetStIdx()); + if (curSt->HasAddrOfValues()) { + break; + } + } + if (BARDEBUG) { + iassign->Dump(0); + } +#ifdef MEMVERIFY + // Call memory verification + CallNode *newStmt = CreateMemCheckCall(*rhs); + block.InsertAfter(&stmt, newStmt); + return newStmt; +#endif + } + default: + break; + } + return &stmt; +} + +// this function handles local ref var initialization +// and formal ref parameters backup +void BarrierInsertion::RunFunction::InsertPrologue() { + StmtNode *firstStmt = mirFunc->GetBody()->GetFirst(); + // Copy assigned formal parameters to backup variables using MCC_WriteRefVar. + // This will inc those parameters, and those parameters will be dec-ed before + // returning. + for (StIdx asgnParam : assignedParams) { + MIRSymbol *backupSym = NewBackupVariable("modified_param"); + // Clear the temporary variable + ConstvalNode *rhsZero = builder->CreateIntConst(0, PTY_ref); + DassignNode *dassignClear = builder->CreateStmtDassign(*backupSym, 0, rhsZero); + mirFunc->GetBody()->InsertBefore(firstStmt, dassignClear); + // Backup the parameter + AddrofNode *lhsAddr = builder->CreateExprAddrof(0, backupSym->GetStIdx()); + DreadNode *rhs = builder->CreateDread(*mirFunc->GetSymTab()->GetSymbolFromStIdx(asgnParam.Idx()), PTY_ref); + CallNode *newStmt = CreateWriteRefVarCall(*lhsAddr, *rhs); + mirFunc->GetBody()->InsertBefore(firstStmt, newStmt); + } + // Initialize local variables (but not formal parameters) of ref type to 0. + size_t bSize = mirFunc->GetSymTab()->GetSymbolTableSize(); + for (size_t i = 1; i < bSize; ++i) { + // 0 is a reserved stIdx. + MIRSymbol *sym = mirFunc->GetSymTab()->GetSymbolFromStIdx(i); + CHECK_FATAL(sym != nullptr, "sym is nullptr"); + if (sym->GetStorageClass() != kScAuto || + (GlobalTables::GetTypeTable().GetTypeFromTyIdx(sym->GetTyIdx())->GetPrimType() != PTY_ref)) { + continue; + } + if (sym->IgnoreRC()) { + continue; + } + if (backupVarIndices.find(sym->GetStIdx()) != backupVarIndices.end()) { + continue; + } + if (BARDEBUG) { + LogInfo::MapleLogger() << "Local variable " << sym->GetName() << " set to null\n"; + } + mirFunc->GetBody()->InsertBefore(firstStmt, + builder->CreateStmtDassign(*sym, 0, builder->CreateIntConst(0, PTY_ref))); + } +} + +void BarrierInsertion::RunFunction::HandleReturn(const NaryStmtNode &retNode) { + std::set retValStIdxs; + for (size_t i = 0; i < retNode.NumOpnds(); ++i) { + BaseNode *val = retNode.Opnd(i); + if (val->GetOpCode() == OP_constval && static_cast(val)->GetConstVal()->IsMagicNum()) { + if (BARDEBUG) { + LogInfo::MapleLogger() << "BARDEBUG: Ignoring magic number return\n"; + } + continue; + } + if (val->GetPrimType() != PTY_ref) { + continue; + } + if (val->GetOpCode() != OP_dread) { + if (val->GetOpCode() == OP_constval) { + auto constvalNode = static_cast(val); + MIRConst *con = constvalNode->GetConstVal(); + if (con->GetKind() == kConstInt) { + auto intConst = safe_cast(con); + if (intConst->IsZero()) { + // It is a nullptr. Skip this return value. + continue; + } + } + } + CHECK_FATAL(false, + "Found a return statement that returns a ref but is not from a dread. Please enable the code below" + "this line."); + } else { + // It is a dassign. Blacklist this symbol for this return. + DreadNode *dreadNode = static_cast(val); + MIRSymbol *sym = mirFunc->GetLocalOrGlobalSymbol(dreadNode->GetStIdx()); + CHECK_FATAL(sym != nullptr, "sym is null"); + if (sym->IgnoreRC()) { + continue; + } + if (sym->GetStorageClass() == kScFormal && assignedParams.find(sym->GetStIdx()) == assignedParams.end()) { + // If returning a parameter that is never assigned to, + // insert a MCC_WriteRefVar to a temp var before returning. + MIRSymbol *backupSym = NewBackupVariable("ret_prarm_unassigned"); + // Clear the temporary variable + ConstvalNode *rhsZero = builder->CreateIntConst(0, PTY_ref); + DassignNode *dassignClear = builder->CreateStmtDassign(*backupSym, 0, rhsZero); + mirFunc->GetBody()->InsertBefore(&retNode, dassignClear); + // Assign the parameter to the temporary variable + AddrofNode *lhsAddr = builder->CreateExprAddrof(0, backupSym->GetStIdx()); + DreadNode *newDreadNode = builder->CreateDread(*sym, PTY_ref); + CallNode *newStmt = CreateWriteRefVarCall(*lhsAddr, *newDreadNode); + mirFunc->GetBody()->InsertBefore(&retNode, newStmt); + } + (void)retValStIdxs.insert(dreadNode->GetStIdx()); + } + } + // now release all local reference except return values + size_t size = mirFunc->GetSymTab()->GetSymbolTableSize(); + for (size_t i = 1; i < size; ++i) { + // 0 is a reserved stIdx. + MIRSymbol *localSym = mirFunc->GetSymTab()->GetSymbolFromStIdx(i); + CHECK_FATAL(localSym != nullptr, "local_sym is nullptr"); + if (GlobalTables::GetTypeTable().GetTypeFromTyIdx(localSym->GetTyIdx())->GetPrimType() == PTY_ref && + (localSym->GetStorageClass() == kScAuto || assignedParams.find(localSym->GetStIdx()) != assignedParams.end())) { + if (localSym->IgnoreRC()) { + continue; + } + if (backupVarIndices.find(localSym->GetStIdx()) != backupVarIndices.end()) { + continue; + } + if (retValStIdxs.find(localSym->GetStIdx()) != retValStIdxs.end()) { + continue; + } + if (BARDEBUG) { + LogInfo::MapleLogger() << "Local variable " << localSym->GetName() << " going out of scope\n"; + } + // Attempt to release var if it is not the return value. + DreadNode *localVar = builder->CreateDread(*localSym, PTY_ref); + mirFunc->GetBody()->InsertBefore(&retNode, CreateReleaseRefVarCall(*localVar)); + } + } +} + +void BarrierInsertion::RunFunction::Run() { + mirModule->SetCurFunction(mirFunc); + backupVarCount = 0; + HandleBlock(*mirFunc->GetBody()); +} + +void BarrierInsertion::EnsureLibraryFunction(MIRModule &module, const char &name, const MIRType &retType, + const ArgVector &args) { + MIRFunction *func = module.GetMIRBuilder()->CreateFunction(&name, retType, args); + CHECK_FATAL(func != nullptr, "func is null in BarrierInsertion::EnsureLibraryFunction"); + func->SetBody(nullptr); + module.AddFunction(func); +} + +void BarrierInsertion::EnsureLibraryFunctions(MIRModule &module) { + { + constexpr const char *name = "MCC_WriteRefVar"; + MIRType *retType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(PTY_void)); + ArgVector args(module.GetMPAllocator().Adapter()); + args.push_back(ArgPair("var", GlobalTables::GetTypeTable().GetVoidPtr())); + args.push_back(ArgPair("value", GlobalTables::GetTypeTable().GetVoidPtr())); + EnsureLibraryFunction(module, *name, *retType, args); + } + { + constexpr const char *name = "MCC_WriteRefField"; + MIRType *retType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(PTY_void)); + ArgVector args(module.GetMPAllocator().Adapter()); + args.push_back(ArgPair("obj", GlobalTables::GetTypeTable().GetVoidPtr())); + args.push_back(ArgPair("field", GlobalTables::GetTypeTable().GetVoidPtr())); + args.push_back(ArgPair("value", GlobalTables::GetTypeTable().GetVoidPtr())); + EnsureLibraryFunction(module, *name, *retType, args); + } + { + constexpr const char *name = "MCC_ReleaseRefVar"; + MIRType *retType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(PTY_void)); + ArgVector args(module.GetMPAllocator().Adapter()); + args.push_back(ArgPair("var", GlobalTables::GetTypeTable().GetVoidPtr())); + EnsureLibraryFunction(module, *name, *retType, args); + } + { + constexpr const char *name = "MCC_CheckObjMem"; + MIRType *retType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(PTY_void)); + ArgVector args(module.GetMPAllocator().Adapter()); + args.push_back(ArgPair("var", GlobalTables::GetTypeTable().GetVoidPtr())); + EnsureLibraryFunction(module, *name, *retType, args); + } +} + +AnalysisResult *BarrierInsertion::Run(MIRModule *module, ModuleResultMgr*) { +#ifndef MEMVERIFY + return nullptr; +#endif + for (MIRFunction *func : module->GetFunctionList()) { + if (PhaseName().empty()) { + continue; + } + if (BARDEBUG) { + LogInfo::MapleLogger() << " Handling function " << func->GetName() << "\n"; + } + if (Options::dumpFunc == func->GetName()) { + LogInfo::MapleLogger() << "Function found" << "\n"; + } + if (func->GetBody() == nullptr) { + continue; + } + RunFunction runFunction(*this, *module, *func); + runFunction.Run(); + } + return nullptr; +} +} // namespace maple diff --git a/src/mapleall/mpl2mpl/src/class_hierarchy.cpp b/src/mapleall/mpl2mpl/src/class_hierarchy.cpp index ab2e8a76cceda816e25bb95742a223ee7624ebf9..1e991ddac7567e1f145b7f21113ba2d476980f7f 100644 --- a/src/mapleall/mpl2mpl/src/class_hierarchy.cpp +++ b/src/mapleall/mpl2mpl/src/class_hierarchy.cpp @@ -40,7 +40,15 @@ namespace maple { bool KlassHierarchy::traceFlag = false; bool IsSystemPreloadedClass(const std::string &className) { - return false; + if (!Options::usePreloadedClass) { + return false; + } + static const std::unordered_set preloadedClass = { +#define CLASS_PREFIX(classname) #classname, +#include "white_list.def" +#undef CLASS_PREFIX + }; + return preloadedClass.find(className) != preloadedClass.end(); } Klass::Klass(MIRStructType *type, MapleAllocator *alc) @@ -329,6 +337,28 @@ Klass *KlassHierarchy::GetKlassFromLiteral(const std::string &name) const { return GetKlassFromStrIdx(GlobalTables::GetStrTable().GetStrIdxFromName(namemangler::GetInternalNameLiteral(name))); } +// check if super is a superclass of base +// 1/0/-1: true/false/unknown +int KlassHierarchy::IsSuperKlass(TyIdx superTyIdx, TyIdx baseTyIdx) const { + if (superTyIdx == 0u || baseTyIdx == 0u) { + return -1; + } + if (superTyIdx == baseTyIdx) { + return 1; + } + Klass *super = GetKlassFromTyIdx(superTyIdx); + Klass *base = GetKlassFromTyIdx(baseTyIdx); + if (super == nullptr || base == nullptr) { + return -1; + } + while (base != nullptr) { + if (base == super) { + return 1; + } + base = base->GetSuperKlass(); + } + return 0; +} bool KlassHierarchy::IsSuperKlass(const Klass *super, const Klass *base) const { if (super == nullptr || base == nullptr || base->IsInterface()) { @@ -482,7 +512,25 @@ const std::string &KlassHierarchy::GetLCA(const std::string &name1, const std::s void KlassHierarchy::AddKlasses() { for (MIRType *type : GlobalTables::GetTypeTable().GetTypeTable()) { - if (type == nullptr || (type->GetKind() != kTypeClass && type->GetKind() != kTypeInterface)) { +#if DEBUG + if (type != nullptr) { + MIRTypeKind kd = type->GetKind(); + if (kd == kTypeStructIncomplete || kd == kTypeClassIncomplete || kd == kTypeInterfaceIncomplete) + LogInfo::MapleLogger() << "Warning: KlassHierarchy::AddKlasses " + << GlobalTables::GetStrTable().GetStringFromStrIdx(type->GetNameStrIdx()) + << " INCOMPLETE \n"; + } +#endif + if (Options::deferredVisit2 && type && (type->IsIncomplete())) { + GStrIdx stridx = type->GetNameStrIdx(); + std::string strName = GlobalTables::GetStrTable().GetStringFromStrIdx(stridx); +#if DEBUG + LogInfo::MapleLogger() << "Waring: " << strName << " INCOMPLETE \n"; +#endif + if (strName == namemangler::kClassMetadataTypeName) { + continue; + } + } else if (type == nullptr || (type->GetKind() != kTypeClass && type->GetKind() != kTypeInterface)) { continue; } GStrIdx strIdx = type->GetNameStrIdx(); @@ -750,6 +798,44 @@ void KlassHierarchy::Dump() const { } } +GStrIdx KlassHierarchy::GetUniqueMethod(GStrIdx vfuncNameStridx) const { + auto it = vfunc2RfuncMap.find(vfuncNameStridx); + return (it != vfunc2RfuncMap.end() ? it->second : GStrIdx(0)); +} + +bool KlassHierarchy::IsDevirtualListEmpty() const { + return vfunc2RfuncMap.empty(); +} + +void KlassHierarchy::DumpDevirtualList(const std::string &outputFileName) const { + std::unordered_map funcMap; + for (Klass *klass : topoWorkList) { + for (MIRFunction *func : klass->GetMethods()) { + MIRFunction *uniqCand = klass->GetUniqueMethod(func->GetBaseFuncNameWithTypeStrIdx()); + if (uniqCand != nullptr) { + funcMap[func->GetName()] = uniqCand->GetName(); + } + } + } + std::ofstream outputFile; + outputFile.open(outputFileName); + for (auto it : funcMap) { + outputFile << it.first << "\t" << it.second << "\n"; + } + outputFile.close(); +} + +void KlassHierarchy::ReadDevirtualList(const std::string &inputFileName) { + std::ifstream inputFile; + inputFile.open(inputFileName); + std::string vfuncName; + std::string rfuncName; + while (inputFile >> vfuncName >> rfuncName) { + vfunc2RfuncMap[GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(vfuncName)] = + GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(rfuncName); + } + inputFile.close(); +} void KlassHierarchy::BuildHierarchy() { // Scan class list and generate Klass without method information @@ -766,6 +852,14 @@ void KlassHierarchy::BuildHierarchy() { if (!strIdx2KlassMap.empty()) { WKTypes::Init(); } + // Use --dump-devirtual-list=... to dump a closed-wolrd analysis result into a file + if (!Options::dumpDevirtualList.empty()) { + DumpDevirtualList(Options::dumpDevirtualList); + } + // Use --read-devirtual-list=... to read in a closed-world analysis result + if (!Options::readDevirtualList.empty()) { + ReadDevirtualList(Options::readDevirtualList); + } } KlassHierarchy::KlassHierarchy(MIRModule *mirmodule, MemPool *memPool) @@ -773,6 +867,7 @@ KlassHierarchy::KlassHierarchy(MIRModule *mirmodule, MemPool *memPool) alloc(memPool), mirModule(mirmodule), strIdx2KlassMap(std::less(), alloc.Adapter()), + vfunc2RfuncMap(std::less(), alloc.Adapter()), topoWorkList(alloc.Adapter()) {} AnalysisResult *DoKlassHierarchy::Run(MIRModule *module, ModuleResultMgr *m) { diff --git a/src/mapleall/mpl2mpl/src/class_init.cpp b/src/mapleall/mpl2mpl/src/class_init.cpp index 1113d040a5d53cfe4b35459725baa782840dc60b..e9db10d6bb24ac36dfa63f21241a2644635cd780 100644 --- a/src/mapleall/mpl2mpl/src/class_init.cpp +++ b/src/mapleall/mpl2mpl/src/class_init.cpp @@ -17,6 +17,9 @@ #include namespace { +constexpr char kCinfString[] = "__cinf_Ljava_2Flang_2FString_3B"; +constexpr char kINFOFilename[] = "INFO_filename"; +constexpr char kCoreAll[] = "core-all"; constexpr char kMCCPreClinitCheck[] = "MCC_PreClinitCheck"; constexpr char kMCCPostClinitCheck[] = "MCC_PostClinitCheck"; } // namespace @@ -26,9 +29,27 @@ constexpr char kMCCPostClinitCheck[] = "MCC_PostClinitCheck"; // for place where needed. // Insert clinit check for static native methods which are not private. // 2. Lower JAVA_CLINIT_CHECK to MPL_CLINIT_CHECK. +// Before insert or tranform the clinit check, we used a optimise based on +// white list. When the dexname is core-all and the class is in the white list +// we dont't insert clinit check.Because the class in the white list is intialized +// in the system bootup. namespace maple { bool ClassInit::CanRemoveClinitCheck(const std::string &clinitClassname) const { - return false; + if (!Options::usePreloadedClass) { + return false; + } + if (clinitClassname.empty()) { + return false; + } + if (clinitClassname == kCinfString) { + return true; + } + uint32 dexNameIdx = GetMIRModule().GetFileinfo(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kINFOFilename)); + const std::string &dexName = GlobalTables::GetStrTable().GetStringFromStrIdx(GStrIdx(dexNameIdx)); + if (dexName.find(kCoreAll) != std::string::npos) { + return false; + } + return IsSystemPreloadedClass(clinitClassname); } void ClassInit::GenClassInitCheckProfile(MIRFunction &func, const MIRSymbol &classInfo, StmtNode *clinit) const { @@ -134,6 +155,9 @@ void ClassInit::ProcessFunc(MIRFunction *func) { } else { doClinitCheck = !CanRemoveClinitCheck(className) && klassHierarchy->NeedClinitCheckRecursively(*klass); } + if (Options::buildApp != 0) { + doClinitCheck = true; + } if (doClinitCheck) { MIRSymbol *classInfo = GetClassInfo(className); AddrofNode *classInfoNode = builder->CreateExprAddrof(0, *classInfo); diff --git a/src/mapleall/mpl2mpl/src/coderelayout.cpp b/src/mapleall/mpl2mpl/src/coderelayout.cpp index 31cc74bacd31dfb95b697ae6f5d34f6e179a6cde..1235d62a8a4862600c2c145d10f705a5d1f4fc86 100644 --- a/src/mapleall/mpl2mpl/src/coderelayout.cpp +++ b/src/mapleall/mpl2mpl/src/coderelayout.cpp @@ -179,7 +179,8 @@ void CodeReLayout::Finish() { for (auto &function : GetMIRModule().GetFunctionList()) { ++layoutCount[static_cast(function->GetLayoutType())]; } - if (trace) { + if (Options::genPGOReport || trace) { + GetMIRModule().GetProfile().DumpFuncIRProfUseInfo(); for (uint32 i = 0; i < static_cast(LayoutType::kLayoutTypeCount); ++i) { LogInfo::MapleLogger() << "function in category\t" << GetLayoutTypeString(i) << "\tcount=" << layoutCount[i] << "\n"; diff --git a/src/mapleall/mpl2mpl/src/gen_check_cast.cpp b/src/mapleall/mpl2mpl/src/gen_check_cast.cpp index 38e41f0050fffaab351c4919f7d921002d5f80d6..950a64b71a792a2c61b1fcfa1fb1f039c5c50ad3 100644 --- a/src/mapleall/mpl2mpl/src/gen_check_cast.cpp +++ b/src/mapleall/mpl2mpl/src/gen_check_cast.cpp @@ -23,6 +23,15 @@ constexpr char kMCCReflectThrowCastException[] = "MCC_Reflect_ThrowCastException constexpr char kMCCReflectCheckCastingNoArray[] = "MCC_Reflect_Check_Casting_NoArray"; constexpr char kMCCReflectCheckCastingArray[] = "MCC_Reflect_Check_Casting_Array"; constexpr char kCastTargetClass[] = "castTargetClass"; +constexpr char kObjectClassSym[] = "_objectClassSym"; +constexpr char kMCCIsAssignableFrom[] = "MCC_IsAssignableFrom"; +constexpr char kMCCThrowCastException[] = "MCC_ThrowCastException"; +constexpr char kClinitBridge[] = "clinitbridge"; +constexpr char kInstanceOfCacheFalse[] = "instanceOfCacheFalse"; +constexpr char kCacheTrueClass[] = "cacheTrueClass"; +constexpr char kCacheFalseClass[] = "cacheFalseClass"; +constexpr char kTargetClass[] = "targetClass"; +constexpr char kIsAssignableFromResult[] = "isAssignableFromResult"; } // namespace // This phase does two things: @@ -41,6 +50,7 @@ CheckCastGenerator::CheckCastGenerator(MIRModule &mod, KlassHierarchy *kh, bool InitFuncs(); } +PreCheckCast::PreCheckCast(MIRModule &mod, KlassHierarchy *kh, bool dump) : FuncOptimizeImpl(mod, kh, dump) {} void CheckCastGenerator::InitTypes() { const MIRType *javaLangObjectType = WKTypes::Util::GetJavaLangObjectType(); @@ -59,10 +69,15 @@ void CheckCastGenerator::InitFuncs() { checkCastingArray = builder->GetOrCreateFunction(kMCCReflectCheckCastingArray, TyIdx(PTY_void)); checkCastingArray->SetAttr(FUNCATTR_nosideeffect); + mccIsAssignableFrom = + builder->GetOrCreateFunction(kMCCIsAssignableFrom, GlobalTables::GetTypeTable().GetUInt1()->GetTypeIndex()); + castExceptionFunc = builder->GetOrCreateFunction(kMCCThrowCastException, TyIdx(PTY_void)); + castExceptionFunc->SetAttr(FUNCATTR_nosideeffect); } MIRSymbol *CheckCastGenerator::GetOrCreateClassInfoSymbol(const std::string &className) { std::string classInfoName = CLASSINFO_PREFIX_STR + className; + builder->GlobalLock(); MIRSymbol *classInfoSymbol = builder->GetGlobalDecl(classInfoName); if (classInfoSymbol == nullptr) { GStrIdx gStrIdx = GlobalTables::GetStrTable().GetStrIdxFromName(className); @@ -73,6 +88,7 @@ MIRSymbol *CheckCastGenerator::GetOrCreateClassInfoSymbol(const std::string &cla // Creating global symbol needs synchronization. classInfoSymbol = builder->CreateGlobalDecl(classInfoName, *GlobalTables::GetTypeTable().GetPtr(), sclass); } + builder->GlobalUnlock(); return classInfoSymbol; } @@ -106,7 +122,7 @@ void CheckCastGenerator::GenCheckCast(StmtNode &stmt) { MIRType *checkType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(checkTyidx); Klass *checkKlass = klassHierarchy->GetKlassFromTyIdx(static_cast(checkType)->GetPointedTyIdx()); - { + if (funcWithoutCastCheck.find(currFunc->GetName()) == funcWithoutCastCheck.end()) { if ((checkKlass != nullptr) && (checkKlass->GetKlassName() != "")) { if (checkKlass->GetKlassName() == namemangler::kJavaLangObjectStr) { const size_t callNodeNopndSize1 = callNode->GetNopndSize(); @@ -183,14 +199,18 @@ void CheckCastGenerator::GenCheckCast(StmtNode &stmt) { elementName == "S" || elementName == "J" || elementName == "D" || elementName == "Z" || elementName == "V") { std::string primClassinfoName = PRIMITIVECLASSINFO_PREFIX_STR + elementName; + builder->GlobalUnlock(); elemClassSt = builder->GetGlobalDecl(primClassinfoName); if (elemClassSt == nullptr) { elemClassSt = builder->CreateGlobalDecl(primClassinfoName, *GlobalTables::GetTypeTable().GetPtr()); } + builder->GlobalUnlock(); } else { elemClassSt = GetOrCreateClassInfoSymbol(elementName); } BaseNode *valueExpr = builder->CreateExprAddrof(0, *elemClassSt); + builder->GlobalLock(); + builder->GlobalUnlock(); MapleVector opnds(currFunc->GetCodeMempoolAllocator().Adapter()); opnds.push_back(valueExpr); const size_t callNodeNopndSize3 = callNode->GetNopndSize(); @@ -294,13 +314,629 @@ BaseNode *CheckCastGenerator::GetObjectShadow(BaseNode *opnd) { return ireadExpr; } +// optimise instance-of && cast +// #1 convert instance-of, cast to check IsAssignableFrom +// 1) check nullptr +// 2) check type, call IsAssignableFrom(targetClass, objClass) +// eg: +// (1). cast: +// intrinsiccallwithtypeassigned <* <$targetClass>> JAVA_CHECK_CAST (dread ref %Reg2_R45718) { dassign %Reg2_R45709 0} +// ==> +// ## check nullptr +// if (ne u1 ptr (dread ref %Reg2_R45718, constval ptr 0)) { +// dassign %objClass 0 (iread ptr <* <$Ljava_2Flang_2FObject_3B>> 1 (dread ref %Reg2_R45718)) +// dassign %targetClass 0 (intrinsicopwithtype ref <* <$targetClass>> JAVA_CONST_CLASS ()) +// ## check type +// dassign %isAssignableFromResult 0 +// (intrinsicopwithtype ref <* <$targetClass>> JAVA_ISASSIGNABLEFROM (dread ptr %objClass)) +// if (eq u1 ptr (dread u1 %isAssignableFromResult, constval u1 0)) { +// call &MCC_ThrowCastException (dread ptr %targetClass, dread ref %Reg2_R45718) +// } +// } +// dassign %Reg2_R45709 0 (dread ref %Reg2_R45718) +// +// (2) instance-of +// dassign %Reg0_Z 0 (intrinsicopwithtype u1 <* <$targetClass>> JAVA_INSTANCE_OF (dread ref %Reg0_R45718)) +// ==> +// ## check nullptr +// if (ne u1 ptr (dread ref %Reg0_R45718, constval ptr 0)) { +// dassign %objClass 0 (iread ptr <* <$Ljava_2Flang_2FObject_3B>> 1 (dread ref %Reg0_R45718)) +// dassign %Reg0_Z 0 (intrinsicopwithtype ref <* <$targetClass>> JAVA_ISASSIGNABLEFROM (dread ptr %objClass)) +// } else { +// dassign %Reg0_Z 0 (constval u1 0) +// } +// +// #2 optimise type check(IsAssignableFrom(targetClass, objClass)) +// 1) slow path, invoke runtime api to check +// 2) fast path, use cache to check type first, if fail, then go to slow path +// fast path implement: +// (1) target class is is final class or is private and inner class and has no subclass +// it means there can't be subclass of target class,so if a obj is instance of target +// class , the obj must be referred the target class,replace the instance-of with +// maple IR,the IR do the things check if obj.getClass() == target_class,below is the detail +// suppose the obj is %obj, target-class is T,result is saved in reg %1 +// regassign u1 %1 (constval u1 0) +// brfalse (ne u1 ptr (regread ref %obj, constval ptr 0)) #check if obj is null +// #check if obj's class is equal the target class ,if equal set the result 1 +// brflase (eq u1 ptr( +// iread ptr <* <$Ljava_2Flang_2FObject_3B>> 1 (regread ref %obj), +// addrof ptr T)) +// regassign u1 %1 (constval u1 1) +// +// (2) check cache +// a. check objClass equal to targetClass, if fail, then +// b. check objClass.cacheTrueClass equal to targetClass, if fail, then +// c. check objClass.cacheTFalseClass equal to targetClass, if fail, then +// b. go to slow path +// eg: +// dassign %Reg0_Z 0 (intrinsicopwithtype ref <* <$targetClass>> JAVA_ISASSIGNABLEFROM (dread ptr %objClass)) +// ==> +// ##set result true first +// dassign %Reg0_Z 0 (constval u1 1) +// if (ne u1 ptr (dread ptr %objClass, dread ptr %targetClass)) { +// // load cacheTrueClass, it stored in runtime +// dassign %cacheTrueClass 0 (iread u64 <* <$__class_meta__>> 11 (dread ptr %objClass)) +// if (ne u1 ptr (dread ptr %targetClass, dread u64 %cacheTrueClass)) { +// ##load cacheFalseClass, it stored in runtime +// dassign %cacheFalseClass 0 (iread u64 <* <$__class_meta__>> 10 (dread ptr %objClass)) +// if (eq u1 ptr ( +// dread ptr %targetClass, +// lshr u64 (dread u64 %cacheFalseClass, constval u8 32))) { +// dassign %Reg0_Z 0 (constval u1 0) +// } else { +// ##check cache fail, got to slow path, check in runtime +// callassigned &MCC_IsAssignableFrom (dread ptr %objClass, dread ptr %targetClass) { dassign %Reg0_Z 0 } +// } +// } +// } +void CheckCastGenerator::AssignedCastValue(StmtNode &stmt) { + if (stmt.GetOpCode() == OP_intrinsiccallwithtype) { + return; + } + // Assigned + auto *assignedCallNode = static_cast(&stmt); + MapleVector nopnd = assignedCallNode->GetNopnd(); + BaseNode *opnd = nopnd[0]; + ASSERT(!assignedCallNode->GetReturnVec().empty(), "container check"); + CallReturnPair callReturnPair = assignedCallNode->GetCallReturnPair(0); + StmtNode *assignReturnTypeNode = nullptr; + if (!callReturnPair.second.IsReg()) { + assignReturnTypeNode = builder->CreateStmtDassign(callReturnPair.first, callReturnPair.second.GetFieldID(), opnd); + } else { + PregIdx pregIdx = callReturnPair.second.GetPregIdx(); + MIRPreg *mirpreg = currFunc->GetPregTab()->PregFromPregIdx(pregIdx); + assignReturnTypeNode = builder->CreateStmtRegassign(mirpreg->GetPrimType(), pregIdx, opnd); + } + currFunc->GetBody()->InsertAfter(&stmt, assignReturnTypeNode); +} + +void CheckCastGenerator::ConvertCheckCastToIsAssignableFrom(StmtNode &stmt) { + AssignedCastValue(stmt); + + auto *callNode = static_cast(&stmt); + MIRType *checkType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(callNode->GetTyIdx()); + auto *ptrCheckType = static_cast(checkType); + MIRType *ptype = ptrCheckType->GetPointedType(); + MIRTypeKind kd = ptype->GetKind(); + + if (kd == kTypeClass || kd == kTypeInterface || kd == kTypeJArray) { + if (funcWithoutCastCheck.find(currFunc->GetName()) != funcWithoutCastCheck.end()) { + currFunc->GetBody()->RemoveStmt(&stmt); + return; + } + + StmtNode *objectClassAssign = nullptr; + StmtNode *isAssignableFromResultAssign = nullptr; + BaseNode *objectClassReadNode = nullptr; + BaseNode *checkTypeReadNode = nullptr; + StmtNode *checkTypeAssign = nullptr; + BaseNode *isAssignableFromResultReadNode = nullptr; + BaseNode *isAssignableFromNode = nullptr; + MapleVector nopnd = callNode->GetNopnd(); + BaseNode *opnd = nopnd[0]; + BaseNode *ireadShadowExpr = GetObjectShadow(opnd); + + MapleVector arguments(builder->GetCurrentFuncCodeMpAllocator()->Adapter()); + BaseNode *checkTypeNode = builder->CreateExprIntrinsicop(INTRN_JAVA_CONST_CLASS, OP_intrinsicopwithtype, + *checkType, arguments); + ConstvalNode *falseVal = builder->GetConstUInt1(false); + BaseNode *nullVal = builder->CreateIntConst(0, PTY_ptr); + if (opnd->op == OP_regread) { + PrimType classPrimType = ireadShadowExpr->GetPrimType(); + PregIdx objectClassSymPregIdx = currFunc->GetPregTab()->CreatePreg(classPrimType); + objectClassAssign = builder->CreateStmtRegassign(classPrimType, objectClassSymPregIdx, ireadShadowExpr); + objectClassReadNode = builder->CreateExprRegread(PTY_ptr, objectClassSymPregIdx); + + PregIdx checkTypePregIdx = currFunc->GetPregTab()->CreatePreg(classPrimType); + checkTypeAssign = builder->CreateStmtRegassign(classPrimType, checkTypePregIdx, checkTypeNode); + checkTypeReadNode = builder->CreateExprRegread(PTY_ptr, checkTypePregIdx); + + MapleVector opndArgs(builder->GetCurrentFuncCodeMpAllocator()->Adapter()); + opndArgs.push_back(objectClassReadNode); + isAssignableFromNode = + builder->CreateExprIntrinsicop(INTRN_JAVA_ISASSIGNABLEFROM, OP_intrinsicopwithtype, *checkType, opndArgs); + PregIdx IsAssignableFromResultIdx = currFunc->GetPregTab()->CreatePreg(PTY_u1); + isAssignableFromResultAssign = + builder->CreateStmtRegassign(PTY_u1, IsAssignableFromResultIdx, isAssignableFromNode); + isAssignableFromResultReadNode = builder->CreateExprRegread(PTY_u1, IsAssignableFromResultIdx); + } else { + MIRSymbol *objectClassSym = + builder->GetOrCreateLocalDecl(kObjectClassSym, *GlobalTables::GetTypeTable().GetPtr()); + objectClassAssign = builder->CreateStmtDassign(*objectClassSym, 0, ireadShadowExpr); + objectClassReadNode = builder->CreateExprDread(*objectClassSym); + + MIRSymbol *checkTypeSym = builder->GetOrCreateLocalDecl(kTargetClass, *GlobalTables::GetTypeTable().GetPtr()); + checkTypeAssign = builder->CreateStmtDassign(*checkTypeSym, 0, checkTypeNode); + checkTypeReadNode = builder->CreateExprDread(*checkTypeSym); + MapleVector opndArgs(builder->GetCurrentFuncCodeMpAllocator()->Adapter()); + opndArgs.push_back(objectClassReadNode); + isAssignableFromNode = + builder->CreateExprIntrinsicop(INTRN_JAVA_ISASSIGNABLEFROM, OP_intrinsicopwithtype, *checkType, opndArgs); + MIRSymbol *IsAssignableFromResultSym = + builder->GetOrCreateLocalDecl(kIsAssignableFromResult, *GlobalTables::GetTypeTable().GetUInt1()); + isAssignableFromResultAssign = builder->CreateStmtDassign(*IsAssignableFromResultSym, 0, isAssignableFromNode); + isAssignableFromResultReadNode = builder->CreateExprDread(*IsAssignableFromResultSym); + } + + BaseNode *condZero = builder->CreateExprCompare( + OP_ne, *GlobalTables::GetTypeTable().GetUInt1(), *GlobalTables::GetTypeTable().GetPtrType(), opnd, nullVal); + IfStmtNode *ifObjZeroNode = builder->CreateStmtIf(condZero); + + BaseNode *condIsAssignableFrom = builder->CreateExprCompare(OP_eq, *GlobalTables::GetTypeTable().GetUInt1(), + *GlobalTables::GetTypeTable().GetPtrType(), + isAssignableFromResultReadNode, falseVal); + IfStmtNode *ifIsAssignableFromNode = builder->CreateStmtIf(condIsAssignableFrom); + + MapleVector throwArguments(builder->GetCurrentFuncCodeMpAllocator()->Adapter()); + throwArguments.push_back(checkTypeReadNode); + throwArguments.push_back(opnd); + StmtNode *callThrowCastException = builder->CreateStmtCall(castExceptionFunc->GetPuidx(), throwArguments); + ifIsAssignableFromNode->GetThenPart()->AddStatement(callThrowCastException); + + ifObjZeroNode->GetThenPart()->AddStatement(objectClassAssign); + ifObjZeroNode->GetThenPart()->AddStatement(checkTypeAssign); + ifObjZeroNode->GetThenPart()->AddStatement(isAssignableFromResultAssign); + ifObjZeroNode->GetThenPart()->AddStatement(ifIsAssignableFromNode); + + currFunc->GetBody()->ReplaceStmt1WithStmt2(&stmt, ifObjZeroNode); + } else if (kd == kTypeStructIncomplete || kd == kTypeClassIncomplete || kd == kTypeInterfaceIncomplete) { + std::cout << "Warining: CheckCastGenerator::GenCheckCast " << + GlobalTables::GetStrTable().GetStringFromStrIdx(ptype->GetNameStrIdx()) << + " INCOMPLETE \n"; + currFunc->GetBody()->RemoveStmt(&stmt); + } else { + ASSERT(false, "unsupport kind"); + } +} + +void CheckCastGenerator::GenAllCheckCast(bool isHotFunc) { + auto &stmtNodes = currFunc->GetBody()->GetStmtNodes(); + for (auto &stmt : stmtNodes) { + if (stmt.GetOpCode() == OP_intrinsiccallwithtypeassigned || stmt.GetOpCode() == OP_intrinsiccallwithtype) { + auto &callNode = static_cast(stmt); + if (callNode.GetIntrinsic() == INTRN_JAVA_CHECK_CAST) { + if (isHotFunc) { + ConvertCheckCastToIsAssignableFrom(stmt); + } else { + GenCheckCast(stmt); + if (stmt.GetOpCode() == OP_intrinsiccallwithtype) { + currFunc->GetBody()->RemoveStmt(&stmt); + } + } + } + } + } +} + +// Use "srcclass == targetclass" replace instanceof if target class is final. +void CheckCastGenerator::ReplaceNoSubClassIsAssignableFrom(BlockNode &blockNode, StmtNode &stmt, + const MIRPtrType &ptrType, + const IntrinsicopNode &intrinsicNode) { + MapleVector nopnd = intrinsicNode.GetNopnd(); + BaseNode *subClassNode = nopnd[0]; + MIRClassType &targetClassType = static_cast(*ptrType.GetPointedType()); + const std::string &className = GlobalTables::GetStrTable().GetStringFromStrIdx(targetClassType.GetNameStrIdx()); + PregIdx targetClassSymPregIdx = 0; + MIRSymbol *targetClassSym = nullptr; + BaseNode *targetClassNode = nullptr; + // this pattern: + // regassign ptr %6 (intrinsicopwithtype ref <* <$Ljava_lang_String_3B>> JAVA_CONST_CLASS ()) + // regassign u1 %2 (intrinsicopwithtype ref <* <$Ljava_2Flang_2FString_3B>> JAVA_ISASSIGNABLEFROM (regread ptr %1)) + // for intrinsic JAVA_ISASSIGNABLEFROM, we can reuse JAVA_CONST_CLASS result(%6), + // rathe than define symbol again(CreateExprAddrof). + bool isPreDefinedConstClass = IsDefinedConstClass(stmt, ptrType, targetClassSymPregIdx, targetClassSym); + if (!isPreDefinedConstClass) { + MIRSymbol *targetClassSy = GetOrCreateClassInfoSymbol(className); + targetClassNode = builder->CreateExprAddrof(0, *targetClassSy); + } else { + if (targetClassSym == nullptr) { + targetClassNode = builder->CreateExprRegread(PTY_ref, targetClassSymPregIdx); + } else { + targetClassNode = builder->CreateExprDread(*targetClassSym); + } + } + BaseNode *innerCond = builder->CreateExprCompare(OP_eq, *GlobalTables::GetTypeTable().GetUInt1(), + *GlobalTables::GetTypeTable().GetPtrType(), + subClassNode, targetClassNode); + auto *innerIfStmt = static_cast(builder->CreateStmtIfThenElse(innerCond)); + + StmtNode *retFalseNode = nullptr; + StmtNode *retTrueNode = nullptr; + ConstvalNode *falseVal = builder->GetConstUInt1(false); + ConstvalNode *trueVal = builder->GetConstUInt1(true); + if (stmt.op == OP_regassign) { + auto *regAssignNode = static_cast(&stmt); + MIRPreg *mirPreg = currFunc->GetPregTab()->PregFromPregIdx(regAssignNode->GetRegIdx()); + retFalseNode = builder->CreateStmtRegassign(mirPreg->GetPrimType(), regAssignNode->GetRegIdx(), falseVal); + retTrueNode = builder->CreateStmtRegassign(mirPreg->GetPrimType(), regAssignNode->GetRegIdx(), trueVal); + } else { + auto *dAssignNode = static_cast(&stmt); + MIRSymbol *instanceOfRet = currFunc->GetLocalOrGlobalSymbol(dAssignNode->GetStIdx()); + retFalseNode = builder->CreateStmtDassign(*instanceOfRet, 0, falseVal); + retTrueNode = builder->CreateStmtDassign(*instanceOfRet, 0, trueVal); + } + innerIfStmt->GetThenPart()->AddStatement(retTrueNode); + innerIfStmt->GetElsePart()->AddStatement(retFalseNode); + blockNode.ReplaceStmt1WithStmt2(&stmt, innerIfStmt); +} + +bool CheckCastGenerator::IsDefinedConstClass(StmtNode &stmt, const MIRPtrType &targetClassType, + PregIdx &classSymPregIdx, MIRSymbol *&classSym) { + StmtNode *stmtPre = stmt.GetPrev(); + Opcode opPre = stmtPre->GetOpCode(); + if ((opPre != OP_dassign) && (opPre != OP_regassign)) { + return false; + } + + auto *unode = static_cast(stmtPre); + ASSERT(unode->GetRHS() != nullptr, "null ptr check!"); + if (unode->GetRHS()->GetOpCode() != OP_intrinsicopwithtype) { + return false; + } + auto *preIntrinsicNode = static_cast(unode->GetRHS()); + if (preIntrinsicNode->GetIntrinsic() != INTRN_JAVA_CONST_CLASS) { + return false; + } + + MIRType *classType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(preIntrinsicNode->GetTyIdx()); + if (!classType->EqualTo(targetClassType)) { + return false; + } + + if (opPre == OP_regassign) { + auto *regAssignNodePre = static_cast(stmtPre); + classSymPregIdx = regAssignNodePre->GetRegIdx(); + } else { + auto *dAssignNode = static_cast(stmtPre); + classSym = currFunc->GetLocalOrGlobalSymbol(dAssignNode->GetStIdx()); + } + return true; +} + +// inline check cache, it implements __MRT_IsAssignableFromCheckCache +void CheckCastGenerator::ReplaceIsAssignableFromUsingCache(BlockNode &blockNode, StmtNode &stmt, + const MIRPtrType &targetClassType, + const IntrinsicopNode &intrinsicNode) { + StmtNode *resultFalse = nullptr; + StmtNode *resultTrue = nullptr; + StmtNode *cacheFalseClassesAssign = nullptr; + StmtNode *cacheTrueClassesAssign = nullptr; + StmtNode *targetClassAssign = nullptr; + BaseNode *targetClassReadNode = nullptr; + BaseNode *cacheFalseClassesReadNode = nullptr; + BaseNode *cacheTrueClassesReadNode = nullptr; + BaseNode *cacheFalseClasses = nullptr; + BaseNode *cacheTrueClasses = nullptr; + StmtNode *callMCCIsAssignableFromStmt = nullptr; + PregIdx targetClassSymPregIdx = 0; + MIRSymbol *targetClassSym = nullptr; + bool isDefinedConstClass = IsDefinedConstClass(stmt, targetClassType, targetClassSymPregIdx, targetClassSym); + + MapleVector nopnd = intrinsicNode.GetNopnd(); + BaseNode *objectClassNode = nopnd[0]; + MapleVector arguments(builder->GetCurrentFuncCodeMpAllocator()->Adapter()); + BaseNode *targetClassNode = + builder->CreateExprIntrinsicop(INTRN_JAVA_CONST_CLASS, OP_intrinsicopwithtype, targetClassType, arguments); + FieldID superCacheTrueFldid = builder->GetStructFieldIDFromFieldName(*classinfoType, kClinitBridge); + FieldID superCacheFalseFldid = builder->GetStructFieldIDFromFieldName(*classinfoType, kInstanceOfCacheFalse); + + ConstvalNode *falseVal = builder->GetConstUInt1(false); + ConstvalNode *trueVal = builder->GetConstUInt1(true); + if (stmt.op == OP_regassign) { + auto *regAssignNode = static_cast(&stmt); + PrimType classPrimType = objectClassNode->GetPrimType(); + MIRPreg *mirPreg = currFunc->GetPregTab()->PregFromPregIdx(regAssignNode->GetRegIdx()); + resultFalse = builder->CreateStmtRegassign(mirPreg->GetPrimType(), regAssignNode->GetRegIdx(), falseVal); + resultTrue = builder->CreateStmtRegassign(mirPreg->GetPrimType(), regAssignNode->GetRegIdx(), trueVal); + + if (isDefinedConstClass == false) { + targetClassSymPregIdx = currFunc->GetPregTab()->CreatePreg(classPrimType); + targetClassAssign = builder->CreateStmtRegassign(classPrimType, targetClassSymPregIdx, targetClassNode); + } + targetClassReadNode = builder->CreateExprRegread(PTY_ptr, targetClassSymPregIdx); + cacheTrueClasses = builder->CreateExprIread(*GlobalTables::GetTypeTable().GetPtr(), *pointerClassMetaType, + superCacheTrueFldid, objectClassNode); + cacheFalseClasses = builder->CreateExprIread(*GlobalTables::GetTypeTable().GetPtr(), *pointerClassMetaType, + superCacheFalseFldid, objectClassNode); + + // cache true class + PregIdx cacheTrueClassSymPregIdx = currFunc->GetPregTab()->CreatePreg(classPrimType); + cacheTrueClassesAssign = builder->CreateStmtRegassign(classPrimType, cacheTrueClassSymPregIdx, cacheTrueClasses); + cacheTrueClassesReadNode = builder->CreateExprRegread(PTY_ptr, cacheTrueClassSymPregIdx); + // cache false class + PregIdx cacheFalseClassSymPregIdx = currFunc->GetPregTab()->CreatePreg(classPrimType); + cacheFalseClassesAssign = + builder->CreateStmtRegassign(classPrimType, cacheFalseClassSymPregIdx, cacheFalseClasses); + cacheFalseClassesReadNode = builder->CreateExprRegread(PTY_ptr, cacheFalseClassSymPregIdx); + + MapleVector opnds(builder->GetCurrentFuncCodeMpAllocator()->Adapter()); + opnds.push_back(objectClassNode); + opnds.push_back(targetClassReadNode); + callMCCIsAssignableFromStmt = builder->CreateStmtCallRegassigned(mccIsAssignableFrom->GetPuidx(), opnds, + regAssignNode->GetRegIdx(), OP_callassigned); + } else { + MIRSymbol *cacheTrueClassSym = + builder->GetOrCreateLocalDecl(kCacheTrueClass, *GlobalTables::GetTypeTable().GetPtr()); + MIRSymbol *cacheFalseClassSym = + builder->GetOrCreateLocalDecl(kCacheFalseClass, *GlobalTables::GetTypeTable().GetPtr()); + auto *dAssignNode = static_cast(&stmt); + MIRSymbol *instanceOfRet = currFunc->GetLocalOrGlobalSymbol(dAssignNode->GetStIdx()); + resultFalse = builder->CreateStmtDassign(*instanceOfRet, 0, falseVal); + resultTrue = builder->CreateStmtDassign(*instanceOfRet, 0, trueVal); + + if (isDefinedConstClass == false) { + targetClassSym = builder->GetOrCreateLocalDecl(kTargetClass, *GlobalTables::GetTypeTable().GetUIntType()); + targetClassAssign = builder->CreateStmtDassign(*targetClassSym, 0, targetClassNode); + } + ASSERT(targetClassSym != nullptr, "null ptr check!"); + targetClassReadNode = builder->CreateExprDread(*targetClassSym); + cacheTrueClasses = builder->CreateExprIread(*GlobalTables::GetTypeTable().GetPtr(), *pointerClassMetaType, + superCacheTrueFldid, objectClassNode); + cacheFalseClasses = builder->CreateExprIread(*GlobalTables::GetTypeTable().GetPtr(), *pointerClassMetaType, + superCacheFalseFldid, objectClassNode); + // cache true class + cacheTrueClassesAssign = builder->CreateStmtDassign(*cacheTrueClassSym, 0, cacheTrueClasses); + cacheTrueClassesReadNode = builder->CreateExprDread(*cacheTrueClassSym); + + // cache false class + cacheFalseClassesAssign = builder->CreateStmtDassign(*cacheFalseClassSym, 0, cacheFalseClasses); + cacheFalseClassesReadNode = builder->CreateExprDread(*cacheFalseClassSym); + + MapleVector opnds(builder->GetCurrentFuncCodeMpAllocator()->Adapter()); + opnds.push_back(objectClassNode); + opnds.push_back(targetClassReadNode); + callMCCIsAssignableFromStmt = + builder->CreateStmtCallAssigned(mccIsAssignableFrom->GetPuidx(), opnds, instanceOfRet, OP_callassigned); + } + + BaseNode *classEqualCond = builder->CreateExprCompare(OP_ne, *GlobalTables::GetTypeTable().GetUInt1(), + *GlobalTables::GetTypeTable().GetPtrType(), + objectClassNode, targetClassReadNode); + auto *classEqualCondIfStmt = static_cast(builder->CreateStmtIf(classEqualCond)); + classEqualCondIfStmt->GetThenPart()->AddStatement(cacheTrueClassesAssign); + + BaseNode *classCacheTrueEqualCond = builder->CreateExprCompare(OP_ne, *GlobalTables::GetTypeTable().GetUInt1(), + *GlobalTables::GetTypeTable().GetPtrType(), + targetClassReadNode, cacheTrueClassesReadNode); + auto *classCacheTrueEqualCondIfStmt = static_cast(builder->CreateStmtIf(classCacheTrueEqualCond)); + classEqualCondIfStmt->GetThenPart()->AddStatement(classCacheTrueEqualCondIfStmt); + + BaseNode *classCacheFalseEqualCond = builder->CreateExprCompare(OP_eq, *GlobalTables::GetTypeTable().GetUInt1(), + *GlobalTables::GetTypeTable().GetPtrType(), + targetClassReadNode, cacheFalseClassesReadNode); + auto *classCacheFalseEqualCondIfStmt = + static_cast(builder->CreateStmtIfThenElse(classCacheFalseEqualCond)); + classCacheFalseEqualCondIfStmt->GetThenPart()->AddStatement(resultFalse); + classCacheFalseEqualCondIfStmt->GetElsePart()->AddStatement(callMCCIsAssignableFromStmt); + + classCacheTrueEqualCondIfStmt->GetThenPart()->AddStatement(cacheFalseClassesAssign); + classCacheTrueEqualCondIfStmt->GetThenPart()->AddStatement(classCacheFalseEqualCondIfStmt); + + blockNode.InsertBefore(&stmt, resultTrue); + if (isDefinedConstClass == false) { + blockNode.InsertBefore(&stmt, targetClassAssign); + } + blockNode.ReplaceStmt1WithStmt2(&stmt, classEqualCondIfStmt); +} + +void CheckCastGenerator::CheckIsAssignableFrom(BlockNode &blockNode, StmtNode &stmt, + const IntrinsicopNode &intrinsicNode) { + MIRType *targetClassType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(intrinsicNode.GetTyIdx()); + auto *ptrType = static_cast(targetClassType); + MIRType *ptype = ptrType->GetPointedType(); + MIRTypeKind kd = ptype->GetKind(); + if (Options::buildApp == 0 && kd == kTypeClass) { + auto *classType = static_cast(ptype); + Klass *clazz = klassHierarchy->GetKlassFromTyIdx(classType->GetTypeIndex()); + if (classType->IsFinal() || (clazz && clazz->IsPrivateInnerAndNoSubClass())) { + ReplaceNoSubClassIsAssignableFrom(blockNode, stmt, *ptrType, intrinsicNode); + return; + } + } + ReplaceIsAssignableFromUsingCache(blockNode, stmt, *ptrType, intrinsicNode); +} + +void CheckCastGenerator::ConvertInstanceofToIsAssignableFrom(StmtNode &stmt, const IntrinsicopNode &intrinsicNode) { + MIRType *targetClassType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(intrinsicNode.GetTyIdx()); + StmtNode *resultFalse = nullptr; + StmtNode *result = nullptr; + StmtNode *objectClassAssign = nullptr; + BaseNode *objectClassReadNode = nullptr; + + MapleVector nopnd = intrinsicNode.GetNopnd(); + BaseNode *opnd = nopnd[0]; + BaseNode *ireadShadowExpr = GetObjectShadow(opnd); + + ConstvalNode *falseVal = builder->GetConstUInt1(false); + BaseNode *nullVal = builder->CreateIntConst(0, PTY_ptr); + if (stmt.op == OP_regassign) { + auto *regAssignNode = static_cast(&stmt); + PrimType classPrimType = ireadShadowExpr->GetPrimType(); + MIRPreg *mirPreg = currFunc->GetPregTab()->PregFromPregIdx(regAssignNode->GetRegIdx()); + resultFalse = builder->CreateStmtRegassign(mirPreg->GetPrimType(), regAssignNode->GetRegIdx(), falseVal); + + PregIdx objectClassSymPregIdx = currFunc->GetPregTab()->CreatePreg(classPrimType); + objectClassAssign = builder->CreateStmtRegassign(classPrimType, objectClassSymPregIdx, ireadShadowExpr); + objectClassReadNode = builder->CreateExprRegread(PTY_ptr, objectClassSymPregIdx); + + MapleVector arguments(builder->GetCurrentFuncCodeMpAllocator()->Adapter()); + arguments.push_back(objectClassReadNode); + BaseNode *assignableFromNode = builder->CreateExprIntrinsicop(INTRN_JAVA_ISASSIGNABLEFROM, OP_intrinsicopwithtype, + *targetClassType, arguments); + result = builder->CreateStmtRegassign(mirPreg->GetPrimType(), regAssignNode->GetRegIdx(), assignableFromNode); + } else { + auto *regAssignNode = static_cast(&stmt); + MIRSymbol *instanceOfRet = currFunc->GetLocalOrGlobalSymbol(regAssignNode->GetStIdx()); + resultFalse = builder->CreateStmtDassign(*instanceOfRet, 0, falseVal); + + MIRSymbol *objectClassSym = builder->GetOrCreateLocalDecl(kObjectClassSym, *GlobalTables::GetTypeTable().GetPtr()); + objectClassAssign = builder->CreateStmtDassign(*objectClassSym, 0, ireadShadowExpr); + objectClassReadNode = builder->CreateExprDread(*objectClassSym); + MapleVector arguments(builder->GetCurrentFuncCodeMpAllocator()->Adapter()); + arguments.push_back(objectClassReadNode); + BaseNode *assignableFromNode = builder->CreateExprIntrinsicop(INTRN_JAVA_ISASSIGNABLEFROM, OP_intrinsicopwithtype, + *targetClassType, arguments); + result = builder->CreateStmtDassign(*instanceOfRet, 0, assignableFromNode); + } + + BaseNode *condZero = builder->CreateExprCompare( + OP_ne, *GlobalTables::GetTypeTable().GetUInt1(), *GlobalTables::GetTypeTable().GetPtrType(), opnd, nullVal); + IfStmtNode *ifObjZeroNode = builder->CreateStmtIfThenElse(condZero); + + ifObjZeroNode->GetThenPart()->AddStatement(objectClassAssign); + ifObjZeroNode->GetThenPart()->InsertLast(result); + ifObjZeroNode->GetElsePart()->AddStatement(resultFalse); + + currFunc->GetBody()->InsertBefore(&stmt, ifObjZeroNode); + currFunc->GetBody()->RemoveStmt(&stmt); +} + +void CheckCastGenerator::OptimizeInstanceof() { + StmtNode *stmt = currFunc->GetBody()->GetFirst(); + StmtNode *next = nullptr; + while (stmt != nullptr) { + next = stmt->GetNext(); + Opcode op = stmt->GetOpCode(); + if (op == OP_dassign || op == OP_regassign) { + auto *unode = static_cast(stmt); + if (unode->GetRHS() != nullptr && unode->GetRHS()->GetOpCode() == OP_intrinsicopwithtype) { + auto *intrinsicNode = static_cast(unode->GetRHS()); + ASSERT(intrinsicNode != nullptr, "null ptr check!"); + if (intrinsicNode->GetIntrinsic() == INTRN_JAVA_INSTANCE_OF) { + ConvertInstanceofToIsAssignableFrom(*stmt, *intrinsicNode); + } + } + } + stmt = next; + } +} + +void CheckCastGenerator::OptimizeIsAssignableFrom() { + StmtNode *stmt = currFunc->GetBody()->GetFirst(); + StmtNode *next = nullptr; + while (stmt != nullptr) { + next = stmt->GetNext(); + Opcode op = stmt->GetOpCode(); + if (op == OP_if) { + auto *ifStmtNode = static_cast(stmt); + BlockNode *thenpart = ifStmtNode->GetThenPart(); + ASSERT(thenpart != nullptr, "null ptr check!"); + StmtNode *thenStmt = thenpart->GetFirst(); + while (thenStmt != nullptr) { + if (thenStmt->GetOpCode() == OP_dassign || thenStmt->GetOpCode() == OP_regassign) { + auto *unode = static_cast(thenStmt); + ASSERT(unode->GetRHS() != nullptr, "null ptr check!"); + if (unode->GetRHS()->GetOpCode() == OP_intrinsicopwithtype) { + auto *intrinsicNode = static_cast(unode->GetRHS()); + if (intrinsicNode->GetIntrinsic() == INTRN_JAVA_ISASSIGNABLEFROM) { + CheckIsAssignableFrom(*thenpart, *thenStmt, *intrinsicNode); + break; + } + } + } + thenStmt = thenStmt->GetNext(); + } + } + stmt = next; + } +} + +void PreCheckCast::ProcessFunc(MIRFunction *func) { + if (func->IsEmpty()) { + return; + } + SetCurrentFunction(*func); + StmtNode *next = nullptr; + for (StmtNode *stmt = currFunc->GetBody()->GetFirst(); stmt != nullptr; stmt = next) { + next = stmt->GetNext(); + if (stmt->GetOpCode() != OP_intrinsiccallwithtypeassigned) { + continue; + } + + auto *callnode = static_cast(stmt); + if (callnode == nullptr || callnode->GetIntrinsic() != INTRN_JAVA_CHECK_CAST) { + continue; + } + + // handle the special case like (Type)null, we dont need a checkcast. + ASSERT(callnode->GetNopndSize() == 1, ""); + BaseNode *opnd = callnode->Opnd(0); + if (opnd->op == OP_constval) { + ASSERT(!callnode->GetReturnVec().empty(), "container check"); + CallReturnPair callretpair = callnode->GetCallReturnPair(0); + StmtNode *assignRet = nullptr; + if (!callretpair.second.IsReg()) { + assignRet = builder->CreateStmtDassign(callretpair.first, callretpair.second.GetFieldID(), opnd); + } else { + PregIdx pregidx = callretpair.second.GetPregIdx(); + MIRPreg *mirpreg = currFunc->GetPregTab()->PregFromPregIdx(pregidx); + assignRet = builder->CreateStmtRegassign(mirpreg->GetPrimType(), pregidx, opnd); + } + func->GetBody()->ReplaceStmt1WithStmt2(stmt, assignRet); + continue; + } + // split OP_intrinsiccallwithtypeassigned to OP_intrinsiccall + dassign. + if (opnd->GetPrimType() != PTY_ref && opnd->GetPrimType() != PTY_ptr) { + continue; + } + ASSERT(!callnode->GetReturnVec().empty(), "container check"); + CallReturnPair callretpair = callnode->GetCallReturnPair(0); + StmtNode *assignRet = nullptr; + if (!callretpair.second.IsReg()) { + assignRet = builder->CreateStmtDassign(callretpair.first, callretpair.second.GetFieldID(), opnd); + } else { + PregIdx pregidx = callretpair.second.GetPregIdx(); + MIRPreg *mirpreg = currFunc->GetPregTab()->PregFromPregIdx(pregidx); + assignRet = builder->CreateStmtRegassign(mirpreg->GetPrimType(), pregidx, opnd); + } + func->GetBody()->InsertAfter(stmt, assignRet); + StmtNode *newCall = builder->CreateStmtIntrinsicCall(callnode->GetIntrinsic(), callnode->GetNopnd(), + callnode->GetTyIdx()); + func->GetBody()->ReplaceStmt1WithStmt2(stmt, newCall); + } +} void CheckCastGenerator::ProcessFunc(MIRFunction *func) { if (func->IsEmpty()) { return; } SetCurrentFunction(*func); - GenAllCheckCast(); + bool isHotFunc = false; + +#ifdef USE_32BIT_REF + const auto &proFileData = GetMIRModule().GetProfile().GetFunctionProf(); + const auto &funcItem = proFileData.find(func->GetName()); + if (funcItem != proFileData.end()) { + int callTimes = (funcItem->second).callTimes; + isHotFunc = callTimes > 0; + } +#endif + + GenAllCheckCast(isHotFunc); + if (isHotFunc) { + OptimizeInstanceof(); + OptimizeIsAssignableFrom(); + } MIRLower mirlowerer(GetMIRModule(), func); mirlowerer.LowerFunc(*func); } diff --git a/src/mapleall/mpl2mpl/src/java_intrn_lowering.cpp b/src/mapleall/mpl2mpl/src/java_intrn_lowering.cpp index 5605da10a04f75c3c86de502f08bf0e12f9de6d8..378a40fb23f0d1f5d0cef13c339ecd2b70eee32a 100644 --- a/src/mapleall/mpl2mpl/src/java_intrn_lowering.cpp +++ b/src/mapleall/mpl2mpl/src/java_intrn_lowering.cpp @@ -18,6 +18,16 @@ #include namespace { +constexpr char kMplSuffix[] = ".mpl"; +constexpr char kClinvocation[] = ".clinvocation"; +constexpr char kJavaLangClassloader[] = "Ljava_2Flang_2FClassLoader_3B"; +constexpr char kFuncClassForname1[] = + "Ljava_2Flang_2FClass_3B_7CforName_7C_28Ljava_2Flang_2FString_3B_29Ljava_2Flang_2FClass_3B"; +constexpr char kFuncClassForname3[] = + "Ljava_2Flang_2FClass_3B_7CforName_7C_28Ljava_2Flang_2FString_3BZLjava_2Flang_2FClassLoader_3B_29Ljava_2Flang_" + "2FClass_3B"; +constexpr char kFuncGetCurrentCl[] = "MCC_GetCurrentClassLoader"; +constexpr char kRetvarCurrentClassloader[] = "retvar_current_classloader"; } // namespace // JavaIntrnLowering lowers several kinds of intrinsics: @@ -26,6 +36,11 @@ namespace { // if yes, turn it into a Retype or CvtType; if no, assert // 2. INTRN_JAVA_FILL_NEW_ARRAY // Turn it into a jarray malloc and jarray element-wise assignment +// +// JavaIntrnLowering also performs the following optimizations: +// 1. Turn single-parameter Class.forName call into three-parameter +// Class.forName call, where the third-parameter points to the +// current class loader being used. namespace maple { inline bool IsConstvalZero(BaseNode &node) { return (node.GetOpCode() == OP_constval) && (static_cast(node).GetConstVal()->IsZero()); @@ -33,8 +48,49 @@ inline bool IsConstvalZero(BaseNode &node) { JavaIntrnLowering::JavaIntrnLowering(MIRModule &mod, KlassHierarchy *kh, bool dump) : FuncOptimizeImpl(mod, kh, dump) { + InitTypes(); + InitFuncs(); + InitLists(); } +void JavaIntrnLowering::InitLists() { + if (Options::dumpClassLoaderInvocation || !Options::classLoaderInvocationList.empty()) { + LoadClassLoaderInvocation(Options::classLoaderInvocationList); + } + if (Options::dumpClassLoaderInvocation) { + // Remove any existing output file. + const std::string &mplName = GetMIRModule().GetFileName(); + CHECK_FATAL(mplName.rfind(kMplSuffix) != std::string::npos, "File name %s does not contain .mpl", mplName.c_str()); + std::string prefix = mplName.substr(0, mplName.rfind(kMplSuffix)); + outFileName = prefix + kClinvocation; + std::remove(outFileName.c_str()); + } +} + +void JavaIntrnLowering::InitTypes() { + GStrIdx gStrIdx = GlobalTables::GetStrTable().GetStrIdxFromName(kJavaLangClassloader); + MIRType *classLoaderType = + GlobalTables::GetTypeTable().GetTypeFromTyIdx(GlobalTables::GetTypeNameTable().GetTyIdxFromGStrIdx(gStrIdx)); + CHECK_FATAL(classLoaderType != nullptr, "Ljava_2Flang_2FClassLoader_3B type can not be null"); + classLoaderPointerToType = GlobalTables::GetTypeTable().GetOrCreatePointerType(*classLoaderType, PTY_ref); +} + +void JavaIntrnLowering::InitFuncs() { + classForName1Func = builder->GetFunctionFromName(kFuncClassForname1); + CHECK_FATAL(classForName1Func != nullptr, "classForName1Func is null in JavaIntrnLowering::InitFuncs"); + classForName3Func = builder->GetFunctionFromName(kFuncClassForname3); + CHECK_FATAL(classForName3Func != nullptr, "classForName3Func is null in JavaIntrnLowering::InitFuncs"); + // MCC_GetCurrentClassLoader. + getCurrentClassLoaderFunc = builder->GetFunctionFromName(kFuncGetCurrentCl); + if (!getCurrentClassLoaderFunc) { + ArgVector clArgs(GetMIRModule().GetMPAllocator().Adapter()); + MIRType *refTy = GlobalTables::GetTypeTable().GetRef(); + clArgs.push_back(ArgPair("caller", refTy)); + getCurrentClassLoaderFunc = builder->CreateFunction(kFuncGetCurrentCl, *refTy, clArgs); + CHECK_FATAL(getCurrentClassLoaderFunc != nullptr, + "getCurrentClassLoaderFunc is null in JavaIntrnLowering::InitFuncs"); + } +} void JavaIntrnLowering::ProcessStmt(StmtNode &stmt) { Opcode opcode = stmt.GetOpCode(); @@ -57,6 +113,12 @@ void JavaIntrnLowering::ProcessStmt(StmtNode &stmt) { } break; } + case OP_callassigned: { + auto &call = static_cast(stmt); + // Currently it's only for classloader. + ProcessForNameClassLoader(call); + break; + } case OP_intrinsiccallwithtypeassigned: { IntrinsiccallNode &intrinCall = static_cast(stmt); if (intrinCall.GetIntrinsic() == INTRN_JAVA_FILL_NEW_ARRAY) { @@ -69,6 +131,133 @@ void JavaIntrnLowering::ProcessStmt(StmtNode &stmt) { } } +void JavaIntrnLowering::CheckClassLoaderInvocation(const CallNode &callNode) const { + MIRFunction *callee = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callNode.GetPUIdx()); + if (clInterfaceSet.find(callee->GetName()) != clInterfaceSet.end()) { + auto range = clInvocationMap.equal_range(currFunc->GetName()); + for (auto i = range.first; i != range.second; ++i) { + const std::string &val = i->second; + if (val == callee->GetName()) { + return; + } + } + CHECK_FATAL(false, + "Check ClassLoader Invocation, failed. \ + Please copy \"%s,%s\" into %s, and submit it to review. mpl file:%s", + namemangler::DecodeName(currFunc->GetName()).c_str(), + namemangler::DecodeName(callee->GetName()).c_str(), Options::classLoaderInvocationList.c_str(), + GetMIRModule().GetFileName().c_str()); + } +} + +void JavaIntrnLowering::DumpClassLoaderInvocation(const CallNode &callNode) { + MIRFunction *callee = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callNode.GetPUIdx()); + if (clInterfaceSet.find(callee->GetName()) != clInterfaceSet.end()) { + builder->GlobalLock(); + std::ofstream outfile; + outfile.open(outFileName, std::ios::out | std::ios::app); + CHECK_FATAL(!outfile.fail(), "Dump ClassLoader Invocation, open file failed."); + outfile << namemangler::DecodeName(currFunc->GetName()) << "," << namemangler::DecodeName(callee->GetName()) + << "\n"; + outfile.close(); + LogInfo::MapleLogger() << "Dump ClassLoader Invocation, \"" << namemangler::DecodeName(currFunc->GetName()) << "," + << namemangler::DecodeName(callee->GetName()) << "\", " << GetMIRModule().GetFileName() + << "\n"; + builder->GlobalUnlock(); + } +} + +void JavaIntrnLowering::LoadClassLoaderInvocation(const std::string &list) { + std::ifstream infile; + infile.open(list); + CHECK_FATAL(!infile.fail(), "Load ClassLoader Invocation, open file %s failed.", list.c_str()); + + bool reachInvocation = false; + std::string line; + // Load ClassLoader Interface&Invocation Config. + // There're two parts: interfaces and invocations in the list. + // Firstly loading interfaces, then loading invocations. + while (getline(infile, line)) { + if (line.empty()) { + continue; // Ignore empty line. + } + if (line.front() == '#') { + continue; // Ignore comment line. + } + // Check if reach invocation parts by searching ',' + if (!reachInvocation && std::string::npos != line.find(',')) { + reachInvocation = true; + } + if (!reachInvocation) { + // Load interface. + (void)clInterfaceSet.insert(namemangler::EncodeName(line)); + } else { + // Load invocation, which has 2 elements seperated by ','. + std::stringstream ss(line); + std::string caller; + std::string callee; + if (!getline(ss, caller, ',')) { + CHECK_FATAL(false, "Load ClassLoader Invocation, wrong format."); + } + if (!getline(ss, callee, ',')) { + CHECK_FATAL(false, "Load ClassLoader Invocation, wrong format."); + } + (void)clInvocationMap.insert(make_pair(namemangler::EncodeName(caller), namemangler::EncodeName(callee))); + } + } + infile.close(); +} + +void JavaIntrnLowering::ProcessForNameClassLoader(CallNode &callNode) { + if (callNode.GetPUIdx() != classForName1Func->GetPuidx()) { + return; + } + BaseNode *arg = nullptr; + if (currFunc->IsStatic()) { + // It's a static function, + // pass caller functions's classinfo directly. + std::string callerName = CLASSINFO_PREFIX_STR; + callerName += currFunc->GetBaseClassName(); + builder->GlobalLock(); + MIRSymbol *callerClassinfoSym = + GlobalTables::GetGsymTable().GetSymbolFromStrIdx(GlobalTables::GetStrTable().GetStrIdxFromName(callerName)); + if (callerClassinfoSym == nullptr) { + callerClassinfoSym = builder->CreateGlobalDecl(callerName, *GlobalTables::GetTypeTable().GetPtr(), kScExtern); + } + builder->GlobalUnlock(); + arg = builder->CreateExprAddrof(0, *callerClassinfoSym); + } else { + // It's an instance function, + // pass caller function's this pointer + CHECK_FATAL(currFunc->GetFormalCount() > 0, "index out of range in JavaIntrnLowering::ProcessForNameClassLoader"); + MIRSymbol *formalst = currFunc->GetFormal(0); + if (formalst->GetSKind() != kStPreg) { + arg = builder->CreateExprDread(*formalst); + } else { + arg = builder->CreateExprRegread(formalst->GetType()->GetPrimType(), currFunc->GetPregTab()->GetPregIdxFromPregno( + formalst->GetValue().preg->GetPregNo())); + } + } + MIRSymbol *currentCL = builder->GetOrCreateLocalDecl(kRetvarCurrentClassloader, *classLoaderPointerToType); + MapleVector args(builder->GetCurrentFuncCodeMpAllocator()->Adapter()); + args.push_back(arg); + CallNode *clCall = builder->CreateStmtCallAssigned(getCurrentClassLoaderFunc->GetPuidx(), args, currentCL); + currFunc->GetBody()->InsertBefore(&callNode, clCall); + // Class.forName(jstring name) ==> + // Class.forName(jstring name, jboolean 1, jobject current_cl) + // Ensure initialized is true. + callNode.GetNopnd().push_back(builder->GetConstUInt1(true)); + // Classloader. + callNode.GetNopnd().push_back(builder->CreateExprDread(*currentCL)); + callNode.numOpnds = callNode.GetNopndSize(); + callNode.SetPUIdx(classForName3Func->GetPuidx()); + if (!Options::dumpClassLoaderInvocation && !Options::classLoaderInvocationList.empty()) { + CheckClassLoaderInvocation(callNode); + } + if (Options::dumpClassLoaderInvocation) { + DumpClassLoaderInvocation(callNode); + } +} void JavaIntrnLowering::ProcessJavaIntrnMerge(StmtNode &assignNode, const IntrinsicopNode &intrinNode) { CHECK_FATAL(intrinNode.GetNumOpnds() == 1, "invalid JAVA_MERGE intrinsic node"); diff --git a/src/mapleall/mpl2mpl/src/native_stub_func.cpp b/src/mapleall/mpl2mpl/src/native_stub_func.cpp index e3eeff923933bd90feaf5f70248c26d3d7918227..827d07b2f3297c91d5ef9bc5914005d0d181c0bc 100644 --- a/src/mapleall/mpl2mpl/src/native_stub_func.cpp +++ b/src/mapleall/mpl2mpl/src/native_stub_func.cpp @@ -33,6 +33,7 @@ NativeStubFuncGeneration::NativeStubFuncGeneration(MIRModule &mod, KlassHierarch auto *jstrPointerType = static_cast(GlobalTables::GetTypeTable().GetOrCreatePointerType(*jstrType, PTY_ref)); jstrPointerTypeIdx = jstrPointerType->GetTypeIndex(); + LoadNativeFuncProperty(); GenerateRegTableEntryType(); GenerateHelperFuncDecl(); GenerateRegFuncTabEntryType(); @@ -126,7 +127,13 @@ void NativeStubFuncGeneration::ProcessFunc(MIRFunction *func) { } func->GetBody()->ResetBlock(); NativeFuncProperty funcProperty; - bool needNativeCall = (!func->GetAttr(FUNCATTR_critical_native)) && (funcProperty.jniType == kJniTypeNormal); + bool isStaticBindingNative = IsStaticBindingMethod(func->GetName()); + bool existsFuncProperty = GetNativeFuncProperty(func->GetName(), funcProperty); + if (existsFuncProperty && funcProperty.jniType == kJniTypeCriticalNative) { + func->SetAttr(FUNCATTR_critical_native); + } + bool needNativeCall = (!func->GetAttr(FUNCATTR_critical_native)) && + (!existsFuncProperty || funcProperty.jniType == kJniTypeNormal) && !isStaticBindingNative; GStrIdx classObjSymStrIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(CLASSINFO_PREFIX_STR + func->GetBaseClassName()); MIRSymbol *classObjSymbol = GlobalTables::GetGsymTable().GetSymbolFromStrIdx(classObjSymStrIdx); @@ -177,17 +184,26 @@ void NativeStubFuncGeneration::ProcessFunc(MIRFunction *func) { if (!func->GetAttr(FUNCATTR_critical_native)) { if (needNativeCall) { func->GetBody()->AddStatement(preFuncCall); - // set up env - allocCallArgs.push_back(Options::usePreg - ? (static_cast(builder->CreateExprRegread(PTY_ptr, envPregIdx))) - : (static_cast(builder->CreateExprDread(*envPtrSym)))); + if (existsFuncProperty && funcProperty.useEnv == 0) { + // set up env + allocCallArgs.push_back(builder->CreateIntConst(0, PTY_i32)); + } else { + // set up env + allocCallArgs.push_back(Options::usePreg + ? (static_cast(builder->CreateExprRegread(PTY_ptr, envPregIdx))) + : (static_cast(builder->CreateExprDread(*envPtrSym)))); + } } else { // set up env allocCallArgs.push_back(builder->CreateIntConst(0, PTY_i32)); } // set up class if (func->GetAttr(FUNCATTR_static)) { - allocCallArgs.push_back(builder->CreateExprAddrof(0, *classObjSymbol)); + if (existsFuncProperty && funcProperty.useClassObj == 0) { + allocCallArgs.push_back(builder->CreateIntConst(0, PTY_i32)); + } else { + allocCallArgs.push_back(builder->CreateExprAddrof(0, *classObjSymbol)); + } } } for (uint32 i = 0; i < func->GetFormalCount(); ++i) { @@ -210,7 +226,7 @@ void NativeStubFuncGeneration::ProcessFunc(MIRFunction *func) { if (Options::regNativeFunc) { GenerateRegisteredNativeFuncCall(*func, nativeFunc, allocCallArgs, stubFuncRet); } - bool needDecodeRef = (func->GetReturnType()->GetPrimType() == PTY_ref); + bool needDecodeRef = (func->GetReturnType()->GetPrimType() == PTY_ref) && !isStaticBindingNative; if (needDecodeRef) { MapleVector decodeArgs(func->GetCodeMempoolAllocator().Adapter()); CHECK_FATAL(stubFuncRet != nullptr, "stubfunc_ret is nullptr"); @@ -242,14 +258,15 @@ void NativeStubFuncGeneration::ProcessFunc(MIRFunction *func) { NaryStmtNode *syncExit = builder->CreateStmtNary(OP_syncexit, monitor); func->GetBody()->AddStatement(syncExit); } - bool needCheckExceptionCall = needNativeCall; + bool needCheckExceptionCall = needNativeCall || isStaticBindingNative; // check pending exception just before leaving this stub frame except for critical natives if (needCheckExceptionCall) { MapleVector getExceptArgs(func->GetCodeMempoolAllocator().Adapter()); CallNode *callGetExceptFunc = builder->CreateStmtCallAssigned(MRTCheckThrowPendingExceptionFunc->GetPuidx(), getExceptArgs, nullptr, OP_callassigned); func->GetBody()->AddStatement(callGetExceptFunc); - } else if (!func->GetAttr(FUNCATTR_critical_native)) { + } else if (!func->GetAttr(FUNCATTR_critical_native) && + !(existsFuncProperty && funcProperty.jniType == kJniTypeCriticalNeedArg)) { MapleVector frameStatusArgs(func->GetCodeMempoolAllocator().Adapter()); CallNode *callSetFrameStatusFunc = builder->CreateStmtCallAssigned(MCCSetReliableUnwindContextFunc->GetPuidx(), frameStatusArgs, nullptr, OP_callassigned); @@ -259,6 +276,10 @@ void NativeStubFuncGeneration::ProcessFunc(MIRFunction *func) { StmtNode *stmt = builder->CreateStmtReturn(builder->CreateExprDread(*stubFuncRet)); func->GetBody()->AddStatement(stmt); } + if (existsFuncProperty && funcProperty.jniType == kJniTypeCriticalNeedArg) { + func->UnSetAttr(FUNCATTR_fast_native); + func->SetAttr(FUNCATTR_critical_native); + } } void NativeStubFuncGeneration::GenerateRegFuncTabEntryType() { @@ -344,9 +365,11 @@ void NativeStubFuncGeneration::GenerateRegisteredNativeFuncCall(MIRFunction &fun // read func ptr from symbol auto readFuncPtr = builder->CreateExprDread(*funcPtrSym); NativeFuncProperty funcProperty; - bool needCheckThrowPendingExceptionFunc = - (!func.GetAttr(FUNCATTR_critical_native)) && (funcProperty.jniType == kJniTypeNormal); - bool needIndirectCall = func.GetAttr(FUNCATTR_critical_native) || func.GetAttr(FUNCATTR_fast_native); + bool existsFuncProperty = GetNativeFuncProperty(func.GetName(), funcProperty); + bool needCheckThrowPendingExceptionFunc = (!func.GetAttr(FUNCATTR_critical_native)) && + (!existsFuncProperty || funcProperty.jniType == kJniTypeNormal); + bool needIndirectCall = func.GetAttr(FUNCATTR_critical_native) || func.GetAttr(FUNCATTR_fast_native) || + (existsFuncProperty && funcProperty.jniType == kJniTypeCriticalNeedArg); // Get current native method function ptr from reg_jni_func_tab slot BaseNode *regReadExpr = builder->CreateExprDread(*funcPtrSym); @@ -500,6 +523,16 @@ void NativeStubFuncGeneration::GenerateRegisteredNativeFuncCall(MIRFunction &fun func.GetBody()->AddStatement(icall); } +// Use wrapper to call the native function, the logic is: +// if func is fast_native or critical_native { +// icall[assigned](args, ...)[{ret}] +// } else { +// if num_of_args < 8 { +// call MCC_CallSlowNative(nativeFunc, ...) +// } else { +// call MCC_CallSlowNativeExt(nativeFunc, num_of_args, ...) +// } +// } StmtNode *NativeStubFuncGeneration::CreateNativeWrapperCallNode(MIRFunction &func, BaseNode *funcPtr, MapleVector &args, const MIRSymbol *ret, bool needIndirectCall) { @@ -621,6 +654,33 @@ bool NativeStubFuncGeneration::IsStaticBindingMethod(const std::string &methodNa staticBindingMethodsSet.end()); } +bool NativeStubFuncGeneration::GetNativeFuncProperty(const std::string &funcName, NativeFuncProperty &property) { + auto it = nativeFuncPropertyMap.find(funcName); + if (it != nativeFuncPropertyMap.end()) { + property = it->second; + return true; + } + return false; +} + +void NativeStubFuncGeneration::LoadNativeFuncProperty() { + const std::string kNativeFuncPropertyFile = Options::nativeFuncPropertyFile; + std::ifstream in(kNativeFuncPropertyFile, std::ios::in | std::ios::binary); + if (!in.is_open()) { + std::cerr << "Cannot Open native function property file " << kNativeFuncPropertyFile << "\n"; + return; + } + // Mangled name of java function to native function name + while (!in.eof()) { + NativeFuncProperty property; + in >> property.javaFunc >> property.nativeFile >> property.nativeFunc >> + property.jniType >> property.useEnv >> property.useClassObj; + if (!property.javaFunc.empty()) { + nativeFuncPropertyMap[property.javaFunc] = property; + } + } + in.close(); +} void NativeStubFuncGeneration::Finish() { if (!regTableConst->GetConstVec().empty()) { diff --git a/src/mapleall/mpl2mpl/src/reflection_analysis.cpp b/src/mapleall/mpl2mpl/src/reflection_analysis.cpp index 58d0ae179c7d0c1b0446bde1777f2cd4ad45c81a..ecdc683015636262520e25d1a23edaf07acd18e5 100644 --- a/src/mapleall/mpl2mpl/src/reflection_analysis.cpp +++ b/src/mapleall/mpl2mpl/src/reflection_analysis.cpp @@ -35,6 +35,7 @@ using namespace maple; constexpr uint64 kMethodNotVirtual = 0x00000001; constexpr uint64 kMethodFinalize = 0x00000002; constexpr uint64 kMethodSignature = 0x00000008; +constexpr uint64 kMethodMetaCompact = 0x00000004; constexpr uint64 kMethodAbstract = 0x00000010; constexpr uint64 kFieldOffsetIspOffset = 0x00000001; @@ -103,6 +104,7 @@ constexpr char kMethodNameStr[] = "methodname"; constexpr char kInitFuntionStr[] = "_3Cinit_3E"; constexpr char kClassinforoStr[] = "classinforo"; constexpr char kClassloaderStr[] = "classloader"; +constexpr char kINFOFileName[] = "INFO_filename"; constexpr char kLebPadding0Str[] = "lebPadding0"; constexpr char kNumOfFieldsStr[] = "numoffields"; constexpr char kClinitbridgeStr[] = "clinitbridge"; @@ -156,6 +158,14 @@ std::string ReflectionAnalysis::strTabStartHot = std::string(1, '\0'); std::string ReflectionAnalysis::strTabBothHot = std::string(1, '\0'); std::string ReflectionAnalysis::strTabRunHot = std::string(1, '\0'); bool ReflectionAnalysis::strTabInited = false; +uint32_t ReflectionAnalysis::hotMethodMeta = 0; +uint32_t ReflectionAnalysis::totalMethodMeta = 0; +uint32_t ReflectionAnalysis::hotClassMeta = 0; +uint32_t ReflectionAnalysis::totalClassMeta = 0; +uint32_t ReflectionAnalysis::hotFieldMeta = 0; +uint32_t ReflectionAnalysis::totalFieldMeta = 0; +uint32_t ReflectionAnalysis::hotCStr = 0; +uint32_t ReflectionAnalysis::totalCStr = 0; std::map, std::string> ReflectionAnalysis::superClasesIdxMap{}; void ReflectionAnalysis::GenFieldTypeClassInfo(const MIRType &type, const Klass &klass, std::string &classInfo, @@ -255,6 +265,7 @@ void ReflectionAnalysis::InitReflectString() { uint32 ReflectionAnalysis::FindOrInsertRepeatString(const std::string &str, bool isHot, uint8 hotType) { if (strTabInited == false) { // Add default hot strings. + InitReflectString(); strTabInited = true; } return FirstFindOrInsertRepeatString(str, isHot, hotType); @@ -436,6 +447,9 @@ uint32 ReflectionAnalysis::GetTypeNameIdxFromType(const MIRType &type, const Kla case kTypePointer: { auto *ptype = static_cast(type).GetPointedType(); if (ptype->GetKind() == kTypeArray || ptype->GetKind() == kTypeJArray) { + if (kRADebug && 0) { + ptype->Dump(0, false); + } CHECK_NULL_FATAL(ptype); const std::string &javaName = static_cast(ptype)->GetJavaName(); std::string klassJavaDescriptor; @@ -785,6 +799,12 @@ void ReflectionAnalysis::GenMethodMeta(const Klass &klass, MIRStructType &method uint32 fieldID = 1; // @method_in_vtable_index uint32 methodInVtabIndex = GetMethodInVtabIndex(klass, func); + if (Options::deferredVisit2 && VtableAnalysis::IsVtableCandidate(func)) { + // We generate new vtable index in the order of idx instead of -10 when DAI2.0 is open. + // As idx begins at 0, we add 1 to vtable index so it would be starting with 1. + methodInVtabIndex = (methodInVtabIndex != static_cast(kMethodNotFound)) ? methodInVtabIndex + : static_cast(idx + 1); + } mirBuilder.AddIntFieldConst(methodsInfoType, newConst, fieldID++, methodInVtabIndex); // @declaringclass MIRSymbol *dklassSt = GetOrCreateSymbol(CLASSINFO_PREFIX_STR + func.GetBaseClassName(), classMetadataTyIdx); @@ -935,7 +955,107 @@ MIRSymbol *ReflectionAnalysis::GetMethodSignatureSymbol(std::string signature) { return methodSignatureSt; } -MIRSymbol *ReflectionAnalysis::GenMethodsMetaData(const Klass &klass) { +void ReflectionAnalysis::GenMethodMetaCompact(const Klass &klass, MIRStructType &methodsInfoCompactType, int idx, + MIRSymbol &funcSym, MIRAggConst &aggConst, int &allDeclaringClassOffset, + std::unordered_map &baseNameMp, + std::unordered_map &fullNameMp) { + MIRFunction &func = *funcSym.GetFunction(); + MIRAggConst &newConstCompact = *mirModule->GetMemPool()->New(*mirModule, methodsInfoCompactType);; + std::vector methodsCompactLeb128Vec; + uint32 fieldIDCompact = 1; + + // @vtableIndex && flag + uint32 methodInVtabIndex = GetMethodInVtabIndex(klass, func); + if (Options::deferredVisit2 && VtableAnalysis::IsVtableCandidate(func)) { + // We generate new vtable index in the order of idx instead of -10 when DAI2.0 is open. + // As idx begins at 0, we add 1 to vtable index so it would be starting with 1. + methodInVtabIndex = (methodInVtabIndex != static_cast(kMethodNotFound)) ? methodInVtabIndex + : static_cast(idx + 1); + } + constexpr int methodInVtabShift = 16; + uint32 flag = GetMethodFlag(func); + int32 methodInVtabIndexAndFlag = ((flag | kMethodMetaCompact) << methodInVtabShift) | methodInVtabIndex; + mirBuilder.AddIntFieldConst(methodsInfoCompactType, newConstCompact, fieldIDCompact++, methodInVtabIndexAndFlag); + int sizeOfMethodMetaCompactLeb128 = sizeof(int32); + int declaringClassOffset = allDeclaringClassOffset + sizeof(int32); + + // @addr: point function addr + MIRSymbol *methodAddrSt = GenMethodAddrData(funcSym); + if (methodAddrSt != nullptr) { + mirBuilder.AddAddrofFieldConst(methodsInfoCompactType, newConstCompact, fieldIDCompact++, *methodAddrSt); + sizeOfMethodMetaCompactLeb128 += sizeof(int32); + declaringClassOffset += sizeof(int32); + } else { + mirBuilder.AddIntFieldConst(methodsInfoCompactType, newConstCompact, fieldIDCompact++, 0); + } + + // @declaringclass offset, leb128 + namemangler::GetUnsignedLeb128Encode(methodsCompactLeb128Vec, static_cast(declaringClassOffset)); + + // @modifier + uint32 mod = GetMethodModifier(klass, func); + namemangler::GetUnsignedLeb128Encode(methodsCompactLeb128Vec, mod); + + // @methodname + std::string baseName = baseNameMp[func.GetBaseFuncNameStrIdx()]; + uint32 methodnameIdx = FindOrInsertReflectString(baseName); + namemangler::GetUnsignedLeb128Encode(methodsCompactLeb128Vec, methodnameIdx); + + // @argsize: Number of arguments. + size_t argsSize = func.GetParamSize(); + namemangler::GetUnsignedLeb128Encode(methodsCompactLeb128Vec, static_cast(argsSize)); + + // @methodsignature + std::string fullname = fullNameMp[func.GetBaseFuncNameWithTypeStrIdx()]; + std::string signature = GetSignatureFromFullName(fullname); + std::vector typeNames; + GetSignatureTypeNames(signature, typeNames); + for (auto typeName : typeNames) { + uint32 typeNameIdx = FindOrInsertReflectString(typeName); + namemangler::GetUnsignedLeb128Encode(methodsCompactLeb128Vec, typeNameIdx); + } + + // @annotation + int annotationIdx = SolveAnnotation(*klass.GetMIRStructType(), func); + namemangler::GetUnsignedLeb128Encode(methodsCompactLeb128Vec, static_cast(annotationIdx)); + + // @leb128 + sizeOfMethodMetaCompactLeb128 += methodsCompactLeb128Vec.size(); + allDeclaringClassOffset += sizeOfMethodMetaCompactLeb128; + for (auto byte : methodsCompactLeb128Vec) { + uint8 byteValue = byte; + mirBuilder.AddIntFieldConst(methodsInfoCompactType, newConstCompact, fieldIDCompact, byteValue); + } + aggConst.PushBack(&newConstCompact); +} + +MIRSymbol *ReflectionAnalysis::GenMethodsMetaCompact(const Klass &klass, + std::vector> &methodInfoVec, + std::unordered_map &baseNameMp, + std::unordered_map &fullNameMp) { + MIRStructType *classType = klass.GetMIRStructType(); + size_t arraySize = classType->GetMethods().size(); + auto &methodsInfoCompactType = + static_cast(*GlobalTables::GetTypeTable().GetTypeFromTyIdx(methodsInfoCompactTyIdx)); + MIRArrayType &arrayType = *GlobalTables::GetTypeTable().GetOrCreateArrayType(methodsInfoCompactType, arraySize); + MIRAggConst *aggConst = mirModule->GetMemPool()->New(*mirModule, arrayType); + ASSERT(aggConst != nullptr, "null ptr check!"); + int allDeclaringClassOffset = sizeof(int32); + int idx = 0; + for (auto &methodInfo : methodInfoVec) { + MIRSymbol *funcSym = GlobalTables::GetGsymTable().GetSymbolFromStidx(methodInfo.first->first.Idx()); + reflectionMuidStr += funcSym->GetName(); + GenMethodMetaCompact(klass, methodsInfoCompactType, idx++, *funcSym, *aggConst, + allDeclaringClassOffset, baseNameMp, fullNameMp); + } + MIRSymbol *methodsArraySt = GetOrCreateSymbol(namemangler::kMethodsInfoCompactPrefixStr + klass.GetKlassName(), + arrayType.GetTypeIndex(), true); + methodsArraySt->SetStorageClass(kScFstatic); + methodsArraySt->SetKonst(aggConst); + return methodsArraySt; +} + +MIRSymbol *ReflectionAnalysis::GenMethodsMetaData(const Klass &klass, bool isHot) { MIRStructType *classType = klass.GetMIRStructType(); if (classType == nullptr || classType->GetMethods().empty()) { return nullptr; @@ -951,9 +1071,11 @@ MIRSymbol *ReflectionAnalysis::GenMethodsMetaData(const Klass &klass) { // Sort constVec by hashcode. HashCodeComparator comparator(baseNameMp, fullNameMp); std::sort(methodinfoVec.begin(), methodinfoVec.end(), comparator); - MIRSymbol *methodsArraySt = GenMethodsMeta(klass, methodinfoVec, baseNameMp, fullNameMp); + MIRSymbol *methodsArraySt = isHot ? GenMethodsMeta(klass, methodinfoVec, baseNameMp, fullNameMp) : + GenMethodsMetaCompact(klass, methodinfoVec, baseNameMp, fullNameMp); return methodsArraySt; } + void ReflectionAnalysis::GenFieldOffsetConst(MIRAggConst &newConst, const Klass &klass, const MIRStructType &type, std::pair &fieldInfo, uint32 metaFieldID) { @@ -1155,8 +1277,80 @@ MIRSymbol *ReflectionAnalysis::GenFieldsMeta(const Klass &klass, std::vector &fieldInfo, MIRAggConst &aggConstCompact) { + MIRModule &module = *mirModule; + std::vector fieldCompactLeb128Vec; + FieldPair fieldP = fieldInfo.first; + MIRAggConst *newConstCompact = module.GetMemPool()->New(module, fieldsInfoCompactType); + ASSERT(newConstCompact != nullptr, "null ptr check!"); + uint32 fieldIDCompact = 1; + + // @pOffset + MIRSymbol *fieldsOffsetSt = GenFieldOffsetData(klass, fieldInfo); + mirBuilder.AddAddrofFieldConst(fieldsInfoCompactType, *newConstCompact, fieldIDCompact++, *fieldsOffsetSt); + // @modifier + FieldAttrs fa = fieldP.second.second; + uint32 modifier = GetFieldModifier(fa); + namemangler::GetUnsignedLeb128Encode(fieldCompactLeb128Vec, modifier); + // @type + TyIdx fieldTyIdx = fieldP.second.first; + std::string fieldName = GlobalTables::GetStrTable().GetStringFromStrIdx(fieldP.first); + MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldTyIdx); + uint32 typeNameIdx = GetTypeNameIdxFromType(*ty, klass, fieldName); + namemangler::GetUnsignedLeb128Encode(fieldCompactLeb128Vec, typeNameIdx); + // @fieldName + bool isStaticField = (fieldInfo.second == -1); + ConvertFieldName(fieldName, isStaticField); + uint32 fieldname32Idx = FindOrInsertReflectString(fieldName); + namemangler::GetUnsignedLeb128Encode(fieldCompactLeb128Vec, fieldname32Idx); + // @annotation + MIRStructType *classType = klass.GetMIRStructType(); + std::string annoArr; + std::map idxNumMap; + GenAnnotation(idxNumMap, annoArr, *classType, kPragmaVar, fieldName, ty->GetTypeIndex()); + uint32 annotationIdx = GetAnnoCstrIndex(idxNumMap, annoArr, true); + namemangler::GetUnsignedLeb128Encode(fieldCompactLeb128Vec, annotationIdx); + + constexpr uint32 lebpaddingIdx = 2u; + uint32 fieldID = lebpaddingIdx; // lebpadding index + for (auto byte : fieldCompactLeb128Vec) { + uint8 byteValue = byte; + mirBuilder.AddIntFieldConst(fieldsInfoCompactType, *newConstCompact, fieldID, byteValue); + } + aggConstCompact.GetConstVec().push_back(newConstCompact); + (void)fieldIDCompact; +} + +MIRSymbol *ReflectionAnalysis::GenFieldsMetaCompact(const Klass &klass, + std::vector> &fieldsVector) { + size_t size = fieldsVector.size(); + auto &fieldsInfoCompactType = + static_cast(*GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldsInfoCompactTyIdx)); + MIRArrayType *arrayTypeCompact = GlobalTables::GetTypeTable().GetOrCreateArrayType(fieldsInfoCompactType, size); + MIRAggConst *aggConstCompact = mirModule->GetMemPool()->New(*mirModule, *arrayTypeCompact); + ASSERT(aggConstCompact != nullptr, "null ptr check!"); + for (auto &fieldInfo : fieldsVector) { + FieldPair fieldP = fieldInfo.first; + std::string fieldName = GlobalTables::GetStrTable().GetStringFromStrIdx(fieldInfo.first.first); + TyIdx fieldTyIdx = fieldP.second.first; + MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldTyIdx); + ASSERT(ty != nullptr, "null ptr check!"); + // Collect the the information about the fieldName and fieldtyidx. + reflectionMuidStr += fieldName; + reflectionMuidStr += ty->GetName(); + GenFieldMetaCompact(klass, fieldsInfoCompactType, fieldInfo, *aggConstCompact); + } + MIRSymbol *fieldsArrayStCompact = GetOrCreateSymbol( + namemangler::kFieldsInfoCompactPrefixStr + klass.GetKlassName(), arrayTypeCompact->GetTypeIndex(), true); + fieldsArrayStCompact->SetStorageClass(kScFstatic); + fieldsArrayStCompact->SetKonst(aggConstCompact); + return fieldsArrayStCompact; +} + +MIRSymbol *ReflectionAnalysis::GenFieldsMetaData(const Klass &klass, bool isHot) { MIRStructType *classType = klass.GetMIRStructType(); + ASSERT(classType != nullptr, "null ptr check!"); FieldVector fields = classType->GetFields(); FieldVector staticFields = classType->GetStaticFields(); ASSERT(fields.size() < fields.max_size() - staticFields.size(), "size too large"); @@ -1164,6 +1358,7 @@ MIRSymbol *ReflectionAnalysis::GenFieldsMetaData(const Klass &klass) { if (size == 0) { return nullptr; } + std::vector> fieldHashvec(size); size_t i = 0; for (; i < fields.size(); ++i) { @@ -1199,7 +1394,8 @@ MIRSymbol *ReflectionAnalysis::GenFieldsMetaData(const Klass &klass) { ++j; } ASSERT(i == size, "In class %s: %d fields seen, BUT %d fields declared", klass.GetKlassName().c_str(), i, size); - MIRSymbol *fieldsArraySt = GenFieldsMeta(klass, fieldinfoVec, fieldHashvec); + MIRSymbol *fieldsArraySt = isHot ? GenFieldsMeta(klass, fieldinfoVec, fieldHashvec) : + GenFieldsMetaCompact(klass, fieldinfoVec); return fieldsArraySt; } @@ -1461,7 +1657,12 @@ void ReflectionAnalysis::GenHotClassNameString(const Klass &klass) { uint32 ReflectionAnalysis::FindOrInsertReflectString(const std::string &str) { uint8 hotType = 0; - return ReflectionAnalysis::FindOrInsertRepeatString(str, false, hotType); + bool isHot = mirModule->GetProfile().CheckReflectionStrHot(str, hotType); + if (isHot) { + hotCStr++; + } + totalCStr++; + return ReflectionAnalysis::FindOrInsertRepeatString(str, isHot, hotType); } MIRSymbol *ReflectionAnalysis::GetClinitFuncSymbol(const Klass &klass) { @@ -1491,7 +1692,7 @@ void ReflectionAnalysis::GenClassMetaData(Klass &klass) { return; } - + bool compactMeta = Options::compactMeta; std::string klassName = klass.GetKlassName(); reflectionMuidStr += klassName; std::string klassJavaDescriptor; @@ -1521,7 +1722,13 @@ void ReflectionAnalysis::GenClassMetaData(Klass &klass) { } } if (!hasAdded) { - MIRSymbol *fieldsSt = GenFieldsMetaData(klass); + bool profilFieldeHot = module.GetProfile().CheckFieldHot(klassJavaDescriptor); + bool isHotFields = compactMeta ? profilFieldeHot : true; + if (profilFieldeHot) { + hotFieldMeta++; + } + totalFieldMeta++; + MIRSymbol *fieldsSt = GenFieldsMetaData(klass, isHotFields); if (fieldsSt != nullptr) { numOfFields = safe_cast(fieldsSt->GetKonst())->GetConstVec().size(); // All meta data will be weak if dummy constructors. @@ -1533,7 +1740,13 @@ void ReflectionAnalysis::GenClassMetaData(Klass &klass) { // @methods: All methods. uint32 numOfMethods = 0; MIRSymbol *methodsSt; - methodsSt = GenMethodsMetaData(klass); + bool isProfHotMethod = module.GetProfile().CheckMethodHot(klassJavaDescriptor); + bool isHotMethods = compactMeta ? isProfHotMethod : true; + if (isProfHotMethod) { + hotMethodMeta++; + } + totalMethodMeta++; + methodsSt = GenMethodsMetaData(klass, isHotMethods); if (methodsSt != nullptr) { numOfMethods = safe_cast(methodsSt->GetKonst())->GetConstVec().size(); mirBuilder.AddAddrofFieldConst(classMetadataROType, *newConst, fieldID++, *methodsSt); @@ -1583,11 +1796,24 @@ void ReflectionAnalysis::GenClassMetaData(Klass &klass) { bool isAnonymous = IsAnonymousClass(annoArray); bool isLocalClass = IsLocalClass(annoArray); CheckPrivateInnerAndNoSubClass(klass, annoArray); + + bool isColdClass = !(module.GetProfile().CheckClassHot(klassJavaDescriptor)); + if ((Options::lazyBinding || Options::hotFix) && !isLibcore) { + isColdClass = true; + } + if (!isColdClass) { + hotClassMeta++; + } + totalClassMeta++; #ifndef USE_32BIT_REF // @flag // Array class and primitive class is not generated by compiler. uint32 flag = klass.GetFlag(kClassHasFinalizer | kClassReference | kClassFinalizerreferenceSentinel); flag = isAnonymous ? (flag | kClassIsanonymousclass) : flag; + flag = isColdClass ? (flag | kClassIscoldclass) : flag; + flag = klass.HasFlag(kClassRuntimeVerify) ? (flag | kClassRuntimeVerify) : flag; + flag = (Options::lazyBinding && !isLibcore) ? (flag | kClassLazyBindingClass) : flag; + flag = Options::buildApp ? flag | kClassNeedDecouple : flag; mirBuilder.AddIntFieldConst(classMetadataROType, *newConst, fieldID++, flag); // @numofsuperclasses CHECK_FATAL(superClassSize <= 0xffff, "Error:the size of superClass is too big"); @@ -1633,6 +1859,10 @@ void ReflectionAnalysis::GenClassMetaData(Klass &klass) { // Array class and primitive class is not generated by compiler. uint32 flag = klass.GetFlag(kClassHasFinalizer | kClassReference | kClassFinalizerreferenceSentinel); flag = isAnonymous ? (flag | kClassIsanonymousclass) : flag; + flag = isColdClass ? (flag | kClassIscoldclass) : flag; + flag = klass.HasFlag(kClassRuntimeVerify) ? (flag | kClassRuntimeVerify) : flag; + flag = (Options::lazyBinding && !isLibcore) ? (flag | kClassLazyBindingClass) : flag; + flag = Options::buildApp ? flag | kClassNeedDecouple : flag; mirBuilder.AddIntFieldConst(classMetadataType, *newConst, fieldID++, flag); // @numofsuperclasses CHECK_FATAL(superClassSize <= 0xffff, "Error:the size of superClass is too big"); @@ -1640,7 +1870,7 @@ void ReflectionAnalysis::GenClassMetaData(Klass &klass) { #endif // USE_32BIT_REF // @itab GStrIdx strIdx = GlobalTables::GetStrTable().GetStrIdxFromName(ITAB_PREFIX_STR + klass.GetKlassName()); - if (strIdx != 0u) { + if (strIdx != 0u && !Options::buildApp) { MIRSymbol *itableSymbolType = GlobalTables::GetGsymTable().GetSymbolFromStrIdx(strIdx); mirBuilder.AddAddrofFieldConst(classMetadataType, *newConst, fieldID++, *itableSymbolType); } else { @@ -1648,7 +1878,7 @@ void ReflectionAnalysis::GenClassMetaData(Klass &klass) { } // @vtab strIdx = GlobalTables::GetStrTable().GetStrIdxFromName(VTAB_PREFIX_STR + klass.GetKlassName()); - if (strIdx != 0u) { + if (strIdx != 0u && !Options::buildApp) { MIRSymbol *vtableSymbolType = GlobalTables::GetGsymTable().GetSymbolFromStrIdx(strIdx); mirBuilder.AddAddrofFieldConst(classMetadataType, *newConst, fieldID++, *vtableSymbolType); } else { @@ -1906,9 +2136,6 @@ static void ReflectionAnalysisGenStrTab(MIRModule &mirModule, const std::string const std::string &strTabName) { MIRBuilder *mirBuilder = mirModule.GetMIRBuilder(); size_t strTabSize = strTab.length(); - if (strTabSize == 1) { - return; - } MIRArrayType &strTabType = *GlobalTables::GetTypeTable().GetOrCreateArrayType(*GlobalTables::GetTypeTable().GetUInt8(), strTabSize); MIRSymbol *strTabSt = mirBuilder->CreateGlobalDecl(strTabName, strTabType); @@ -1963,8 +2190,33 @@ void ReflectionAnalysis::MarkWeakMethods() { } } +void ReflectionAnalysis::DumpPGOSummary() { + LogInfo::MapleLogger() << "PGO summary \n"; + LogInfo::MapleLogger() << "hot method meta " << ReflectionAnalysis::hotMethodMeta << " total " + << ReflectionAnalysis::totalMethodMeta << std::setprecision(2) << " ratio " + << (static_cast(hotMethodMeta) / totalMethodMeta) << "\n"; + LogInfo::MapleLogger() << "hot field meta " << ReflectionAnalysis::hotFieldMeta << " total " + << ReflectionAnalysis::totalFieldMeta << std::setprecision(2) << " ratio " + << (static_cast(hotFieldMeta) / totalFieldMeta) << "\n"; + LogInfo::MapleLogger() << "hot c-str meta " << ReflectionAnalysis::hotCStr << " total " + << ReflectionAnalysis::totalCStr << std::setprecision(2) << " ratio " + << (static_cast(hotCStr) / totalCStr) << "\n"; + LogInfo::MapleLogger() << "hot class " << ReflectionAnalysis::hotClassMeta << " total " + << ReflectionAnalysis::totalClassMeta << std::setprecision(2) << " ratio " + << (static_cast(hotClassMeta) / totalClassMeta) << "\n"; +} void ReflectionAnalysis::Run() { + uint32 dexNameIdx = mirModule->GetFileinfo(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kINFOFileName)); + const std::string &dexName = GlobalTables::GetStrTable().GetStringFromStrIdx(GStrIdx(dexNameIdx)); + bool deCompressSucc = mirModule->GetProfile().DeCompress(Options::profile, dexName, kAll); + if (!deCompressSucc) { + LogInfo::MapleLogger() << "WARN: DeCompress() failed in ReflectionAnalysis::Run()\n"; + } + if (Options::profileFunc) { + mirModule->GetProfile().SetProfileMode(); + } + isLazyBindingOrDecouple = (Options::lazyBinding && !isLibcore) || Options::buildApp; MarkWeakMethods(); GenMetadataType(*mirModule); const MapleVector &klasses = klassH->GetTopoSortedKlasses(); @@ -1998,6 +2250,9 @@ AnalysisResult *DoReflectionAnalysis::Run(MIRModule *module, ModuleResultMgr *mo CHECK_FATAL(false, "failed to allocate memory"); } rv->Run(); + if (Options::genPGOReport) { + rv->DumpPGOSummary(); + } // This is a transform phase, delete mempool. memPoolCtrler.DeleteMemPool(memPool); return nullptr; diff --git a/src/mapleall/mpl2mpl/src/vtable_analysis.cpp b/src/mapleall/mpl2mpl/src/vtable_analysis.cpp index c715b6e371e7a687a8054a5039496a42a649f9fa..1ea4451c0de8000ce2429f80f1d7cc812549db88 100644 --- a/src/mapleall/mpl2mpl/src/vtable_analysis.cpp +++ b/src/mapleall/mpl2mpl/src/vtable_analysis.cpp @@ -42,8 +42,14 @@ VtableAnalysis::VtableAnalysis(MIRModule &mod, KlassHierarchy *kh, bool dump) : GenVtableList(*klass); if (klass->IsClass() && klass->GetMIRStructType()->IsLocal()) { // We generate itable/vtable definition in the same place where the class is defined - GenVtableDefinition(*klass); - GenItableDefinition(*klass); + // We generate vtable of the class if DAI2.0 is off or its only superclass is object + if (!Options::deferredVisit2) { + GenVtableDefinition(*klass); + GenItableDefinition(*klass); + } else if ((klass->GetSuperKlasses().size() == 1) && + (klass->GetSuperKlass()->GetKlassName() == namemangler::kJavaLangObjectStr)) { + GenVtableDefinition(*klass); + } } if (trace) { DumpVtableList(*klass); @@ -477,6 +483,83 @@ BaseNode *VtableAnalysis::GenVtabItabBaseAddr(BaseNode &obj, bool isVirtual) { (isVirtual ? kKlassVtabFieldID : kKlassItabFieldID), classInfoAddress); } +size_t VtableAnalysis::SearchWithoutRettype(const MIRFunction &callee, const MIRStructType &structType) const { + // Initilization must be < 0 + size_t entryoffset = SIZE_MAX; + GStrIdx calleeSigStrIdx = callee.GetBaseFuncSigStrIdx(); + MIRType *tmpType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(callee.GetReturnTyIdx()); + Klass *targetKlass = nullptr; + bool isCalleeScalar = false; + if (tmpType->GetKind() == kTypePointer && tmpType->GetPrimType() == PTY_ref) { + auto *ptrType = (static_cast(tmpType))->GetPointedType(); + targetKlass = klassHierarchy->GetKlassFromTyIdx(ptrType->GetTypeIndex()); + } else if (tmpType->GetKind() == kTypeScalar) { + isCalleeScalar = true; + } else { + targetKlass = klassHierarchy->GetKlassFromTyIdx(tmpType->GetTypeIndex()); + } + if (!isCalleeScalar) { + CHECK_FATAL(targetKlass != nullptr, "null ptr check"); + } + Klass *curKlass = nullptr; + bool isCurrVtabScalar = false; + bool isFindMethod = false; + for (size_t id = 0; id < structType.GetVTableMethodsSize(); ++id) { + MIRFunction *vtableMethod = builder->GetFunctionFromStidx(structType.GetVTableMethodsElemt(id)->first); + ASSERT_NOT_NULL(vtableMethod); + if (calleeSigStrIdx == vtableMethod->GetBaseFuncSigStrIdx()) { + MIRType *tmpVtabType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(vtableMethod->GetReturnTyIdx()); + Klass *tmpKlass = nullptr; + if (tmpVtabType->GetKind() == kTypePointer && tmpVtabType->GetPrimType() == PTY_ref) { + auto *tmpPtrType = (static_cast(tmpVtabType))->GetPointedType(); + tmpKlass = klassHierarchy->GetKlassFromTyIdx(tmpPtrType->GetTypeIndex()); + } else if (tmpVtabType->GetKind() == kTypeScalar) { + isCurrVtabScalar = true; + } else { + tmpKlass = klassHierarchy->GetKlassFromTyIdx(tmpVtabType->GetTypeIndex()); + } + if (!isCurrVtabScalar) { + CHECK_FATAL(tmpKlass != nullptr, "null ptr check"); + } + if (isCalleeScalar || isCurrVtabScalar) { + if (isFindMethod) { + CHECK_FATAL(klassHierarchy->GetKlassFromTyIdx(structType.GetTypeIndex()) != nullptr, "null ptr check"); + LogInfo::MapleLogger() << "warning: this " + << (klassHierarchy->GetKlassFromTyIdx(structType.GetTypeIndex()))->GetKlassName() + << " has mult methods with the same function name but with different return type!\n"; + break; + } + entryoffset = id; + isFindMethod = true; + continue; + } + CHECK_FATAL(targetKlass != nullptr, "null ptr check"); + if (targetKlass->IsClass() && klassHierarchy->IsSuperKlass(tmpKlass, targetKlass) && + (curKlass == nullptr || klassHierarchy->IsSuperKlass(curKlass, tmpKlass))) { + curKlass = tmpKlass; + entryoffset = id; + } + if (targetKlass->IsClass() && klassHierarchy->IsInterfaceImplemented(tmpKlass, targetKlass)) { + entryoffset = id; + break; + } + if (!targetKlass->IsClass()) { + CHECK_FATAL(tmpKlass != nullptr, "null ptr check"); + if (tmpKlass->IsClass() && klassHierarchy->IsInterfaceImplemented(targetKlass, tmpKlass) && + (curKlass == nullptr || klassHierarchy->IsSuperKlass(curKlass, tmpKlass))) { + curKlass = tmpKlass; + entryoffset = id; + } + if (!tmpKlass->IsClass() && klassHierarchy->IsSuperKlassForInterface(tmpKlass, targetKlass) && + (curKlass == nullptr || klassHierarchy->IsSuperKlass(curKlass, tmpKlass))) { + curKlass = tmpKlass; + entryoffset = id; + } + } + } + } + return entryoffset; +} void VtableAnalysis::ReplaceVirtualInvoke(CallNode &stmt) { MIRFunction *callee = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(stmt.GetPUIdx()); @@ -514,6 +597,55 @@ void VtableAnalysis::ReplaceVirtualInvoke(CallNode &stmt) { break; } } + // If full match function can't be found, try to ignore type of return value + if (entryOffset == SIZE_MAX) { + if (Options::deferredVisit) { + return; + } + entryOffset = SearchWithoutRettype(*callee, *structType); + } + // Add this check for the thirdparty APP compile + if (entryOffset == SIZE_MAX) { + Klass *parentKlass = klassHierarchy->GetKlassFromName(callee->GetBaseClassName()); + CHECK_FATAL(parentKlass != nullptr, "nullptr check."); + bool flag = false; + Klass *currKlass = klassHierarchy->GetKlassFromTyIdx(structType->GetTypeIndex()); + CHECK_FATAL(currKlass != nullptr, "nullptr check."); + if (parentKlass->GetKlassName() == currKlass->GetKlassName()) { + flag = true; + } else { + for (Klass * const &superClass : currKlass->GetSuperKlasses()) { + if (parentKlass->GetKlassName() == superClass->GetKlassName()) { + flag = true; + break; + } + } + if (!flag && parentKlass->IsInterface()) { + for (Klass * const &implClass : currKlass->GetImplKlasses()) { + if (parentKlass->GetKlassName() == implClass->GetKlassName()) { + flag = true; + break; + } + } + } + } + if (!flag) { + LogInfo::MapleLogger() << "warning: func " << callee->GetName() << " is not found in DeVirtual!\n"; + LogInfo::MapleLogger() << "warning: " << callee->GetBaseClassName() << " is not the parent of " + << currKlass->GetKlassName() << "\n"; + } + } + if (entryOffset == SIZE_MAX && (structType->GetKind() == kTypeInterface || structType->GetKind() == kTypeClass)) { + CHECK_FATAL(klassHierarchy->GetKlassFromTyIdx(structType->GetTypeIndex()) != nullptr, "null ptr check"); + LogInfo::MapleLogger() << "warning: func " << callee->GetName() << " is not found in " + << (klassHierarchy->GetKlassFromTyIdx(structType->GetTypeIndex()))->GetKlassName() + << " in VirtualCall!" << "\n"; + if (Options::deferredVisit) { + return; + } + stmt.SetOpCode(OP_callassigned); + return; + } CHECK_FATAL(entryOffset != SIZE_MAX, "Error: method for virtual call cannot be found in all included mplt files. Call to %s in %s", callee->GetName().c_str(), currFunc->GetName().c_str()); @@ -531,9 +663,45 @@ void VtableAnalysis::ReplaceVirtualInvoke(CallNode &stmt) { stmt.SetNumOpnds(stmt.GetNumOpnds() + 1); } +bool VtableAnalysis::CheckInterfaceImplemented(const CallNode &stmt) const { + GStrIdx calleeMethodStrIdx = + (GlobalTables::GetFunctionTable().GetFunctionFromPuidx(stmt.GetPUIdx()))->GetBaseFuncNameWithTypeStrIdx(); + MIRFunction *callee = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(stmt.GetPUIdx()); + Klass *klassFromFuncDependCallee = klassHierarchy->GetKlassFromFunc(callee); + if (klassFromFuncDependCallee == nullptr) { + return false; + } + std::queue klassList; + klassList.push(klassFromFuncDependCallee); + while (!klassList.empty()) { + Klass *currentKlass = klassList.front(); + klassList.pop(); + for (Klass *parentKlass : currentKlass->GetSuperKlasses()) { + if (parentKlass != nullptr) { + klassList.push(parentKlass); + } + } + if (currentKlass->IsClass() || currentKlass->IsClassIncomplete()) { + continue; + } + MIRInterfaceType *interfaceType = currentKlass->GetMIRInterfaceType(); + for (MethodPair &imethodPair : interfaceType->GetMethods()) { + MIRFunction *interfaceMethod = builder->GetFunctionFromStidx(imethodPair.first); + ASSERT_NOT_NULL(interfaceMethod); + GStrIdx interfaceMethodStrIdx = interfaceMethod->GetBaseFuncNameWithTypeStrIdx(); + if (interfaceMethodStrIdx == calleeMethodStrIdx) { + return true; + } + } + } + return false; +} void VtableAnalysis::ReplaceInterfaceInvoke(CallNode &stmt) { CHECK_FATAL(!stmt.GetNopnd().empty(), "container check"); + if (Options::deferredVisit && !CheckInterfaceImplemented(stmt)) { + return; + } BaseNode *tabBaseAddress = GenVtabItabBaseAddr(*stmt.GetNopndAt(0), false); MemPool *currentFuncMp = builder->GetCurrentFuncCodeMp(); ASSERT_NOT_NULL(currentFuncMp); diff --git a/src/mapleall/mpl2mpl/src/vtable_impl.cpp b/src/mapleall/mpl2mpl/src/vtable_impl.cpp index 98b03bac2c430f740d9e7f4ecffea0b6fc8a3d22..4985f61f20b600ad20f5fba17cf3b44bee4c6083 100644 --- a/src/mapleall/mpl2mpl/src/vtable_impl.cpp +++ b/src/mapleall/mpl2mpl/src/vtable_impl.cpp @@ -19,6 +19,7 @@ // This phase is mainly to lower interfacecall into icall namespace { +constexpr int kNumOfMCCParas = 5; #if USE_ARM32_MACRO constexpr char kInterfaceMethod[] = "MCC_getFuncPtrFromItabSecondHash32"; #elif USE_32BIT_REF @@ -30,7 +31,7 @@ constexpr char kInterfaceMethod[] = "MCC_getFuncPtrFromItabSecondHash64"; namespace maple { VtableImpl::VtableImpl(MIRModule &mod, KlassHierarchy *kh, bool dump) - : FuncOptimizeImpl(mod, kh, dump), mirModule(&mod) { + : FuncOptimizeImpl(mod, kh, dump), mirModule(&mod), klassHierarchy(kh) { mccItabFunc = builder->GetOrCreateFunction(kInterfaceMethod, TyIdx(PTY_ptr)); mccItabFunc->SetAttr(FUNCATTR_nosideeffect); } @@ -90,6 +91,25 @@ void VtableImpl::ProcessFunc(MIRFunction *func) { while (stmt != nullptr) { next = stmt->GetNext(); Opcode opcode = stmt->GetOpCode(); +#if defined(TARGARM) || defined(TARGAARCH64) + if (kOpcodeInfo.IsCallAssigned(opcode)) { + CallNode *cnode = static_cast(stmt); + MIRFunction *calleefunc = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(cnode->GetPUIdx()); + const std::set intrisicsList { +#define DEF_MIR_INTRINSIC(X, NAME, INTRN_CLASS, RETURN_TYPE, ...) NAME, +#include "simplifyintrinsics.def" +#undef DEF_MIR_INTRINSIC + }; + const std::string funcName = calleefunc->GetName(); + if (!Options::buildApp && Options::O2 && intrisicsList.find(funcName) != intrisicsList.end() && + funcName != "Ljava_2Flang_2FString_3B_7CindexOf_7C_28Ljava_2Flang_2FString_3B_29I") { + if (Intrinsify(*func, *cnode)) { + stmt = next; + continue; + } + } + } +#endif /* TARGARM || TARGAARCH64 */ switch (opcode) { case OP_regassign: { auto *regassign = static_cast(stmt); @@ -131,16 +151,55 @@ void VtableImpl::ProcessFunc(MIRFunction *func) { } case OP_virtualcall: case OP_virtualcallassigned: { - CHECK_FATAL(false, "VtableImpl::ProcessFunc does not expect to see virtucalcall"); + if (Options::deferredVisit) { + DeferredVisit(*(static_cast(stmt)), CallKind::kVirtualCall); + } else { + CHECK_FATAL(false, "VtableImpl::ProcessFunc does not expect to see virtucalcall"); + } + break; + } + case OP_callassigned: { + if (Options::deferredVisit) { + // When open the decouple static, let the decouple resolve this case. + if (Options::decoupleStatic) { + break; + } + auto *callNode = static_cast(stmt); + MIRFunction *calleeFunc = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callNode->GetPUIdx()); + if (!calleeFunc->IsJava() && calleeFunc->GetBaseClassName().empty()) { + break; + } + Klass *calleeKlass = klassHierarchy->GetKlassFromFunc(calleeFunc); + if (calleeKlass == nullptr || (calleeKlass->GetMIRStructType()->IsLocal() && !calleeFunc->GetBody()) || + calleeKlass->GetMIRStructType()->IsIncomplete()) { + DeferredVisit(*(static_cast(stmt)), CallKind::kStaticCall); + } + } break; } case OP_interfacecall: case OP_interfacecallassigned: { - CHECK_FATAL(false, "VtableImpl::ProcessFunc does not expect to see interfacecall"); + if (Options::deferredVisit) { + DeferredVisit(*(static_cast(stmt)), CallKind::kVirtualCall); + } else { + ASSERT(false, "VtableImpl::ProcessFunc does not expect to see interfacecall"); + } break; } case OP_superclasscallassigned: { - CHECK_FATAL(false, "VtableImpl::ProcessFunc does not expect to see supercall"); + if (!Options::deferredVisit) { + CHECK_FATAL(false, "deferredVisit is not be opened, supercallassigned can't be processed"); + } + auto *callNode = static_cast(stmt); + MIRFunction *calleeFunc = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(callNode->GetPUIdx()); + if (!calleeFunc->IsJava() && calleeFunc->GetBaseClassName().empty()) { + std::cerr << "Error func: " << calleeFunc->GetName() << " " + << "supercallassigned can't be processed" << std::endl; + CHECK_FATAL(false, "supercallassigned can't be processed"); + } + Klass *calleeKlass = klassHierarchy->GetKlassFromFunc(calleeFunc); + CHECK_FATAL(calleeKlass != nullptr, "calleeKlass is nullptr in VtableImpl::ProcessFunc!"); + DeferredVisit(*(static_cast(stmt)), CallKind::kSuperCall); break; } default: @@ -153,6 +212,106 @@ void VtableImpl::ProcessFunc(MIRFunction *func) { } } +void VtableImpl::DeferredVisit(CallNode &stmt, enum CallKind kind) { + MIRFunction *mirFunc = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(stmt.GetPUIdx()); + MemPool *currentFunMp = builder->GetCurrentFuncCodeMp(); + std::string mplClassName = mirFunc->GetBaseClassName(); + std::string mrtClassName; + namemangler::DecodeMapleNameToJavaDescriptor(mplClassName, mrtClassName); + const std::string &funcName = namemangler::DecodeName(mirFunc->GetBaseFuncName()); + std::string sigName = namemangler::DecodeName(mirFunc->GetSignature()); + ReflectionAnalysis::ConvertMethodSig(sigName); + UStrIdx classNameStrIdx = GlobalTables::GetUStrTable().GetOrCreateStrIdxFromName(mrtClassName); + CHECK_NULL_FATAL(currentFunMp); + ConststrNode *classNameNode = currentFunMp->New(classNameStrIdx); + UStrIdx funcNameStrIdx = GlobalTables::GetUStrTable().GetOrCreateStrIdxFromName(funcName); + ConststrNode *funcNameNode = currentFunMp->New(funcNameStrIdx); + UStrIdx sigNameStrIdx = GlobalTables::GetUStrTable().GetOrCreateStrIdxFromName(sigName); + ConststrNode *sigNameNode = currentFunMp->New(sigNameStrIdx); + classNameNode->SetPrimType(PTY_ptr); + funcNameNode->SetPrimType(PTY_ptr); + sigNameNode->SetPrimType(PTY_ptr); + if (kind == CallKind::kStaticCall && mirFunc->IsStatic()) { + const std::string &classinfoName = CLASSINFO_PREFIX_STR + currFunc->GetBaseClassName(); + MIRType *classInfoType = + GlobalTables::GetTypeTable().GetOrCreateClassType(namemangler::kClassMetadataTypeName, *mirModule); + MIRSymbol *classInfoSt = mirModule->GetMIRBuilder()->GetOrCreateGlobalDecl(classinfoName, *classInfoType); + (void)stmt.GetNopnd().insert(stmt.GetNopnd().begin(), + mirModule->GetMIRBuilder()->CreateExprAddrof(0, *classInfoSt)); + stmt.numOpnds++; + } + (void)stmt.GetNopnd().insert(stmt.GetNopnd().begin(), sigNameNode); + (void)stmt.GetNopnd().insert(stmt.GetNopnd().begin(), funcNameNode); + (void)stmt.GetNopnd().insert(stmt.GetNopnd().begin(), classNameNode); + if (kind == CallKind::kStaticCall) { + (void)stmt.GetNopnd().insert(stmt.GetNopnd().begin(), builder->CreateIntConst(CallKind::kStaticCall, PTY_u64)); + } else if (kind == CallKind::kVirtualCall) { + (void)stmt.GetNopnd().insert(stmt.GetNopnd().begin(), builder->CreateIntConst(CallKind::kVirtualCall, PTY_u64)); + } else if (kind == CallKind::kSuperCall) { + (void)stmt.GetNopnd().insert(stmt.GetNopnd().begin(), builder->CreateIntConst(CallKind::kSuperCall, PTY_u64)); + } + stmt.GetNopnd().insert(stmt.GetNopnd().begin(), builder->CreateIntConst(0, PTY_u64)); + stmt.SetNumOpnds(stmt.GetNumOpnds() + kNumOfMCCParas); + stmt.SetOpCode(OP_callassigned); + MIRFunction *mccFunc = builder->GetOrCreateFunction("MCC_DeferredInvoke", mirFunc->GetReturnTyIdx()); + stmt.SetPUIdx(mccFunc->GetPuidx()); + DeferredVisitCheckFloat(stmt, *mirFunc); +} + +void VtableImpl::DeferredVisitCheckFloat(CallNode &stmt, const MIRFunction &mirFunc) { + if (!stmt.GetReturnVec().empty() && mirFunc.GetReturnTyIdx() == PTY_f32) { + if (stmt.GetReturnVec().begin()->second.IsReg()) { + PregIdx returnIdx = stmt.GetReturnVec().begin()->second.GetPregIdx(); + PregIdx newPregReturn = currFunc->GetPregTab()->CreatePreg(PTY_i32); + stmt.GetReturnVec().begin()->second.SetPregIdx(newPregReturn); + BaseNode *baseExpr = builder->CreateExprRetype(*GlobalTables::GetTypeTable().GetFloat(), + *GlobalTables::GetTypeTable().GetInt32(), + builder->CreateExprRegread(PTY_i32, newPregReturn)); + RegassignNode *regAssignNode = builder->CreateStmtRegassign(PTY_f32, returnIdx, baseExpr); + currFunc->GetBody()->InsertAfter(&stmt, regAssignNode); + } else { + MIRSymbol *retSymbol = currFunc->GetSymTab()->GetSymbolFromStIdx(stmt.GetReturnVec()[0].first.Idx()); + MIRSymbol *newSymbol = builder->CreateSymbol(GlobalTables::GetTypeTable().GetInt32()->GetTypeIndex(), + retSymbol->GetName() + "_def", retSymbol->GetSKind(), + retSymbol->GetStorageClass(), currFunc, retSymbol->GetScopeIdx()); + stmt.GetReturnVec()[0].first = newSymbol->GetStIdx(); + AddrofNode *dreadNode = + builder->CreateDread(*currFunc->GetSymTab()->GetSymbolFromStIdx(stmt.GetReturnVec()[0].first.Idx()), PTY_i32); + MapleVector args(builder->GetCurrentFuncCodeMpAllocator()->Adapter()); + args.push_back(dreadNode); + IntrinsicopNode *mergeNode = builder->CreateExprIntrinsicop(INTRN_JAVA_MERGE, OP_intrinsicop, + *GlobalTables::GetTypeTable().GetFloat(), args); + DassignNode *dassignNode = builder->CreateStmtDassign(*retSymbol, 0, mergeNode); + currFunc->GetBody()->InsertAfter(&stmt, dassignNode); + } + } else if (!stmt.GetReturnVec().empty() && mirFunc.GetReturnTyIdx() == PTY_f64) { + if (stmt.GetReturnVec().begin()->second.IsReg()) { + PregIdx returnIdx = stmt.GetReturnVec().begin()->second.GetPregIdx(); + PregIdx newPregReturn = currFunc->GetPregTab()->CreatePreg(PTY_i64); + stmt.GetReturnVec().begin()->second.SetPregIdx(newPregReturn); + BaseNode *baseExpr = builder->CreateExprRetype(*GlobalTables::GetTypeTable().GetDouble(), + *GlobalTables::GetTypeTable().GetInt64(), + builder->CreateExprRegread(PTY_i64, newPregReturn)); + RegassignNode *regAssignNode = builder->CreateStmtRegassign(PTY_f64, returnIdx, baseExpr); + currFunc->GetBody()->InsertAfter(&stmt, regAssignNode); + } else { + MIRSymbol *retSymbol = currFunc->GetSymTab()->GetSymbolFromStIdx(stmt.GetReturnVec()[0].first.Idx()); + MIRSymbol *newSymbol = builder->CreateSymbol(GlobalTables::GetTypeTable().GetInt64()->GetTypeIndex(), + retSymbol->GetName() + "_def", retSymbol->GetSKind(), + retSymbol->GetStorageClass(), currFunc, retSymbol->GetScopeIdx()); + stmt.GetReturnVec()[0].first = newSymbol->GetStIdx(); + AddrofNode *dreadNode = + builder->CreateDread(*currFunc->GetSymTab()->GetSymbolFromStIdx(stmt.GetReturnVec()[0].first.Idx()), + PTY_i64); + MapleVector args(builder->GetCurrentFuncCodeMpAllocator()->Adapter()); + args.push_back(dreadNode); + IntrinsicopNode *mergeNode = builder->CreateExprIntrinsicop(INTRN_JAVA_MERGE, OP_intrinsicop, + *GlobalTables::GetTypeTable().GetFloat(), args); + DassignNode *dassignNode = builder->CreateStmtDassign(*retSymbol, 0, mergeNode); + currFunc->GetBody()->InsertAfter(&stmt, dassignNode); + } + } +} void VtableImpl::ReplaceResolveInterface(StmtNode &stmt, const ResolveFuncNode &resolveNode) { MIRFunction *func = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(resolveNode.GetPuIdx()); @@ -161,7 +320,19 @@ void VtableImpl::ReplaceResolveInterface(StmtNode &stmt, const ResolveFuncNode & PrimType compactPtrPrim = compactPtrType->GetPrimType(); PregIdx pregFuncPtr = currFunc->GetPregTab()->CreatePreg(compactPtrPrim); +#ifndef USE_ARM32_MACRO +#ifdef USE_32BIT_REF + if (Options::inlineCache == 1) { + InlineCacheProcess(stmt, resolveNode, signature, pregFuncPtr); + } else { + ItabProcess(stmt, resolveNode, signature, pregFuncPtr, *compactPtrType, compactPtrPrim); + } +#else // ~USE_32BIT_REF + ItabProcess(stmt, resolveNode, signature, pregFuncPtr, *compactPtrType, compactPtrPrim); +#endif // ~USE_32BIT_REF +#else // ~USE_ARM32_MACRO ItabProcess(stmt, resolveNode, signature, pregFuncPtr, *compactPtrType, compactPtrPrim); +#endif // ~USE_ARM32_MACRO if (stmt.GetOpCode() == OP_regassign) { auto *regAssign = static_cast(&stmt); @@ -216,4 +387,126 @@ void VtableImpl::ItabProcess(StmtNode &stmt, const ResolveFuncNode &resolveNode, currFunc->GetBody()->InsertBefore(&stmt, ifStmt); } +#ifndef USE_ARM32_MACRO +#ifdef USE_32BIT_REF +void VtableImpl::InlineCacheinit() { + constexpr char kInterfaceMethodInlineCache[] = "MCC_getFuncPtrFromItabInlineCache"; + mccItabFuncInlineCache = builder->GetOrCreateFunction(kInterfaceMethodInlineCache, TyIdx(PTY_ptr)); + mccItabFuncInlineCache->SetAttr(FUNCATTR_nosideeffect); + GenInlineCacheTableSymbol(); +} + +void VtableImpl::InlineCacheProcess(StmtNode &stmt, const ResolveFuncNode &resolveNode, const std::string &signature, + PregIdx &pregFuncPtr) { + if (numOfInterfaceCallSite == 0) { + InlineCacheinit(); + } + int64 hashCode = GetHashIndex(signature.c_str()); + uint64 secondHashCode = GetSecondHashIndex(signature.c_str()); + AddrofNode *inlineCacheTableAddrExpr = builder->CreateExprAddrof(0, *inlineCacheTableSym); + ConstvalNode *offsetConstNode = builder->CreateIntConst(numOfInterfaceCallSite, PTY_i64); + ArrayNode *inlineCacheTableEntryNode = + builder->CreateExprArray(*inlineCacheTableType, inlineCacheTableAddrExpr, offsetConstNode); + inlineCacheTableEntryNode->SetBoundsCheck(false); + PregIdx pregTargetCacheEntry = currFunc->GetPregTab()->CreatePreg( + GlobalTables::GetTypeTable().GetOrCreatePointerType(*inlineCacheTableEntryType)->GetPrimType()); + RegassignNode *inlineCacheCacheEntryAssign = builder->CreateStmtRegassign( + GlobalTables::GetTypeTable().GetOrCreatePointerType(*inlineCacheTableEntryType)->GetPrimType(), + pregTargetCacheEntry, inlineCacheTableEntryNode); + currFunc->GetBody()->InsertBefore(&stmt, inlineCacheCacheEntryAssign); + RegreadNode *regReadNodeTmp = builder->CreateExprRegread( + GlobalTables::GetTypeTable().GetOrCreatePointerType(*inlineCacheTableEntryType)->GetPrimType(), + pregTargetCacheEntry); + IreadNode *ireadNodeForClassAndMethodAddr = + builder->CreateExprIread(*GlobalTables::GetTypeTable().GetUInt64(), + *GlobalTables::GetTypeTable().GetOrCreatePointerType(*inlineCacheTableEntryType), + 1, regReadNodeTmp); + PregIdx pregClassAndMethodAddr = + currFunc->GetPregTab()->CreatePreg(GlobalTables::GetTypeTable().GetUInt64()->GetPrimType()); + RegassignNode *klassAndMethodAddrAssign = + builder->CreateStmtRegassign(GlobalTables::GetTypeTable().GetUInt64()->GetPrimType(), + pregClassAndMethodAddr, ireadNodeForClassAndMethodAddr); + currFunc->GetBody()->InsertBefore(&stmt, klassAndMethodAddrAssign); + RegreadNode *entryReadNode = + builder->CreateExprRegread(GlobalTables::GetTypeTable().GetUInt64()->GetPrimType(), pregClassAndMethodAddr); + BinaryNode *methodReadNode = + builder->CreateExprBinary(OP_lshr, *GlobalTables::GetTypeTable().GetUInt64(), entryReadNode, + builder->CreateIntConst(32, GlobalTables::GetTypeTable().GetUInt64()->GetPrimType())); + BaseNode *methodReadNode32 = builder->CreateExprTypeCvt(OP_cvt, *GlobalTables::GetTypeTable().GetUInt32(), + *GlobalTables::GetTypeTable().GetUInt64(), methodReadNode); + RegassignNode *methodAddrInCacheAssign = + builder->CreateStmtRegassign(GlobalTables::GetTypeTable().GetUInt32()->GetPrimType(), + pregFuncPtr, methodReadNode32); + BaseNode *classInfoAddress = resolveNode.GetBOpnd(1); + BaseNode *checkCacheHitExpr = + builder->CreateExprCompare(OP_eq, *GlobalTables::GetTypeTable().GetUInt1(), + *GlobalTables::GetTypeTable().GetUInt32(), classInfoAddress, + entryReadNode); // low 32 in entryReadNode means class metadata cached in cache + IfStmtNode *ifStmt = static_cast(builder->CreateStmtIfThenElse(checkCacheHitExpr)); + ifStmt->GetThenPart()->AddStatement(methodAddrInCacheAssign); + CallMrtInlineCacheFun(stmt, resolveNode, *regReadNodeTmp, hashCode, secondHashCode, signature, pregFuncPtr, *ifStmt); + ++numOfInterfaceCallSite; +} + +void VtableImpl::CallMrtInlineCacheFun(StmtNode &stmt, const ResolveFuncNode &resolveNode, RegreadNode ®ReadNodeTmp, + int64 hashCode, uint64 secondHashCode, const std::string &signature, + PregIdx &pregFuncPtr, IfStmtNode &ifStmt) { + BaseNode *classInfoAddress = resolveNode.GetBOpnd(1); + MapleAllocator *currentFuncMpAllocator = builder->GetCurrentFuncCodeMpAllocator(); + CHECK_FATAL(currentFuncMpAllocator != nullptr, "null ptr check"); + MapleVector opnds(currentFuncMpAllocator->Adapter()); + opnds.push_back(®ReadNodeTmp); + opnds.push_back(classInfoAddress); + opnds.push_back(builder->CreateIntConst(hashCode, PTY_u64)); + opnds.push_back(builder->CreateIntConst(secondHashCode, PTY_u64)); + UStrIdx strIdx = GlobalTables::GetUStrTable().GetOrCreateStrIdxFromName(signature); + MemPool *currentFunMp = builder->GetCurrentFuncCodeMp(); + CHECK_FATAL(currentFunMp != nullptr, "null ptr check"); + ConststrNode *signatureNode = currentFunMp->New(strIdx); + signatureNode->SetPrimType(PTY_ptr); + opnds.push_back(signatureNode); + StmtNode *mccCallStmt = + builder->CreateStmtCallRegassigned(mccItabFuncInlineCache->GetPuidx(), opnds, pregFuncPtr, OP_callassigned); + ifStmt.GetElsePart()->AddStatement(mccCallStmt); + currFunc->GetBody()->InsertBefore(&stmt, &ifStmt); +} + +void VtableImpl::GenInlineCacheTableSymbol() { + // Create inline_cache_table + FieldVector parentFields; + FieldVector fields; + GlobalTables::GetTypeTable().PushIntoFieldVector(fields, "KlassAndMethodAddr", + *GlobalTables::GetTypeTable().GetUInt64()); + inlineCacheTableEntryType = static_cast( + GlobalTables::GetTypeTable().GetOrCreateStructType("InlineCacheTableEntry", + fields, parentFields, GetMIRModule())); + inlineCacheTableType = GlobalTables::GetTypeTable().GetOrCreateArrayType(*inlineCacheTableEntryType, 0); + std::string inlineCacheTableSymName = namemangler::kInlineCacheTabStr + GetMIRModule().GetFileNameAsPostfix(); + inlineCacheTableSym = builder->GetOrCreateGlobalDecl(inlineCacheTableSymName, *inlineCacheTableType); +} + +void VtableImpl::ResolveInlineCacheTable() { + if (numOfInterfaceCallSite == 0) { + ++numOfInterfaceCallSite; + } + inlineCacheTableType->SetSizeArrayItem(static_cast(0), numOfInterfaceCallSite); + MIRAggConst *inlineCacheTableConst = + GetMIRModule().GetMemPool()->New(GetMIRModule(), *inlineCacheTableType); + for (uint32 i = 0; i < numOfInterfaceCallSite; ++i) { + MIRAggConst &entryConst = *GetMIRModule().GetMemPool()->New(GetMIRModule(), + *inlineCacheTableEntryType); + builder->AddIntFieldConst(*inlineCacheTableEntryType, entryConst, 1, 0); + inlineCacheTableConst->PushBack(&entryConst); + } + inlineCacheTableSym->SetStorageClass(kScFstatic); + inlineCacheTableSym->SetKonst(inlineCacheTableConst); +} + +void VtableImpl::Finish() { + if (numOfInterfaceCallSite > 0) { + ResolveInlineCacheTable(); + } +} +#endif // ~USE_32BIT_REF +#endif // ~USE_ARM32_MACRO } // namespace maple diff --git a/src/mrt/deplibs/libmplandroid.so b/src/mrt/deplibs/libmplandroid.so index fab5ba95c496278d67041434ecd3859faeb1f9ac..48552d4c7d630b5a718984b1cd2a20c40f042154 100755 Binary files a/src/mrt/deplibs/libmplandroid.so and b/src/mrt/deplibs/libmplandroid.so differ