PropertyGuard.h 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  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. #if ENABLE_NATIVE_CODEGEN
  9. class JitPolyEquivalentTypeGuard;
  10. #endif
  11. class PropertyGuard
  12. {
  13. friend class PropertyGuardValidator;
  14. #if ENABLE_NATIVE_CODEGEN
  15. friend class JitPolyEquivalentTypeGuard;
  16. #endif
  17. private:
  18. Field(intptr_t) value; // value is address of Js::Type
  19. #if ENABLE_NATIVE_CODEGEN
  20. Field(bool) isPoly;
  21. #endif
  22. #if DBG
  23. Field(bool) wasReincarnated = false;
  24. #endif
  25. public:
  26. static PropertyGuard* New(Recycler* recycler) { return RecyclerNewLeaf(recycler, Js::PropertyGuard); }
  27. PropertyGuard() : value(GuardValue::Uninitialized)
  28. #if ENABLE_NATIVE_CODEGEN
  29. , isPoly(false)
  30. #endif
  31. {
  32. }
  33. PropertyGuard(intptr_t value) : value(value)
  34. #if ENABLE_NATIVE_CODEGEN
  35. , isPoly(false)
  36. #endif
  37. {
  38. // GuardValue::Invalidated and GuardValue::Invalidated_DuringSweeping can only be set using
  39. // Invalidate() and InvalidatedDuringSweep() methods respectively.
  40. Assert(this->value != GuardValue::Invalidated && this->value != GuardValue::Invalidated_DuringSweep);
  41. }
  42. inline static size_t GetSizeOfValue() { return sizeof(((PropertyGuard*)0)->value); }
  43. inline static size_t GetOffsetOfValue() { return offsetof(PropertyGuard, value); }
  44. intptr_t GetValue() const { return this->value; }
  45. bool IsValid()
  46. {
  47. return this->value != GuardValue::Invalidated && this->value != GuardValue::Invalidated_DuringSweep;
  48. }
  49. bool IsInvalidatedDuringSweep() { return this->value == GuardValue::Invalidated_DuringSweep; }
  50. void SetValue(intptr_t value)
  51. {
  52. // GuardValue::Invalidated and GuardValue::Invalidated_DuringSweeping can only be set using
  53. // Invalidate() and InvalidatedDuringSweep() methods respectively.
  54. Assert(value != GuardValue::Invalidated && value != GuardValue::Invalidated_DuringSweep);
  55. this->value = value;
  56. }
  57. intptr_t const* GetAddressOfValue() { return &this->value; }
  58. void Invalidate();
  59. void InvalidateDuringSweep();
  60. #if DBG
  61. bool WasReincarnated() { return this->wasReincarnated; }
  62. #endif
  63. enum GuardValue : intptr_t
  64. {
  65. Invalidated = 0,
  66. Uninitialized = 1,
  67. Invalidated_DuringSweep = 2
  68. };
  69. #if ENABLE_NATIVE_CODEGEN
  70. bool IsPoly() const { return this->isPoly; }
  71. JitPolyEquivalentTypeGuard * AsPolyTypeCheckGuard()
  72. {
  73. AssertOrFailFast(this->IsPoly());
  74. return (JitPolyEquivalentTypeGuard*)(this);
  75. }
  76. #endif
  77. };
  78. class PropertyGuardValidator
  79. {
  80. // Required by EquivalentTypeGuard::SetType.
  81. CompileAssert(offsetof(PropertyGuard, value) == 0);
  82. // CompileAssert(offsetof(ConstructorCache, guard.value) == offsetof(PropertyGuard, value));
  83. };
  84. #if ENABLE_NATIVE_CODEGEN
  85. class JitIndexedPropertyGuard : public Js::PropertyGuard
  86. {
  87. private:
  88. int index;
  89. public:
  90. JitIndexedPropertyGuard(intptr_t value, int index) :
  91. Js::PropertyGuard(value), index(index) {}
  92. JitIndexedPropertyGuard(int index) :
  93. Js::PropertyGuard(), index(index) {}
  94. int GetIndex() const { return this->index; }
  95. };
  96. class JitTypePropertyGuard : public Js::JitIndexedPropertyGuard
  97. {
  98. public:
  99. JitTypePropertyGuard(intptr_t typeAddr, int index) :
  100. JitIndexedPropertyGuard(typeAddr, index) {}
  101. intptr_t GetTypeAddr() const { return this->GetValue(); }
  102. };
  103. struct TypeGuardTransferEntry
  104. {
  105. PropertyId propertyId;
  106. JitIndexedPropertyGuard* guards[0];
  107. TypeGuardTransferEntry() : propertyId(Js::Constants::NoProperty) {}
  108. };
  109. class FakePropertyGuardWeakReference : public RecyclerWeakReference<Js::PropertyGuard>
  110. {
  111. public:
  112. static FakePropertyGuardWeakReference* New(Recycler* recycler, Js::PropertyGuard* guard)
  113. {
  114. Assert(guard != nullptr);
  115. return RecyclerNewLeaf(recycler, Js::FakePropertyGuardWeakReference, guard);
  116. }
  117. FakePropertyGuardWeakReference(const Js::PropertyGuard* guard)
  118. {
  119. this->strongRef = (char*)guard;
  120. this->strongRefHeapBlock = &CollectedRecyclerWeakRefHeapBlock::Instance;
  121. }
  122. void Zero()
  123. {
  124. Assert(this->strongRef != nullptr);
  125. this->strongRef = nullptr;
  126. }
  127. };
  128. struct CtorCacheGuardTransferEntry
  129. {
  130. PropertyId propertyId;
  131. intptr_t caches[0];
  132. CtorCacheGuardTransferEntry() : propertyId(Js::Constants::NoProperty) {}
  133. };
  134. struct PropertyEquivalenceInfo
  135. {
  136. PropertyIndex slotIndex;
  137. bool isAuxSlot;
  138. bool isWritable;
  139. PropertyEquivalenceInfo() :
  140. slotIndex(Constants::NoSlot), isAuxSlot(false), isWritable(false) {}
  141. PropertyEquivalenceInfo(PropertyIndex slotIndex, bool isAuxSlot, bool isWritable) :
  142. slotIndex(slotIndex), isAuxSlot(isAuxSlot), isWritable(isWritable) {}
  143. };
  144. struct EquivalentPropertyEntry
  145. {
  146. Js::PropertyId propertyId;
  147. Js::PropertyIndex slotIndex;
  148. bool isAuxSlot;
  149. bool mustBeWritable;
  150. };
  151. struct TypeEquivalenceRecord
  152. {
  153. uint propertyCount;
  154. EquivalentPropertyEntry* properties;
  155. };
  156. struct EquivalentTypeCache
  157. {
  158. Js::Type* types[EQUIVALENT_TYPE_CACHE_SIZE];
  159. PropertyGuard *guard;
  160. TypeEquivalenceRecord record;
  161. uint nextEvictionVictim;
  162. bool isLoadedFromProto;
  163. bool hasFixedValue;
  164. EquivalentTypeCache() : nextEvictionVictim(EQUIVALENT_TYPE_CACHE_SIZE) {}
  165. bool ClearUnusedTypes(Recycler *recycler);
  166. void SetGuard(PropertyGuard *theGuard) { this->guard = theGuard; }
  167. void SetIsLoadedFromProto() { this->isLoadedFromProto = true; }
  168. bool IsLoadedFromProto() const { return this->isLoadedFromProto; }
  169. void SetHasFixedValue() { this->hasFixedValue = true; }
  170. bool HasFixedValue() const { return this->hasFixedValue; }
  171. };
  172. class JitEquivalentTypeGuard : public JitIndexedPropertyGuard
  173. {
  174. // This pointer is allocated from background thread first, and then transferred to recycler,
  175. // so as to keep the cached types alive.
  176. EquivalentTypeCache* cache;
  177. uint32 objTypeSpecFldId;
  178. // TODO: OOP JIT, reenable these asserts
  179. #if DBG && 0
  180. // Intentionally have as intptr_t so this guard doesn't hold scriptContext
  181. intptr_t originalScriptContextValue = 0;
  182. #endif
  183. public:
  184. JitEquivalentTypeGuard(intptr_t typeAddr, int index, uint32 objTypeSpecFldId) :
  185. JitIndexedPropertyGuard(typeAddr, index), cache(nullptr), objTypeSpecFldId(objTypeSpecFldId)
  186. {
  187. #if DBG && 0
  188. originalScriptContextValue = reinterpret_cast<intptr_t>(type->GetScriptContext());
  189. #endif
  190. }
  191. JitEquivalentTypeGuard(int index, uint32 objTypeSpecFldId) :
  192. JitIndexedPropertyGuard(index), cache(nullptr), objTypeSpecFldId(objTypeSpecFldId)
  193. {
  194. }
  195. intptr_t GetTypeAddr() const { return this->GetValue(); }
  196. void SetTypeAddr(const intptr_t typeAddr)
  197. {
  198. #if DBG && 0
  199. if (originalScriptContextValue == 0)
  200. {
  201. originalScriptContextValue = reinterpret_cast<intptr_t>(type->GetScriptContext());
  202. }
  203. else
  204. {
  205. AssertMsg(originalScriptContextValue == reinterpret_cast<intptr_t>(type->GetScriptContext()), "Trying to set guard type from different script context.");
  206. }
  207. #endif
  208. this->SetValue(typeAddr);
  209. }
  210. uint32 GetObjTypeSpecFldId() const
  211. {
  212. return this->objTypeSpecFldId;
  213. }
  214. Js::EquivalentTypeCache* GetCache() const
  215. {
  216. return this->cache;
  217. }
  218. void SetCache(Js::EquivalentTypeCache* cache)
  219. {
  220. this->cache = cache;
  221. }
  222. };
  223. class JitPolyEquivalentTypeGuard : public JitEquivalentTypeGuard
  224. {
  225. public:
  226. JitPolyEquivalentTypeGuard(int index, uint32 objTypeSpecFldId) : JitEquivalentTypeGuard(index, objTypeSpecFldId)
  227. {
  228. isPoly = true;
  229. for (uint i = 0; i < GetSize(); i++)
  230. {
  231. polyValues[i] = GuardValue::Uninitialized;
  232. }
  233. }
  234. private:
  235. intptr_t polyValues[EQUIVALENT_TYPE_CACHE_SIZE];
  236. public:
  237. static int32 GetOffsetOfPolyValues() { return offsetof(JitPolyEquivalentTypeGuard, polyValues); }
  238. // TODO: Revisit optimal size. Make it vary according to the number of caches? Is this worth a variable-size allocation?
  239. uintptr_t GetSize() const { return EQUIVALENT_TYPE_CACHE_SIZE; }
  240. intptr_t const * GetAddressOfPolyValues() { return &this->polyValues[0]; }
  241. intptr_t GetPolyValue(uint8 index) const
  242. {
  243. AssertOrFailFast(index < GetSize());
  244. return polyValues[index];
  245. }
  246. void SetPolyValue(intptr_t value, uint8 index)
  247. {
  248. AssertOrFailFast(index < GetSize());
  249. polyValues[index] = value;
  250. }
  251. uint8 GetIndexForValue(intptr_t value) const
  252. {
  253. return (uint8)((value >> PolymorphicInlineCacheShift) & (GetSize() - 1));
  254. }
  255. void Invalidate()
  256. {
  257. for (uint8 i = 0; i < GetSize(); i++)
  258. {
  259. Invalidate(i);
  260. }
  261. }
  262. void Invalidate(uint8 i)
  263. {
  264. AssertOrFailFast(i < GetSize());
  265. polyValues[i] = GuardValue::Invalidated;
  266. }
  267. void InvalidateDuringSweep()
  268. {
  269. for (uint8 i = 0; i < GetSize(); i++)
  270. {
  271. InvalidateDuringSweep(i);
  272. }
  273. }
  274. void InvalidateDuringSweep(uint8 i)
  275. {
  276. AssertOrFailFast(i < GetSize());
  277. polyValues[i] = GuardValue::Invalidated_DuringSweep;
  278. }
  279. };
  280. #endif // ENABLE_NATIVE_CODEGEN
  281. inline void PropertyGuard::Invalidate()
  282. {
  283. this->value = GuardValue::Invalidated;
  284. #if ENABLE_NATIVE_CODEGEN
  285. if (this->IsPoly())
  286. {
  287. this->AsPolyTypeCheckGuard()->JitPolyEquivalentTypeGuard::Invalidate();
  288. }
  289. #endif
  290. }
  291. inline void PropertyGuard::InvalidateDuringSweep()
  292. {
  293. #if DBG
  294. wasReincarnated = true;
  295. #endif
  296. this->value = GuardValue::Invalidated_DuringSweep;
  297. #if ENABLE_NATIVE_CODEGEN
  298. if (this->IsPoly())
  299. {
  300. this->AsPolyTypeCheckGuard()->JitPolyEquivalentTypeGuard::InvalidateDuringSweep();
  301. }
  302. #endif
  303. }
  304. };