PropertyRecordUsageCache.h 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. namespace Js
  7. {
  8. // Keeps track of inline caches for loads and stores on the contained PropertyRecord.
  9. // Used in PropertyString and JavascriptSymbol.
  10. class PropertyRecordUsageCache sealed
  11. {
  12. private:
  13. Field(const PropertyRecord*) propertyRecord;
  14. Field(PolymorphicInlineCache*) ldElemInlineCache;
  15. Field(PolymorphicInlineCache*) stElemInlineCache;
  16. Field(int) hitRate;
  17. public:
  18. PropertyRecordUsageCache();
  19. PropertyRecordUsageCache(StaticType* type, const PropertyRecord* propertyRecord);
  20. const PropertyRecord* GetPropertyRecord() const { return propertyRecord; }
  21. PolymorphicInlineCache* GetLdElemInlineCache() const;
  22. PolymorphicInlineCache* GetStElemInlineCache() const;
  23. PolymorphicInlineCache* CreateBiggerPolymorphicInlineCache(bool isLdElem);
  24. void RegisterCacheMiss();
  25. int GetHitRate() const { return this->hitRate; };
  26. void RegisterCacheHit() { ++this->hitRate; };
  27. bool ShouldUseCache() const;
  28. bool ShouldDisableWriteCache() const { return propertyRecord && propertyRecord->ShouldDisableWriteCache(); }
  29. static uint32 GetOffsetOfLdElemInlineCache() { return offsetof(PropertyRecordUsageCache, ldElemInlineCache); }
  30. static uint32 GetOffsetOfStElemInlineCache() { return offsetof(PropertyRecordUsageCache, stElemInlineCache); }
  31. static uint32 GetOffsetOfHitRate() { return offsetof(PropertyRecordUsageCache, hitRate); }
  32. template <bool ReturnOperationInfo>
  33. _Success_(return) bool TrySetPropertyFromCache(
  34. _In_ RecyclableObject *const object,
  35. _In_ Var propertyValue,
  36. _In_ ScriptContext *const requestContext,
  37. const PropertyOperationFlags propertyOperationFlags,
  38. _Out_ PropertyValueInfo *const propertyValueInfo,
  39. _In_ RecyclableObject *const owner, // Object that this usage cache is part of
  40. _Out_opt_ PropertyCacheOperationInfo* operationInfo);
  41. template <
  42. bool OwnPropertyOnly,
  43. bool OutputExistence, // When set, propertyValue represents whether the property exists on the instance, not its actual value
  44. bool ReturnOperationInfo>
  45. _Success_(return) bool TryGetPropertyFromCache(
  46. _In_ Var const instance,
  47. _In_ RecyclableObject *const object,
  48. _Out_ Var* const propertyValue,
  49. _In_ ScriptContext* const requestContext,
  50. _Out_ PropertyValueInfo* const propertyValueInfo,
  51. _In_ RecyclableObject* const owner, // Object that this usage cache is part of
  52. _Out_opt_ PropertyCacheOperationInfo* operationInfo)
  53. {
  54. if (ShouldUseCache())
  55. {
  56. PropertyValueInfo::SetCacheInfo(propertyValueInfo, owner, this, GetLdElemInlineCache(), true /* allowResizing */);
  57. // Some caches will look at prototype, so GetOwnProperty lookups must not check these
  58. bool found = CacheOperators::TryGetProperty<
  59. true, // CheckLocal
  60. !OwnPropertyOnly, // CheckProto
  61. !OwnPropertyOnly, // CheckAccessor
  62. !OwnPropertyOnly, // CheckMissing
  63. true, // CheckPolymorphicInlineCache
  64. !OwnPropertyOnly, // CheckTypePropertyCache
  65. false, // IsInlineCacheAvailable
  66. true, // IsPolymorphicInlineCacheAvailable
  67. ReturnOperationInfo,// ReturnOperationInfo
  68. OutputExistence> // OutputExistence
  69. (instance,
  70. false, // isRoot
  71. object,
  72. this->propertyRecord->GetPropertyId(),
  73. propertyValue,
  74. requestContext,
  75. operationInfo,
  76. propertyValueInfo);
  77. if (found)
  78. {
  79. RegisterCacheHit();
  80. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  81. if (PHASE_TRACE1(PropertyCachePhase))
  82. {
  83. Output::Print(_u("PropertyCache: GetElem cache hit for '%s': type %p\n"),
  84. GetString(),
  85. object->GetType());
  86. }
  87. #endif
  88. return true;
  89. }
  90. }
  91. RegisterCacheMiss();
  92. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  93. if (PHASE_TRACE1(PropertyCachePhase))
  94. {
  95. Output::Print(_u("PropertyCache: GetElem cache miss for '%s': type %p, index %d\n"),
  96. GetString(),
  97. object->GetType(),
  98. GetLdElemInlineCache()->GetInlineCacheIndexForType(object->GetType()));
  99. DumpCache(true);
  100. }
  101. #endif
  102. return false;
  103. }
  104. #if ENABLE_DEBUG_CONFIG_OPTIONS
  105. const char16* GetString()
  106. {
  107. return propertyRecord->GetBuffer();
  108. }
  109. private:
  110. void DumpCache(bool ldElemCache)
  111. {
  112. PolymorphicInlineCache * cache = ldElemCache ? GetLdElemInlineCache() : GetStElemInlineCache();
  113. Output::Print(_u("PropertyCache HitRate: %i; types: "), this->hitRate);
  114. for (uint i = 0; i < cache->GetSize(); ++i)
  115. {
  116. Output::Print(_u("%p,"), cache->GetInlineCaches()[i].GetType());
  117. }
  118. Output::Print(_u("\n"));
  119. }
  120. #endif
  121. };
  122. template <bool ReturnOperationInfo>
  123. _Success_(return) inline bool PropertyRecordUsageCache::TrySetPropertyFromCache(
  124. _In_ RecyclableObject *const object,
  125. _In_ Var propertyValue,
  126. _In_ ScriptContext *const requestContext,
  127. const PropertyOperationFlags propertyOperationFlags,
  128. _Out_ PropertyValueInfo *const propertyValueInfo,
  129. _In_ RecyclableObject *const owner, // Object that this usage cache is part of
  130. _Out_opt_ PropertyCacheOperationInfo* operationInfo)
  131. {
  132. if (ShouldUseCache())
  133. {
  134. PropertyValueInfo::SetCacheInfo(propertyValueInfo, owner, this, GetStElemInlineCache(), true /* allowResizing */);
  135. bool found = CacheOperators::TrySetProperty<
  136. true, // CheckLocal
  137. true, // CheckLocalTypeWithoutProperty
  138. true, // CheckAccessor
  139. true, // CheckPolymorphicInlineCache
  140. true, // CheckTypePropertyCache
  141. false, // IsInlineCacheAvailable
  142. true, // IsPolymorphicInlineCacheAvailable
  143. ReturnOperationInfo>
  144. (object,
  145. false, // isRoot
  146. this->propertyRecord->GetPropertyId(),
  147. propertyValue,
  148. requestContext,
  149. propertyOperationFlags,
  150. operationInfo,
  151. propertyValueInfo);
  152. if (found)
  153. {
  154. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  155. if (PHASE_TRACE1(PropertyCachePhase))
  156. {
  157. Output::Print(_u("PropertyCache: SetElem cache hit for '%s': type %p\n"), GetString(), object->GetType());
  158. }
  159. #endif
  160. RegisterCacheHit();
  161. return true;
  162. }
  163. }
  164. RegisterCacheMiss();
  165. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  166. if (PHASE_TRACE1(PropertyCachePhase))
  167. {
  168. Output::Print(_u("PropertyCache: SetElem cache miss for '%s': type %p, index %d\n"),
  169. GetString(),
  170. object->GetType(),
  171. GetStElemInlineCache()->GetInlineCacheIndexForType(object->GetType()));
  172. DumpCache(false);
  173. }
  174. #endif
  175. return false;
  176. }
  177. }