RootObjectBase.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  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. #include "RuntimeLibraryPch.h"
  6. namespace Js
  7. {
  8. RootObjectInlineCache::RootObjectInlineCache(InlineCacheAllocator * allocator):
  9. inlineCache(nullptr), refCount(1)
  10. {
  11. inlineCache = AllocatorNewZ(InlineCacheAllocator,
  12. allocator, Js::InlineCache);
  13. }
  14. RootObjectBase::RootObjectBase(DynamicType * type) :
  15. DynamicObject(type), hostObject(nullptr), loadInlineCacheMap(nullptr), loadMethodInlineCacheMap(nullptr), storeInlineCacheMap(nullptr)
  16. {}
  17. RootObjectBase::RootObjectBase(DynamicType * type, ScriptContext* scriptContext) :
  18. DynamicObject(type, scriptContext), hostObject(nullptr), loadInlineCacheMap(nullptr), loadMethodInlineCacheMap(nullptr), storeInlineCacheMap(nullptr)
  19. {}
  20. HostObjectBase * RootObjectBase::GetHostObject() const
  21. {
  22. Assert(hostObject == nullptr || Js::JavascriptOperators::GetTypeId(hostObject) == TypeIds_HostObject);
  23. return this->hostObject;
  24. }
  25. void RootObjectBase::SetHostObject(HostObjectBase * hostObject)
  26. {
  27. Assert(hostObject == nullptr || Js::JavascriptOperators::GetTypeId(hostObject) == TypeIds_HostObject);
  28. this->hostObject = hostObject;
  29. }
  30. Js::InlineCache *
  31. RootObjectBase::GetInlineCache(Js::PropertyRecord const* propertyRecord, bool isLoadMethod, bool isStore)
  32. {
  33. Js::RootObjectInlineCache * rootObjectInlineCache = GetRootInlineCache(propertyRecord, isLoadMethod, isStore);
  34. return rootObjectInlineCache->GetInlineCache();
  35. }
  36. Js::RootObjectInlineCache*
  37. RootObjectBase::GetRootInlineCache(Js::PropertyRecord const* propertyRecord, bool isLoadMethod, bool isStore)
  38. {
  39. RootObjectInlineCacheMap * inlineCacheMap = isStore ? storeInlineCacheMap :
  40. isLoadMethod ? loadMethodInlineCacheMap : loadInlineCacheMap;
  41. Js::RootObjectInlineCache * rootObjectInlineCache;
  42. if (inlineCacheMap == nullptr)
  43. {
  44. Recycler * recycler = this->GetLibrary()->GetRecycler();
  45. inlineCacheMap = RecyclerNew(recycler, RootObjectInlineCacheMap, recycler);
  46. if (isStore)
  47. {
  48. this->storeInlineCacheMap = inlineCacheMap;
  49. }
  50. else if (isLoadMethod)
  51. {
  52. this->loadMethodInlineCacheMap = inlineCacheMap;
  53. }
  54. else
  55. {
  56. this->loadInlineCacheMap = inlineCacheMap;
  57. }
  58. }
  59. else if (inlineCacheMap->TryGetValue(propertyRecord, &rootObjectInlineCache))
  60. {
  61. rootObjectInlineCache->AddRef();
  62. return rootObjectInlineCache;
  63. }
  64. Recycler * recycler = this->GetLibrary()->GetRecycler();
  65. rootObjectInlineCache = RecyclerNewLeaf(recycler, RootObjectInlineCache, this->GetScriptContext()->GetInlineCacheAllocator());
  66. inlineCacheMap->Add(propertyRecord, rootObjectInlineCache);
  67. return rootObjectInlineCache;
  68. }
  69. // TODO: Switch to take PropertyRecord instead once we clean up the function body to hold onto propertyRecord
  70. // instead of propertyId.
  71. uint
  72. RootObjectBase::ReleaseInlineCache(Js::PropertyId propertyId, bool isLoadMethod, bool isStore, bool isShutdown)
  73. {
  74. uint unregisteredInlineCacheCount = 0;
  75. RootObjectInlineCacheMap * inlineCacheMap = isStore ? storeInlineCacheMap :
  76. isLoadMethod ? loadMethodInlineCacheMap : loadInlineCacheMap;
  77. bool found = false;
  78. inlineCacheMap->RemoveIfWithKey(propertyId,
  79. [this, isShutdown, &unregisteredInlineCacheCount, &found](PropertyRecord const * propertyRecord, RootObjectInlineCache * rootObjectInlineCache)
  80. {
  81. found = true;
  82. if (rootObjectInlineCache->Release() == 0)
  83. {
  84. // If we're not shutting down, we need to remove this cache from thread context's invalidation list (if any),
  85. // and release memory back to the arena. During script context shutdown, we leave everything in place, because
  86. // the inline cache arena will stay alive until script context is destroyed (as in destructor called as opposed to
  87. // Close called) and thus the invalidation lists are safe to keep references to caches from this script context.
  88. if (!isShutdown)
  89. {
  90. if (rootObjectInlineCache->GetInlineCache()->RemoveFromInvalidationList())
  91. {
  92. unregisteredInlineCacheCount++;
  93. }
  94. AllocatorDelete(InlineCacheAllocator, this->GetScriptContext()->GetInlineCacheAllocator(), rootObjectInlineCache->GetInlineCache());
  95. }
  96. return true; // Remove from the map
  97. }
  98. return false; // don't remove from the map
  99. }
  100. );
  101. Assert(found);
  102. return unregisteredInlineCacheCount;
  103. }
  104. BOOL
  105. RootObjectBase::EnsureProperty(PropertyId propertyId)
  106. {
  107. if (!RootObjectBase::HasOwnPropertyCheckNoRedecl(propertyId))
  108. {
  109. this->InitProperty(propertyId, this->GetLibrary()->GetUndefined(),
  110. static_cast<Js::PropertyOperationFlags>(PropertyOperation_PreInit | PropertyOperation_SpecialValue));
  111. }
  112. return true;
  113. }
  114. BOOL
  115. RootObjectBase::EnsureNoRedeclProperty(PropertyId propertyId)
  116. {
  117. RootObjectBase::HasOwnPropertyCheckNoRedecl(propertyId);
  118. return true;
  119. }
  120. void
  121. RootObjectBase::EnsureCanDeclGloFunc(PropertyId propertyId)
  122. {
  123. // #sec-candeclareglobalfunction states that if an exisiting property is
  124. // not configurable, not writable, and not enumerable, return false.
  125. if (!IsConfigurable(propertyId) && !IsWritable(propertyId) && !IsEnumerable(propertyId))
  126. {
  127. JavascriptError::ThrowTypeError(GetScriptContext(), JSERR_InvalidGloFuncDecl,
  128. GetScriptContext()->GetPropertyName(propertyId)->GetBuffer());
  129. }
  130. }
  131. BOOL
  132. RootObjectBase::HasOwnPropertyCheckNoRedecl(PropertyId propertyId)
  133. {
  134. bool noRedecl = false;
  135. if (!GetTypeHandler()->HasRootProperty(this, propertyId, &noRedecl))
  136. {
  137. return FALSE;
  138. }
  139. else if (noRedecl)
  140. {
  141. JavascriptError::ThrowReferenceError(GetScriptContext(), ERRRedeclaration);
  142. }
  143. return true;
  144. }
  145. BOOL
  146. RootObjectBase::HasRootProperty(PropertyId propertyId)
  147. {
  148. Assert(!Js::IsInternalPropertyId(propertyId));
  149. return GetTypeHandler()->HasRootProperty(this, propertyId);
  150. }
  151. BOOL
  152. RootObjectBase::GetRootProperty(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  153. {
  154. Assert(!Js::IsInternalPropertyId(propertyId));
  155. return GetTypeHandler()->GetRootProperty(this, originalInstance, propertyId, value, info, requestContext);
  156. }
  157. BOOL
  158. RootObjectBase::GetRootPropertyReference(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  159. {
  160. Assert(!Js::IsInternalPropertyId(propertyId));
  161. return GetTypeHandler()->GetRootProperty(this, originalInstance, propertyId, value, info, requestContext);
  162. }
  163. BOOL
  164. RootObjectBase::SetRootProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  165. {
  166. Assert(!Js::IsInternalPropertyId(propertyId));
  167. return GetTypeHandler()->SetRootProperty(this, propertyId, value, flags, info);
  168. }
  169. DescriptorFlags
  170. RootObjectBase::GetRootSetter(PropertyId propertyId, Var* setterValue, PropertyValueInfo* info, ScriptContext* requestContext)
  171. {
  172. Assert(!Js::IsInternalPropertyId(propertyId));
  173. return GetTypeHandler()->GetRootSetter(this, propertyId, setterValue, info, requestContext);
  174. }
  175. BOOL
  176. RootObjectBase::DeleteRootProperty(PropertyId propertyId, PropertyOperationFlags flags)
  177. {
  178. Assert(!Js::IsInternalPropertyId(propertyId));
  179. return GetTypeHandler()->DeleteRootProperty(this, propertyId, flags);
  180. }
  181. PropertyIndex
  182. RootObjectBase::GetRootPropertyIndex(PropertyId propertyId)
  183. {
  184. Assert(!Js::IsInternalPropertyId(propertyId));
  185. Assert(propertyId != Constants::NoProperty);
  186. return GetTypeHandler()->GetRootPropertyIndex(this->GetScriptContext()->GetPropertyName(propertyId));
  187. }
  188. void
  189. RootObjectBase::EnsureNoProperty(PropertyId propertyId)
  190. {
  191. Assert(!Js::IsInternalPropertyId(propertyId));
  192. bool isDeclared = false;
  193. bool isNonconfigurable = false;
  194. if (GetTypeHandler()->HasRootProperty(this, propertyId, nullptr, &isDeclared, &isNonconfigurable) &&
  195. (isDeclared || isNonconfigurable))
  196. {
  197. JavascriptError::ThrowReferenceError(this->GetScriptContext(), ERRRedeclaration);
  198. }
  199. }
  200. #if DBG
  201. bool
  202. RootObjectBase::IsLetConstGlobal(PropertyId propertyId)
  203. {
  204. Assert(!Js::IsInternalPropertyId(propertyId));
  205. return GetTypeHandler()->IsLetConstGlobal(this, propertyId);
  206. }
  207. #endif
  208. }