123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- #include <unordered_map>
- #include "MethodBodyCache.h"
- #include "MetadataModule.h"
- #include "AOTHomologousImage.h"
- #include "Opcodes.h"
- #include "MetadataDef.h"
- #include "utils/HashUtils.h"
- #include "../RuntimeConfig.h"
- namespace hybridclr
- {
- namespace metadata
- {
- struct ImageTokenPair
- {
- hybridclr::metadata::Image* image;
- uint32_t token;
- };
- struct ImageTokenPairHash
- {
- size_t operator()(const ImageTokenPair& s) const noexcept
- {
- return il2cpp::utils::HashUtils::Combine((size_t)s.image, (size_t)s.token);
- }
- };
- struct ImageTokenPairEqualTo
- {
- bool operator()(const ImageTokenPair& p1, const ImageTokenPair& p2) const
- {
- return p1.image == p2.image && p1.token == p2.token;
- }
- };
- enum class InlineMode : uint8_t
- {
- None,
- Inlineable,
- NotInlineable,
- };
- struct MethodBodyCacheInfo
- {
- MethodBody* methodBody;
- int32_t accessVersion;
- uint16_t accessCount;
- InlineMode inlineMode;
- };
- constexpr int32_t kMinShrinkMethodBodyCacheInterval = 256;
- static bool s_enableShrinkMethodBodyCache = true;
- static int32_t s_methodBodyCacheVersion = 0;
- static Il2CppHashMap<ImageTokenPair, MethodBodyCacheInfo*, ImageTokenPairHash, ImageTokenPairEqualTo> s_methodBodyCache;
- static MethodBodyCacheInfo* GetOrInitMethodBodyCache(hybridclr::metadata::Image* image, uint32_t token)
- {
- ImageTokenPair key = { image, token };
- auto it = s_methodBodyCache.find(key);
- if (it != s_methodBodyCache.end())
- {
- return it->second;
- }
- MethodBody* methodBody = image->GetMethodBody(token);
- MethodBodyCacheInfo* ci = (MethodBodyCacheInfo*)HYBRIDCLR_MALLOC_ZERO(sizeof(MethodBodyCacheInfo));
- *ci = { methodBody, s_methodBodyCacheVersion, 0, InlineMode::None};
- s_methodBodyCache[key] = ci;
- return ci;
- }
- MethodBody* MethodBodyCache::GetMethodBody(hybridclr::metadata::Image* image, uint32_t token)
- {
- MethodBodyCacheInfo* ci = GetOrInitMethodBodyCache(image, token);
- ci->accessVersion = s_methodBodyCacheVersion;
- ++ci->accessCount;
- return ci->methodBody;
- }
- static void ShrinkMethodBodyCache(int32_t shrinkMethodBodyCacheInterval)
- {
- if (s_methodBodyCache.size() <= RuntimeConfig::GetMaxMethodBodyCacheSize())
- {
- return;
- }
- int32_t expiredVersion = s_methodBodyCacheVersion - shrinkMethodBodyCacheInterval;
- for (auto it = s_methodBodyCache.begin(); it != s_methodBodyCache.end(); )
- {
- MethodBodyCacheInfo* ci = it->second;
- // add extra interval when accessCount exceeded 1
- int32_t accessVersion = ci->accessVersion + (ci->accessCount - 1) * shrinkMethodBodyCacheInterval;
- if (accessVersion < expiredVersion)
- {
- if (ci->methodBody)
- {
- ci->methodBody->~MethodBody();
- HYBRIDCLR_FREE(ci->methodBody);
- }
- HYBRIDCLR_FREE(ci);
- s_methodBodyCache.erase(it++);
- }
- else
- {
- ++it;
- }
- }
- }
- void MethodBodyCache::EnableShrinkMethodBodyCache(bool shrink)
- {
- s_enableShrinkMethodBodyCache = shrink;
- if (shrink)
- {
- ++s_methodBodyCacheVersion;
- int32_t shrinkMethodBodyCacheInterval = std::max(RuntimeConfig::GetMaxMethodBodyCacheSize() / 2, kMinShrinkMethodBodyCacheInterval);
- if (s_methodBodyCacheVersion % shrinkMethodBodyCacheInterval == 0)
- {
- ShrinkMethodBodyCache(shrinkMethodBodyCacheInterval);
- }
- }
- }
- static bool IsILCodeInlineable(const byte* ilcodeStart, uint32_t codeSize)
- {
- const byte* codeEnd = ilcodeStart + codeSize;
- const byte* ip = ilcodeStart;
- while (ip < codeEnd)
- {
- const OpCodeInfo* oc = DecodeOpCodeInfo(ip, codeEnd);
- IL2CPP_ASSERT(oc);
- int32_t opCodeSize = GetOpCodeSize(ip, oc);
- ip += opCodeSize;
- int32_t nextOffset = (int32_t)(ip - ilcodeStart);
- IL2CPP_ASSERT(nextOffset >= 0 && nextOffset <= (int32_t)codeSize);
- switch (oc->flow)
- {
- case FlowType::Branch:
- case FlowType::CondBranch:
- case FlowType::Throw:
- {
- return false;
- }
- }
- }
- IL2CPP_ASSERT(ip == codeEnd);
- return true;
- }
- const int32_t kMaxInlineableCodeLength = 16;
- static bool ComputeInlinable(metadata::Image* image, uint32_t token)
- {
- metadata::MethodBody* methodBody = MethodBodyCache::GetMethodBody(image, token);
- if (methodBody == nullptr || methodBody->ilcodes == nullptr)
- {
- return false;
- }
- if (methodBody->codeSize > kMaxInlineableCodeLength || !methodBody->exceptionClauses.empty())
- {
- return false;
- }
- return IsILCodeInlineable(methodBody->ilcodes, methodBody->codeSize);
- }
- bool MethodBodyCache::IsInlineable(const MethodInfo* methodInfo)
- {
- IL2CPP_ASSERT(methodInfo->isInterpterImpl);
- metadata::Image* image = MetadataModule::GetUnderlyingInterpreterImage(methodInfo);
- IL2CPP_ASSERT(image);
- MethodBodyCacheInfo* ci = GetOrInitMethodBodyCache(image, methodInfo->token);
- ci->accessVersion = s_methodBodyCacheVersion;
- ++ci->accessCount;
- if (ci->inlineMode != InlineMode::None)
- {
- return ci->inlineMode == InlineMode::Inlineable;
- }
- bool inlineable = ComputeInlinable(image, methodInfo->token);
- ci->inlineMode = inlineable ? InlineMode::Inlineable : InlineMode::NotInlineable;
- return inlineable;
- }
- void MethodBodyCache::DisableInline(const MethodInfo* methodInfo)
- {
- IL2CPP_ASSERT(methodInfo->isInterpterImpl);
- metadata::Image* image = MetadataModule::GetUnderlyingInterpreterImage(methodInfo);
- IL2CPP_ASSERT(image);
- MethodBodyCacheInfo* ci = GetOrInitMethodBodyCache(image, methodInfo->token);
- ci->inlineMode = InlineMode::NotInlineable;
- }
- }
- }
|