ModuleRoot.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  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. ModuleRoot::ModuleRoot(DynamicType * type):
  9. RootObjectBase(type)
  10. {
  11. }
  12. void ModuleRoot::SetHostObject(ModuleID moduleID, HostObjectBase * hostObject)
  13. {
  14. this->moduleID = moduleID;
  15. __super::SetHostObject(hostObject);
  16. }
  17. PropertyQueryFlags ModuleRoot::HasPropertyQuery(PropertyId propertyId, _Inout_opt_ PropertyValueInfo* info)
  18. {
  19. if (JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::HasPropertyQuery(propertyId, info)))
  20. {
  21. return PropertyQueryFlags::Property_Found;
  22. }
  23. else if (this->hostObject && JavascriptOperators::HasProperty(this->hostObject, propertyId))
  24. {
  25. return PropertyQueryFlags::Property_Found;
  26. }
  27. return this->GetLibrary()->GetGlobalObject()->GlobalObject::HasPropertyQuery(propertyId, info);
  28. }
  29. BOOL ModuleRoot::EnsureProperty(PropertyId propertyId)
  30. {
  31. if (!RootObjectBase::HasOwnPropertyCheckNoRedecl(propertyId))
  32. {
  33. // Cannot pass the extra PropertyOperation_PreInit flag, because module root uses SetSlot directly from
  34. // SetRootProperty. If the property is not yet initialized SetSlot will (correctly) assert.
  35. this->InitProperty(propertyId, this->GetLibrary()->GetUndefined(), (PropertyOperationFlags)(PropertyOperation_SpecialValue | PropertyOperation_NonFixedValue));
  36. }
  37. return true;
  38. }
  39. BOOL ModuleRoot::HasRootProperty(PropertyId propertyId)
  40. {
  41. if (__super::HasRootProperty(propertyId))
  42. {
  43. return TRUE;
  44. }
  45. else if (this->hostObject && JavascriptOperators::HasProperty(this->hostObject, propertyId))
  46. {
  47. return TRUE;
  48. }
  49. return this->GetLibrary()->GetGlobalObject()->GlobalObject::HasRootProperty(propertyId);
  50. }
  51. BOOL ModuleRoot::HasOwnProperty(PropertyId propertyId)
  52. {
  53. return JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::HasPropertyQuery(propertyId, nullptr /*info*/));
  54. }
  55. PropertyQueryFlags ModuleRoot::GetPropertyQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  56. {
  57. PropertyIndex index = GetPropertyIndex(propertyId);
  58. if (index != Constants::NoSlot)
  59. {
  60. *value = this->GetSlot(index);
  61. if (info) // Avoid testing IsWritable if info not being queried
  62. {
  63. PropertyValueInfo::Set(info, this, index, IsWritable(propertyId) ? PropertyWritable : PropertyNone);
  64. #if ENABLE_FIXED_FIELDS
  65. if (this->IsFixedProperty(propertyId))
  66. {
  67. PropertyValueInfo::DisableStoreFieldCache(info);
  68. }
  69. #endif
  70. }
  71. return PropertyQueryFlags::Property_Found;
  72. }
  73. if (this->hostObject && JavascriptOperators::GetProperty(this->hostObject, propertyId, value, requestContext))
  74. {
  75. return PropertyQueryFlags::Property_Found;
  76. }
  77. //
  78. // Try checking the global object
  79. // if the module root doesn't have the property and the host object also doesn't have it
  80. //
  81. GlobalObject* globalObj = this->GetLibrary()->GetGlobalObject();
  82. return globalObj->GlobalObject::GetPropertyQuery(originalInstance, propertyId, value, NULL, requestContext);
  83. }
  84. BOOL ModuleRoot::GetRootProperty(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  85. {
  86. PropertyIndex index = GetRootPropertyIndex(propertyId);
  87. if (index != Constants::NoSlot)
  88. {
  89. *value = this->GetSlot(index);
  90. if (info) // Avoid testing IsWritable if info not being queried
  91. {
  92. PropertyValueInfo::Set(info, this, index, IsWritable(propertyId) ? PropertyWritable : PropertyNone);
  93. #if ENABLE_FIXED_FIELDS
  94. if (this->IsFixedProperty(propertyId))
  95. {
  96. PropertyValueInfo::DisableStoreFieldCache(info);
  97. }
  98. #endif
  99. }
  100. return TRUE;
  101. }
  102. if (this->hostObject && JavascriptOperators::GetProperty(this->hostObject, propertyId, value, requestContext))
  103. {
  104. return TRUE;
  105. }
  106. //
  107. // Try checking the global object
  108. // if the module root doesn't have the property and the host object also doesn't have it
  109. //
  110. GlobalObject* globalObj = this->GetLibrary()->GetGlobalObject();
  111. return globalObj->GlobalObject::GetRootProperty(originalInstance, propertyId, value, NULL, requestContext);
  112. }
  113. PropertyQueryFlags ModuleRoot::GetPropertyQuery(Var originalInstance, JavascriptString* propertyNameString, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  114. {
  115. PropertyRecord const * propertyRecord;
  116. this->GetScriptContext()->GetOrAddPropertyRecord(propertyNameString, &propertyRecord);
  117. return ModuleRoot::GetPropertyQuery(originalInstance, propertyRecord->GetPropertyId(), value, info, requestContext);
  118. }
  119. _Check_return_ _Success_(return) BOOL ModuleRoot::GetAccessors(PropertyId propertyId, _Outptr_result_maybenull_ Var* getter, _Outptr_result_maybenull_ Var* setter, ScriptContext* requestContext)
  120. {
  121. if (DynamicObject::GetAccessors(propertyId, getter, setter, requestContext))
  122. {
  123. return TRUE;
  124. }
  125. if (this->hostObject)
  126. {
  127. return this->hostObject->GetAccessors(propertyId, getter, setter, requestContext);
  128. }
  129. // Try checking the global object
  130. GlobalObject* globalObj = this->GetLibrary()->GetGlobalObject();
  131. return globalObj->GlobalObject::GetAccessors(propertyId, getter, setter, requestContext);
  132. }
  133. PropertyQueryFlags ModuleRoot::GetPropertyReferenceQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info,
  134. ScriptContext* requestContext)
  135. {
  136. PropertyIndex index = GetPropertyIndex(propertyId);
  137. if (index != Constants::NoSlot)
  138. {
  139. *value = this->GetSlot(index);
  140. if (info) // Avoid testing IsWritable if info not being queried
  141. {
  142. PropertyValueInfo::Set(info, this, index, IsWritable(propertyId) ? PropertyWritable : PropertyNone);
  143. #if ENABLE_FIXED_FIELDS
  144. if (this->IsFixedProperty(propertyId))
  145. {
  146. PropertyValueInfo::DisableStoreFieldCache(info);
  147. }
  148. #endif
  149. }
  150. return PropertyQueryFlags::Property_Found;
  151. }
  152. if (this->hostObject && JavascriptOperators::GetPropertyReference(this->hostObject, propertyId, value, requestContext))
  153. {
  154. return PropertyQueryFlags::Property_NotFound;
  155. }
  156. //
  157. // Try checking the global object
  158. // if the module root doesn't have the property and the host object also doesn't have it
  159. //
  160. GlobalObject* globalObj = this->GetLibrary()->GetGlobalObject();
  161. return globalObj->GlobalObject::GetPropertyReferenceQuery(originalInstance, propertyId, value, NULL, requestContext);
  162. }
  163. BOOL ModuleRoot::GetRootPropertyReference(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info,
  164. ScriptContext* requestContext)
  165. {
  166. PropertyIndex index = GetRootPropertyIndex(propertyId);
  167. if (index != Constants::NoSlot)
  168. {
  169. *value = this->GetSlot(index);
  170. if (info) // Avoid testing IsWritable if info not being queried
  171. {
  172. PropertyValueInfo::Set(info, this, index, IsWritable(propertyId) ? PropertyWritable : PropertyNone);
  173. #if ENABLE_FIXED_FIELDS
  174. if (this->IsFixedProperty(propertyId))
  175. {
  176. PropertyValueInfo::DisableStoreFieldCache(info);
  177. }
  178. #endif
  179. }
  180. return TRUE;
  181. }
  182. if (this->hostObject && JavascriptOperators::GetPropertyReference(this->hostObject, propertyId, value, requestContext))
  183. {
  184. return TRUE;
  185. }
  186. //
  187. // Try checking the global object
  188. // if the module root doesn't have the property and the host object also doesn't have it
  189. //
  190. GlobalObject* globalObj = this->GetLibrary()->GetGlobalObject();
  191. return globalObj->GlobalObject::GetRootPropertyReference(originalInstance, propertyId, value, NULL, requestContext);
  192. }
  193. BOOL ModuleRoot::SetProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  194. {
  195. PropertyIndex index = GetPropertyIndex(propertyId);
  196. if (index != Constants::NoSlot)
  197. {
  198. if (this->IsWritable(propertyId) == FALSE)
  199. {
  200. JavascriptError::ThrowCantAssignIfStrictMode(flags, this->GetScriptContext());
  201. #if ENABLE_FIXED_FIELDS
  202. if (this->IsFixedProperty(propertyId))
  203. {
  204. PropertyValueInfo::SetNoCache(info, this);
  205. }
  206. else
  207. #endif
  208. {
  209. PropertyValueInfo::Set(info, this, index, PropertyNone); // Try to cache property info even if not writable
  210. }
  211. return FALSE;
  212. }
  213. this->SetSlot(SetSlotArguments(propertyId, index, value));
  214. #if ENABLE_FIXED_FIELDS
  215. if (this->IsFixedProperty(propertyId))
  216. {
  217. PropertyValueInfo::SetNoCache(info, this);
  218. }
  219. else
  220. #endif
  221. {
  222. PropertyValueInfo::Set(info, this, index);
  223. }
  224. return TRUE;
  225. }
  226. else if (this->hostObject && this->hostObject->HasProperty(propertyId))
  227. {
  228. return this->hostObject->SetProperty(propertyId, value, flags, NULL);
  229. }
  230. //
  231. // Try checking the global object
  232. // if the module root doesn't have the property and the host object also doesn't have it
  233. //
  234. GlobalObject* globalObj = this->GetLibrary()->GetGlobalObject();
  235. BOOL setAttempted = TRUE;
  236. if (globalObj->SetExistingProperty(propertyId, value, NULL, &setAttempted))
  237. {
  238. return TRUE;
  239. }
  240. //
  241. // Set was attempted. But the set operation returned false.
  242. // This happens, when the property is read only.
  243. // In those scenarios, we should be setting the property with default attributes
  244. //
  245. if (setAttempted)
  246. {
  247. return FALSE;
  248. }
  249. return DynamicObject::SetProperty(propertyId, value, flags, info);
  250. }
  251. BOOL ModuleRoot::SetRootProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  252. {
  253. PropertyIndex index = GetRootPropertyIndex(propertyId);
  254. if (index != Constants::NoSlot)
  255. {
  256. if (this->IsWritable(propertyId) == FALSE)
  257. {
  258. JavascriptError::ThrowCantAssignIfStrictMode(flags, this->GetScriptContext());
  259. #if ENABLE_FIXED_FIELDS
  260. if (this->IsFixedProperty(propertyId))
  261. {
  262. PropertyValueInfo::SetNoCache(info, this);
  263. }
  264. else
  265. #endif
  266. {
  267. PropertyValueInfo::Set(info, this, index, PropertyNone); // Try to cache property info even if not writable
  268. }
  269. return FALSE;
  270. }
  271. this->SetSlot(SetSlotArgumentsRoot(propertyId, true, index, value));
  272. #if ENABLE_FIXED_FIELDS
  273. if (this->IsFixedProperty(propertyId))
  274. {
  275. PropertyValueInfo::SetNoCache(info, this);
  276. }
  277. else
  278. #endif
  279. {
  280. PropertyValueInfo::Set(info, this, index);
  281. }
  282. return TRUE;
  283. }
  284. else if (this->hostObject && this->hostObject->HasProperty(propertyId))
  285. {
  286. return this->hostObject->SetProperty(propertyId, value, flags, NULL);
  287. }
  288. //
  289. // Try checking the global object
  290. // if the module root doesn't have the property and the host object also doesn't have it
  291. //
  292. GlobalObject* globalObj = this->GetLibrary()->GetGlobalObject();
  293. BOOL setAttempted = TRUE;
  294. if (globalObj->SetExistingRootProperty(propertyId, value, NULL, &setAttempted))
  295. {
  296. return TRUE;
  297. }
  298. //
  299. // Set was attempted. But the set operation returned false.
  300. // This happens, when the property is read only.
  301. // In those scenarios, we should be setting the property with default attributes
  302. //
  303. if (setAttempted)
  304. {
  305. return FALSE;
  306. }
  307. return __super::SetRootProperty(propertyId, value, (PropertyOperationFlags)(flags | PropertyOperation_NonFixedValue), info);
  308. }
  309. BOOL ModuleRoot::SetProperty(JavascriptString* propertyNameString, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  310. {
  311. PropertyRecord const * propertyRecord;
  312. this->GetScriptContext()->GetOrAddPropertyRecord(propertyNameString, &propertyRecord);
  313. return ModuleRoot::SetProperty(propertyRecord->GetPropertyId(), value, (PropertyOperationFlags)(flags | PropertyOperation_NonFixedValue), info);
  314. }
  315. BOOL ModuleRoot::InitPropertyScoped(PropertyId propertyId, Var value)
  316. {
  317. return DynamicObject::InitProperty(propertyId, value, PropertyOperation_NonFixedValue);
  318. }
  319. BOOL ModuleRoot::InitFuncScoped(PropertyId propertyId, Var value)
  320. {
  321. // Var binding of functions declared in eval are elided when conflicting
  322. // with global scope let/const variables, so do not actually set the
  323. // property if it exists and is a let/const variable.
  324. bool noRedecl = false;
  325. if (!GetTypeHandler()->HasRootProperty(this, propertyId, &noRedecl) || !noRedecl)
  326. {
  327. DynamicObject::InitProperty(propertyId, value, PropertyOperation_NonFixedValue);
  328. }
  329. return true;
  330. }
  331. BOOL ModuleRoot::SetAccessors(PropertyId propertyId, Var getter, Var setter, PropertyOperationFlags flags)
  332. {
  333. if (DynamicObject::SetAccessors(propertyId, getter, setter, flags))
  334. {
  335. return TRUE;
  336. }
  337. if (this->hostObject)
  338. {
  339. return this->hostObject->SetAccessors(propertyId, getter, setter, flags);
  340. }
  341. //
  342. // Try checking the global object
  343. // if the module root doesn't have the property and the host object also doesn't have it
  344. //
  345. GlobalObject* globalObj = GetScriptContext()->GetGlobalObject();
  346. return globalObj->GlobalObject::SetAccessors(propertyId, getter, setter, flags);
  347. }
  348. BOOL ModuleRoot::DeleteProperty(PropertyId propertyId, PropertyOperationFlags flags)
  349. {
  350. int index = GetPropertyIndex(propertyId);
  351. if (index != Constants::NoSlot)
  352. {
  353. return FALSE;
  354. }
  355. else if (this->hostObject && this->hostObject->HasProperty(propertyId))
  356. {
  357. return this->hostObject->DeleteProperty(propertyId, flags);
  358. }
  359. return this->GetLibrary()->GetGlobalObject()->GlobalObject::DeleteProperty(propertyId, flags);
  360. }
  361. BOOL ModuleRoot::DeleteProperty(JavascriptString *propertyNameString, PropertyOperationFlags flags)
  362. {
  363. PropertyRecord const *propertyRecord = nullptr;
  364. if (JavascriptOperators::ShouldTryDeleteProperty(this, propertyNameString, &propertyRecord))
  365. {
  366. Assert(propertyRecord);
  367. return DeleteProperty(propertyRecord->GetPropertyId(), flags);
  368. }
  369. return TRUE;
  370. }
  371. BOOL ModuleRoot::DeleteRootProperty(PropertyId propertyId, PropertyOperationFlags flags)
  372. {
  373. int index = GetRootPropertyIndex(propertyId);
  374. if (index != Constants::NoSlot)
  375. {
  376. return FALSE;
  377. }
  378. else if (this->hostObject && this->hostObject->HasProperty(propertyId))
  379. {
  380. return this->hostObject->DeleteProperty(propertyId, flags);
  381. }
  382. return this->GetLibrary()->GetGlobalObject()->GlobalObject::DeleteRootProperty(propertyId, flags);
  383. }
  384. PropertyQueryFlags ModuleRoot::HasItemQuery(uint32 index)
  385. {
  386. return JavascriptConversion::BooleanToPropertyQueryFlags(JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::HasItemQuery(index))
  387. || (this->hostObject && JavascriptOperators::HasItem(this->hostObject, index)));
  388. }
  389. BOOL ModuleRoot::HasOwnItem(uint32 index)
  390. {
  391. return JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::HasItemQuery(index));
  392. }
  393. PropertyQueryFlags ModuleRoot::GetItemReferenceQuery(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext)
  394. {
  395. if (JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::GetItemReferenceQuery(originalInstance, index, value, requestContext)))
  396. {
  397. return PropertyQueryFlags::Property_Found;
  398. }
  399. if (this->hostObject && JavascriptConversion::PropertyQueryFlagsToBoolean(this->hostObject->GetItemReferenceQuery(originalInstance, index, value, requestContext)))
  400. {
  401. return PropertyQueryFlags::Property_Found;
  402. }
  403. *value = requestContext->GetMissingItemResult();
  404. return PropertyQueryFlags::Property_NotFound;
  405. }
  406. BOOL ModuleRoot::SetItem(uint32 index, Var value, PropertyOperationFlags flags)
  407. {
  408. if (DynamicObject::SetItem(index, value, flags))
  409. {
  410. return TRUE;
  411. }
  412. if (this->hostObject)
  413. {
  414. return this->hostObject->SetItem(index, value, flags);
  415. }
  416. return FALSE;
  417. }
  418. PropertyQueryFlags ModuleRoot::GetItemQuery(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext)
  419. {
  420. if (JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::GetItemQuery(originalInstance, index, value, requestContext)))
  421. {
  422. return PropertyQueryFlags::Property_Found;
  423. }
  424. if (this->hostObject && this->hostObject->GetItem(originalInstance, index, value, requestContext))
  425. {
  426. return PropertyQueryFlags::Property_Found;
  427. }
  428. *value = requestContext->GetMissingItemResult();
  429. return PropertyQueryFlags::Property_NotFound;
  430. }
  431. BOOL ModuleRoot::GetDiagValueString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext)
  432. {
  433. stringBuilder->AppendCppLiteral(_u("{Named Item}"));
  434. return TRUE;
  435. }
  436. BOOL ModuleRoot::GetDiagTypeString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext)
  437. {
  438. stringBuilder->AppendCppLiteral(_u("Object, (Named Item)"));
  439. return TRUE;
  440. }
  441. }