ArgumentsObject.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  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. #include "Library/ArgumentsObjectEnumerator.h"
  7. namespace Js
  8. {
  9. BOOL ArgumentsObject::GetEnumerator(JavascriptStaticEnumerator * enumerator, EnumeratorFlags flags, ScriptContext* requestContext, EnumeratorCache * enumeratorCache)
  10. {
  11. return GetEnumeratorWithPrefix(
  12. RecyclerNew(GetScriptContext()->GetRecycler(), ArgumentsObjectPrefixEnumerator, this, flags, requestContext),
  13. enumerator, flags, requestContext, enumeratorCache);
  14. }
  15. BOOL ArgumentsObject::GetDiagValueString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext)
  16. {
  17. stringBuilder->AppendCppLiteral(_u("{...}"));
  18. return TRUE;
  19. }
  20. BOOL ArgumentsObject::GetDiagTypeString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext)
  21. {
  22. stringBuilder->AppendCppLiteral(_u("Object, (Arguments)"));
  23. return TRUE;
  24. }
  25. HeapArgumentsObject::HeapArgumentsObject(DynamicType * type) : ArgumentsObject(type), frameObject(nullptr), formalCount(0),
  26. numOfArguments(0), callerDeleted(false), deletedArgs(nullptr)
  27. {
  28. }
  29. HeapArgumentsObject::HeapArgumentsObject(Recycler *recycler, ActivationObject* obj, uint32 formalCount, DynamicType * type)
  30. : ArgumentsObject(type), frameObject(obj), formalCount(formalCount), numOfArguments(0), callerDeleted(false), deletedArgs(nullptr)
  31. {
  32. Assert(!frameObject || VarIsCorrectType(frameObject));
  33. }
  34. void HeapArgumentsObject::SetNumberOfArguments(uint32 len)
  35. {
  36. numOfArguments = len;
  37. }
  38. uint32 HeapArgumentsObject::GetNumberOfArguments() const
  39. {
  40. return numOfArguments;
  41. }
  42. HeapArgumentsObject* HeapArgumentsObject::As(Var aValue)
  43. {
  44. if (VarIs<ArgumentsObject>(aValue) && static_cast<ArgumentsObject*>(VarTo<RecyclableObject>(aValue))->GetHeapArguments() == aValue)
  45. {
  46. return static_cast<HeapArgumentsObject*>(VarTo<RecyclableObject>(aValue));
  47. }
  48. return NULL;
  49. }
  50. BOOL HeapArgumentsObject::AdvanceWalkerToArgsFrame(JavascriptStackWalker *walker)
  51. {
  52. // Walk until we find this arguments object on the frame.
  53. // Note that each frame may have a HeapArgumentsObject
  54. // associated with it. Look for the HeapArgumentsObject.
  55. while (walker->Walk())
  56. {
  57. if (walker->IsJavascriptFrame() && walker->GetCurrentFunction()->IsScriptFunction())
  58. {
  59. Var args = walker->GetPermanentArguments();
  60. if (args == this)
  61. {
  62. return TRUE;
  63. }
  64. }
  65. }
  66. return FALSE;
  67. }
  68. //
  69. // Get the next valid formal arg index held in this object.
  70. //
  71. uint32 HeapArgumentsObject::GetNextFormalArgIndex(uint32 index, BOOL enumNonEnumerable, PropertyAttributes* attributes) const
  72. {
  73. if (attributes != nullptr)
  74. {
  75. *attributes = PropertyEnumerable;
  76. }
  77. if ( ++index < formalCount )
  78. {
  79. // None of the arguments deleted
  80. if ( deletedArgs == nullptr )
  81. {
  82. return index;
  83. }
  84. while ( index < formalCount )
  85. {
  86. if (!this->deletedArgs->Test(index))
  87. {
  88. return index;
  89. }
  90. index++;
  91. }
  92. }
  93. return JavascriptArray::InvalidIndex;
  94. }
  95. BOOL HeapArgumentsObject::HasItemAt(uint32 index)
  96. {
  97. // If this arg index is bound to a named formal argument, get it from the local frame.
  98. // If not, report this fact to the caller, which will defer to the normal get-value-by-index means.
  99. if (IsFormalArgument(index) && (this->deletedArgs == nullptr || !this->deletedArgs->Test(index)) )
  100. {
  101. return true;
  102. }
  103. return false;
  104. }
  105. BOOL HeapArgumentsObject::GetItemAt(uint32 index, Var* value, ScriptContext* requestContext)
  106. {
  107. // If this arg index is bound to a named formal argument, get it from the local frame.
  108. // If not, report this fact to the caller, which will defer to the normal get-value-by-index means.
  109. if (HasItemAt(index))
  110. {
  111. *value = this->frameObject->GetSlot(index);
  112. return true;
  113. }
  114. return false;
  115. }
  116. BOOL HeapArgumentsObject::SetItemAt(uint32 index, Var value)
  117. {
  118. // If this arg index is bound to a named formal argument, set it in the local frame.
  119. // If not, report this fact to the caller, which will defer to the normal set-value-by-index means.
  120. if (HasItemAt(index))
  121. {
  122. this->frameObject->SetSlot(SetSlotArguments(Constants::NoProperty, index, value));
  123. return true;
  124. }
  125. return false;
  126. }
  127. BOOL HeapArgumentsObject::DeleteItemAt(uint32 index)
  128. {
  129. if (index < formalCount)
  130. {
  131. if (this->deletedArgs == nullptr)
  132. {
  133. Recycler *recycler = GetScriptContext()->GetRecycler();
  134. deletedArgs = RecyclerNew(recycler, BVSparse<Recycler>, recycler);
  135. }
  136. if (!this->deletedArgs->Test(index))
  137. {
  138. this->deletedArgs->Set(index);
  139. return true;
  140. }
  141. }
  142. return false;
  143. }
  144. BOOL HeapArgumentsObject::IsFormalArgument(uint32 index)
  145. {
  146. return index < this->numOfArguments && index < formalCount;
  147. }
  148. BOOL HeapArgumentsObject::IsFormalArgument(PropertyId propertyId)
  149. {
  150. uint32 index;
  151. return IsFormalArgument(propertyId, &index);
  152. }
  153. BOOL HeapArgumentsObject::IsFormalArgument(PropertyId propertyId, uint32* pIndex)
  154. {
  155. return
  156. this->GetScriptContext()->IsNumericPropertyId(propertyId, pIndex) &&
  157. IsFormalArgument(*pIndex);
  158. }
  159. BOOL HeapArgumentsObject::IsArgumentDeleted(uint32 index) const
  160. {
  161. return this->deletedArgs != NULL && this->deletedArgs->Test(index);
  162. }
  163. #if ENABLE_TTD
  164. void HeapArgumentsObject::MarkVisitKindSpecificPtrs(TTD::SnapshotExtractor* extractor)
  165. {
  166. if(this->frameObject != nullptr)
  167. {
  168. extractor->MarkVisitVar(this->frameObject);
  169. }
  170. }
  171. TTD::NSSnapObjects::SnapObjectType HeapArgumentsObject::GetSnapTag_TTD() const
  172. {
  173. return TTD::NSSnapObjects::SnapObjectType::SnapHeapArgumentsObject;
  174. }
  175. void HeapArgumentsObject::ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc)
  176. {
  177. this->ExtractSnapObjectDataInto_Helper<TTD::NSSnapObjects::SnapObjectType::SnapHeapArgumentsObject>(objData, alloc);
  178. }
  179. template <TTD::NSSnapObjects::SnapObjectType argsKind>
  180. void HeapArgumentsObject::ExtractSnapObjectDataInto_Helper(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc)
  181. {
  182. TTD::NSSnapObjects::SnapHeapArgumentsInfo* argsInfo = alloc.SlabAllocateStruct<TTD::NSSnapObjects::SnapHeapArgumentsInfo>();
  183. TTDAssert(this->callerDeleted == 0, "This never seems to be set but I want to assert just to be safe.");
  184. argsInfo->NumOfArguments = this->numOfArguments;
  185. argsInfo->FormalCount = this->formalCount;
  186. uint32 depOnCount = 0;
  187. TTD_PTR_ID* depOnArray = nullptr;
  188. argsInfo->IsFrameNullPtr = false;
  189. argsInfo->FrameObject = TTD_INVALID_PTR_ID;
  190. if(this->frameObject == nullptr)
  191. {
  192. argsInfo->IsFrameNullPtr = true;
  193. }
  194. else
  195. {
  196. argsInfo->FrameObject = TTD_CONVERT_VAR_TO_PTR_ID(this->frameObject);
  197. //Primitive kinds always inflated first so we only need to deal with complex kinds as depends on
  198. if(TTD::JsSupport::IsVarComplexKind(this->frameObject))
  199. {
  200. depOnCount = 1;
  201. depOnArray = alloc.SlabAllocateArray<TTD_PTR_ID>(depOnCount);
  202. depOnArray[0] = argsInfo->FrameObject;
  203. }
  204. }
  205. argsInfo->DeletedArgFlags = (this->formalCount != 0) ? alloc.SlabAllocateArrayZ<byte>(argsInfo->FormalCount) : nullptr;
  206. if(this->deletedArgs != nullptr)
  207. {
  208. for(uint32 i = 0; i < this->formalCount; ++i)
  209. {
  210. if(this->deletedArgs->Test(i))
  211. {
  212. argsInfo->DeletedArgFlags[i] = true;
  213. }
  214. }
  215. }
  216. if(depOnCount == 0)
  217. {
  218. TTD::NSSnapObjects::StdExtractSetKindSpecificInfo<TTD::NSSnapObjects::SnapHeapArgumentsInfo*, argsKind>(objData, argsInfo);
  219. }
  220. else
  221. {
  222. TTD::NSSnapObjects::StdExtractSetKindSpecificInfo<TTD::NSSnapObjects::SnapHeapArgumentsInfo*, argsKind>(objData, argsInfo, alloc, depOnCount, depOnArray);
  223. }
  224. }
  225. ES5HeapArgumentsObject* HeapArgumentsObject::ConvertToES5HeapArgumentsObject_TTD()
  226. {
  227. Assert(VirtualTableInfo<HeapArgumentsObject>::HasVirtualTable(this));
  228. VirtualTableInfo<ES5HeapArgumentsObject>::SetVirtualTable(this);
  229. return static_cast<ES5HeapArgumentsObject*>(this);
  230. }
  231. #endif
  232. ES5HeapArgumentsObject* HeapArgumentsObject::ConvertToUnmappedArgumentsObject(bool overwriteArgsUsingFrameObject)
  233. {
  234. ES5HeapArgumentsObject* es5ArgsObj = ConvertToES5HeapArgumentsObject(overwriteArgsUsingFrameObject);
  235. for (uint i=0; i<this->formalCount && i<numOfArguments; ++i)
  236. {
  237. es5ArgsObj->DisconnectFormalFromNamedArgument(i);
  238. }
  239. return es5ArgsObj;
  240. }
  241. ES5HeapArgumentsObject* HeapArgumentsObject::ConvertToES5HeapArgumentsObject(bool overwriteArgsUsingFrameObject)
  242. {
  243. if (!CrossSite::IsCrossSiteObjectTyped(this))
  244. {
  245. Assert(VirtualTableInfo<HeapArgumentsObject>::HasVirtualTable(this));
  246. VirtualTableInfo<ES5HeapArgumentsObject>::SetVirtualTable(this);
  247. }
  248. else
  249. {
  250. Assert(VirtualTableInfo<CrossSiteObject<HeapArgumentsObject>>::HasVirtualTable(this));
  251. VirtualTableInfo<CrossSiteObject<ES5HeapArgumentsObject>>::SetVirtualTable(this);
  252. }
  253. ES5HeapArgumentsObject* es5This = static_cast<ES5HeapArgumentsObject*>(this);
  254. if (overwriteArgsUsingFrameObject)
  255. {
  256. // Copy existing items to the array so that they are there before the user can call Object.preventExtensions,
  257. // after which we can no longer add new items to the objectArray.
  258. for (uint32 i = 0; i < this->formalCount && i < this->numOfArguments; ++i)
  259. {
  260. AssertMsg(this->IsFormalArgument(i), "this->IsFormalArgument(i)");
  261. if (!this->IsArgumentDeleted(i))
  262. {
  263. // At this time the value doesn't matter, use one from slots.
  264. this->SetObjectArrayItem(i, this->frameObject->GetSlot(i), PropertyOperation_None);
  265. }
  266. }
  267. }
  268. return es5This;
  269. }
  270. PropertyQueryFlags HeapArgumentsObject::HasPropertyQuery(PropertyId id, _Inout_opt_ PropertyValueInfo* info)
  271. {
  272. ScriptContext *scriptContext = GetScriptContext();
  273. // Try to get a numbered property that maps to an actual argument.
  274. uint32 index;
  275. if (scriptContext->IsNumericPropertyId(id, &index) && index < this->HeapArgumentsObject::GetNumberOfArguments())
  276. {
  277. return HeapArgumentsObject::HasItemQuery(index);
  278. }
  279. return DynamicObject::HasPropertyQuery(id, info);
  280. }
  281. PropertyQueryFlags HeapArgumentsObject::GetPropertyQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  282. {
  283. ScriptContext *scriptContext = GetScriptContext();
  284. // Try to get a numbered property that maps to an actual argument.
  285. uint32 index;
  286. if (scriptContext->IsNumericPropertyId(propertyId, &index) && index < this->HeapArgumentsObject::GetNumberOfArguments())
  287. {
  288. if (this->GetItemAt(index, value, requestContext))
  289. {
  290. return PropertyQueryFlags::Property_Found;
  291. }
  292. }
  293. if (JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::GetPropertyQuery(originalInstance, propertyId, value, info, requestContext)))
  294. {
  295. // Property has been pre-set and not deleted. Use it.
  296. return PropertyQueryFlags::Property_Found;
  297. }
  298. *value = requestContext->GetMissingPropertyResult();
  299. return PropertyQueryFlags::Property_NotFound;
  300. }
  301. PropertyQueryFlags HeapArgumentsObject::GetPropertyQuery(Var originalInstance, JavascriptString* propertyNameString, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  302. {
  303. AssertMsg(!PropertyRecord::IsPropertyNameNumeric(propertyNameString->GetString(), propertyNameString->GetLength()),
  304. "Numeric property names should have been converted to uint or PropertyRecord*");
  305. if (JavascriptConversion::PropertyQueryFlagsToBoolean(DynamicObject::GetPropertyQuery(originalInstance, propertyNameString, value, info, requestContext)))
  306. {
  307. // Property has been pre-set and not deleted. Use it.
  308. return PropertyQueryFlags::Property_Found;
  309. }
  310. *value = requestContext->GetMissingPropertyResult();
  311. return PropertyQueryFlags::Property_NotFound;
  312. }
  313. PropertyQueryFlags HeapArgumentsObject::GetPropertyReferenceQuery(Var originalInstance, PropertyId id, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
  314. {
  315. return HeapArgumentsObject::GetPropertyQuery(originalInstance, id, value, info, requestContext);
  316. }
  317. BOOL HeapArgumentsObject::SetProperty(PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  318. {
  319. // Try to set a numbered property that maps to an actual argument.
  320. ScriptContext *scriptContext = GetScriptContext();
  321. uint32 index;
  322. if (scriptContext->IsNumericPropertyId(propertyId, &index) && index < this->HeapArgumentsObject::GetNumberOfArguments())
  323. {
  324. if (this->SetItemAt(index, value))
  325. {
  326. return true;
  327. }
  328. }
  329. // TODO: In strict mode, "callee" and "caller" cannot be set.
  330. // length is also set in the dynamic object
  331. return DynamicObject::SetProperty(propertyId, value, flags, info);
  332. }
  333. BOOL HeapArgumentsObject::SetProperty(JavascriptString* propertyNameString, Var value, PropertyOperationFlags flags, PropertyValueInfo* info)
  334. {
  335. AssertMsg(!PropertyRecord::IsPropertyNameNumeric(propertyNameString->GetString(), propertyNameString->GetLength()),
  336. "Numeric property names should have been converted to uint or PropertyRecord*");
  337. // TODO: In strict mode, "callee" and "caller" cannot be set.
  338. // length is also set in the dynamic object
  339. return DynamicObject::SetProperty(propertyNameString, value, flags, info);
  340. }
  341. PropertyQueryFlags HeapArgumentsObject::HasItemQuery(uint32 index)
  342. {
  343. if (this->HasItemAt(index))
  344. {
  345. return PropertyQueryFlags::Property_Found;
  346. }
  347. return DynamicObject::HasItemQuery(index);
  348. }
  349. PropertyQueryFlags HeapArgumentsObject::GetItemQuery(Var originalInstance, uint32 index, Var* value, ScriptContext* requestContext)
  350. {
  351. if (this->GetItemAt(index, value, requestContext))
  352. {
  353. return PropertyQueryFlags::Property_Found;
  354. }
  355. return DynamicObject::GetItemQuery(originalInstance, index, value, requestContext);
  356. }
  357. PropertyQueryFlags HeapArgumentsObject::GetItemReferenceQuery(Var originalInstance, uint32 index, Var* value, ScriptContext* requestContext)
  358. {
  359. return HeapArgumentsObject::GetItemQuery(originalInstance, index, value, requestContext);
  360. }
  361. BOOL HeapArgumentsObject::SetItem(uint32 index, Var value, PropertyOperationFlags flags)
  362. {
  363. if (this->SetItemAt(index, value))
  364. {
  365. return true;
  366. }
  367. return DynamicObject::SetItem(index, value, flags);
  368. }
  369. BOOL HeapArgumentsObject::DeleteItem(uint32 index, PropertyOperationFlags flags)
  370. {
  371. if (this->DeleteItemAt(index))
  372. {
  373. return true;
  374. }
  375. return DynamicObject::DeleteItem(index, flags);
  376. }
  377. BOOL HeapArgumentsObject::SetConfigurable(PropertyId propertyId, BOOL value)
  378. {
  379. // Try to set a numbered property that maps to an actual argument.
  380. uint32 index;
  381. if (this->IsFormalArgument(propertyId, &index))
  382. {
  383. // From now on, make sure that frame object is ES5HeapArgumentsObject.
  384. return this->ConvertToES5HeapArgumentsObject()->SetConfigurableForFormal(index, propertyId, value);
  385. }
  386. // Use 'this' dynamic object.
  387. // This will use type handler and convert its objectArray to ES5Array is not already converted.
  388. return __super::SetConfigurable(propertyId, value);
  389. }
  390. BOOL HeapArgumentsObject::SetEnumerable(PropertyId propertyId, BOOL value)
  391. {
  392. uint32 index;
  393. if (this->IsFormalArgument(propertyId, &index))
  394. {
  395. return this->ConvertToES5HeapArgumentsObject()->SetEnumerableForFormal(index, propertyId, value);
  396. }
  397. return __super::SetEnumerable(propertyId, value);
  398. }
  399. BOOL HeapArgumentsObject::SetWritable(PropertyId propertyId, BOOL value)
  400. {
  401. uint32 index;
  402. if (this->IsFormalArgument(propertyId, &index))
  403. {
  404. return this->ConvertToES5HeapArgumentsObject()->SetWritableForFormal(index, propertyId, value);
  405. }
  406. return __super::SetWritable(propertyId, value);
  407. }
  408. BOOL HeapArgumentsObject::SetAccessors(PropertyId propertyId, Var getter, Var setter, PropertyOperationFlags flags)
  409. {
  410. uint32 index;
  411. if (this->IsFormalArgument(propertyId, &index))
  412. {
  413. return this->ConvertToES5HeapArgumentsObject()->SetAccessorsForFormal(index, propertyId, getter, setter, flags);
  414. }
  415. return __super::SetAccessors(propertyId, getter, setter, flags);
  416. }
  417. BOOL HeapArgumentsObject::SetPropertyWithAttributes(PropertyId propertyId, Var value, PropertyAttributes attributes, PropertyValueInfo* info, PropertyOperationFlags flags, SideEffects possibleSideEffects)
  418. {
  419. // This is called by defineProperty in order to change the value in objectArray.
  420. // We have to intercept this call because
  421. // in case when we are connected (objectArray item is not used) we need to update the slot value (which is actually used).
  422. uint32 index;
  423. if (this->IsFormalArgument(propertyId, &index))
  424. {
  425. return this->ConvertToES5HeapArgumentsObject()->SetPropertyWithAttributesForFormal(
  426. index, propertyId, value, attributes, info, flags, possibleSideEffects);
  427. }
  428. return __super::SetPropertyWithAttributes(propertyId, value, attributes, info, flags, possibleSideEffects);
  429. }
  430. // This disables adding new properties to the object.
  431. BOOL HeapArgumentsObject::PreventExtensions()
  432. {
  433. // It's possible that after call to preventExtensions, the user can change the attributes;
  434. // In this case if we don't covert to ES5 version now, later we would not be able to add items to objectArray,
  435. // which would cause not being able to change attributes.
  436. // So, convert to ES5 now which will make sure the items are there.
  437. return this->ConvertToES5HeapArgumentsObject()->PreventExtensions();
  438. }
  439. // This is equivalent to .preventExtensions semantics with addition of setting configurable to false for all properties.
  440. BOOL HeapArgumentsObject::Seal()
  441. {
  442. // Same idea as with PreventExtensions: we have to make sure that items in objectArray for formals
  443. // are there before seal, otherwise we will not be able to add them later.
  444. return this->ConvertToES5HeapArgumentsObject()->Seal();
  445. }
  446. // This is equivalent to .seal semantics with addition of setting writable to false for all properties.
  447. BOOL HeapArgumentsObject::Freeze()
  448. {
  449. // Same idea as with PreventExtensions: we have to make sure that items in objectArray for formals
  450. // are there before seal, otherwise we will not be able to add them later.
  451. return this->ConvertToES5HeapArgumentsObject()->Freeze();
  452. }
  453. //---------------------- ES5HeapArgumentsObject -------------------------------
  454. BOOL ES5HeapArgumentsObject::SetConfigurable(PropertyId propertyId, BOOL value)
  455. {
  456. uint32 index;
  457. if (this->IsFormalArgument(propertyId, &index))
  458. {
  459. return this->SetConfigurableForFormal(index, propertyId, value);
  460. }
  461. return this->DynamicObject::SetConfigurable(propertyId, value);
  462. }
  463. BOOL ES5HeapArgumentsObject::SetEnumerable(PropertyId propertyId, BOOL value)
  464. {
  465. uint32 index;
  466. if (this->IsFormalArgument(propertyId, &index))
  467. {
  468. return this->SetEnumerableForFormal(index, propertyId, value);
  469. }
  470. return this->DynamicObject::SetEnumerable(propertyId, value);
  471. }
  472. BOOL ES5HeapArgumentsObject::SetWritable(PropertyId propertyId, BOOL value)
  473. {
  474. uint32 index;
  475. if (this->IsFormalArgument(propertyId, &index))
  476. {
  477. return this->SetWritableForFormal(index, propertyId, value);
  478. }
  479. return this->DynamicObject::SetWritable(propertyId, value);
  480. }
  481. BOOL ES5HeapArgumentsObject::SetAccessors(PropertyId propertyId, Var getter, Var setter, PropertyOperationFlags flags)
  482. {
  483. uint32 index;
  484. if (this->IsFormalArgument(propertyId, &index))
  485. {
  486. return SetAccessorsForFormal(index, propertyId, getter, setter);
  487. }
  488. return this->DynamicObject::SetAccessors(propertyId, getter, setter, flags);
  489. }
  490. BOOL ES5HeapArgumentsObject::SetPropertyWithAttributes(PropertyId propertyId, Var value, PropertyAttributes attributes, PropertyValueInfo* info, PropertyOperationFlags flags, SideEffects possibleSideEffects)
  491. {
  492. // This is called by defineProperty in order to change the value in objectArray.
  493. // We have to intercept this call because
  494. // in case when we are connected (objectArray item is not used) we need to update the slot value (which is actually used).
  495. uint32 index;
  496. if (this->IsFormalArgument(propertyId, &index))
  497. {
  498. return this->SetPropertyWithAttributesForFormal(index, propertyId, value, attributes, info, flags, possibleSideEffects);
  499. }
  500. return this->DynamicObject::SetPropertyWithAttributes(propertyId, value, attributes, info, flags, possibleSideEffects);
  501. }
  502. BOOL ES5HeapArgumentsObject::GetEnumerator(JavascriptStaticEnumerator * enumerator, EnumeratorFlags flags, ScriptContext* requestContext, EnumeratorCache * enumeratorCache)
  503. {
  504. ES5ArgumentsObjectEnumerator * es5HeapArgumentsObjectEnumerator = ES5ArgumentsObjectEnumerator::New(this, flags, requestContext, enumeratorCache);
  505. if (es5HeapArgumentsObjectEnumerator == nullptr)
  506. {
  507. return false;
  508. }
  509. return enumerator->Initialize(es5HeapArgumentsObjectEnumerator, nullptr, nullptr, flags, requestContext, nullptr);
  510. }
  511. BOOL ES5HeapArgumentsObject::PreventExtensions()
  512. {
  513. return this->DynamicObject::PreventExtensions();
  514. }
  515. BOOL ES5HeapArgumentsObject::Seal()
  516. {
  517. return this->DynamicObject::Seal();
  518. }
  519. BOOL ES5HeapArgumentsObject::Freeze()
  520. {
  521. return this->DynamicObject::Freeze();
  522. }
  523. BOOL ES5HeapArgumentsObject::GetItemAt(uint32 index, Var* value, ScriptContext* requestContext)
  524. {
  525. return this->IsFormalDisconnectedFromNamedArgument(index) ?
  526. JavascriptConversion::PropertyQueryFlagsToBoolean(this->DynamicObject::GetItemQuery(this, index, value, requestContext)) :
  527. __super::GetItemAt(index, value, requestContext);
  528. }
  529. BOOL ES5HeapArgumentsObject::SetItemAt(uint32 index, Var value)
  530. {
  531. return this->IsFormalDisconnectedFromNamedArgument(index) ?
  532. this->DynamicObject::SetItem(index, value, PropertyOperation_None) :
  533. __super::SetItemAt(index, value);
  534. }
  535. BOOL ES5HeapArgumentsObject::DeleteItemAt(uint32 index)
  536. {
  537. BOOL result = __super::DeleteItemAt(index);
  538. if (result && IsFormalArgument(index))
  539. {
  540. AssertMsg(this->IsFormalDisconnectedFromNamedArgument(index), "__super::DeleteItemAt must perform the disconnect.");
  541. // Make sure that objectArray does not have the item ().
  542. if (this->HasObjectArrayItem(index))
  543. {
  544. this->DeleteObjectArrayItem(index, PropertyOperation_None);
  545. }
  546. }
  547. return result;
  548. }
  549. //
  550. // Get the next valid formal arg index held in this object.
  551. //
  552. uint32 ES5HeapArgumentsObject::GetNextFormalArgIndex(uint32 index, BOOL enumNonEnumerable, PropertyAttributes* attributes) const
  553. {
  554. return GetNextFormalArgIndexHelper(index, enumNonEnumerable, attributes);
  555. }
  556. uint32 ES5HeapArgumentsObject::GetNextFormalArgIndexHelper(uint32 index, BOOL enumNonEnumerable, PropertyAttributes* attributes) const
  557. {
  558. // Formals:
  559. // - deleted => not in objectArray && not connected -- do not enum, do not advance.
  560. // - connected, if in objectArray -- if (enumerable) enum it, advance objectEnumerator.
  561. // - disconnected =>in objectArray -- if (enumerable) enum it, advance objectEnumerator.
  562. // We use GetFormalCount and IsEnumerableByIndex which don't change the object
  563. // but are not declared as const, so do a const cast.
  564. ES5HeapArgumentsObject* mutableThis = const_cast<ES5HeapArgumentsObject*>(this);
  565. uint32 formalCount = this->GetFormalCount();
  566. while (++index < formalCount)
  567. {
  568. bool isDeleted = mutableThis->IsFormalDisconnectedFromNamedArgument(index) &&
  569. !mutableThis->HasObjectArrayItem(index);
  570. if (!isDeleted)
  571. {
  572. BOOL isEnumerable = mutableThis->IsEnumerableByIndex(index);
  573. if (enumNonEnumerable || isEnumerable)
  574. {
  575. if (attributes != nullptr && isEnumerable)
  576. {
  577. *attributes = PropertyEnumerable;
  578. }
  579. return index;
  580. }
  581. }
  582. }
  583. return JavascriptArray::InvalidIndex;
  584. }
  585. // Disconnects indexed argument from named argument for frame object property.
  586. // Remove association from them map. From now on (or still) for this argument,
  587. // named argument's value is no longer associated with arguments[] item.
  588. void ES5HeapArgumentsObject::DisconnectFormalFromNamedArgument(uint32 index)
  589. {
  590. AssertMsg(this->IsFormalArgument(index), "SetAccessorsForFormal: called for non-formal");
  591. if (!IsFormalDisconnectedFromNamedArgument(index))
  592. {
  593. __super::DeleteItemAt(index);
  594. }
  595. }
  596. BOOL ES5HeapArgumentsObject::IsFormalDisconnectedFromNamedArgument(uint32 index)
  597. {
  598. return this->IsArgumentDeleted(index);
  599. }
  600. // Wrapper over IsEnumerable by uint32 index.
  601. BOOL ES5HeapArgumentsObject::IsEnumerableByIndex(uint32 index)
  602. {
  603. ScriptContext* scriptContext = this->GetScriptContext();
  604. Var indexNumber = JavascriptNumber::New(index, scriptContext);
  605. JavascriptString* indexPropertyName = JavascriptConversion::ToString(indexNumber, scriptContext);
  606. PropertyRecord const * propertyRecord;
  607. scriptContext->GetOrAddPropertyRecord(indexPropertyName, &propertyRecord);
  608. return this->IsEnumerable(propertyRecord->GetPropertyId());
  609. }
  610. // Helper method, just to avoid code duplication.
  611. BOOL ES5HeapArgumentsObject::SetConfigurableForFormal(uint32 index, PropertyId propertyId, BOOL value)
  612. {
  613. AssertMsg(this->IsFormalArgument(index), "SetAccessorsForFormal: called for non-formal");
  614. // In order for attributes to work, the item must exist. Make sure that's the case.
  615. // If we were connected, we have to copy the value from frameObject->slots, otherwise which value doesn't matter.
  616. AutoObjectArrayItemExistsValidator autoItemAddRelease(this, index);
  617. BOOL result = this->DynamicObject::SetConfigurable(propertyId, value);
  618. autoItemAddRelease.m_isReleaseItemNeeded = !result;
  619. return result;
  620. }
  621. // Helper method, just to avoid code duplication.
  622. BOOL ES5HeapArgumentsObject::SetEnumerableForFormal(uint32 index, PropertyId propertyId, BOOL value)
  623. {
  624. AssertMsg(this->IsFormalArgument(index), "SetAccessorsForFormal: called for non-formal");
  625. AutoObjectArrayItemExistsValidator autoItemAddRelease(this, index);
  626. BOOL result = this->DynamicObject::SetEnumerable(propertyId, value);
  627. autoItemAddRelease.m_isReleaseItemNeeded = !result;
  628. return result;
  629. }
  630. // Helper method, just to avoid code duplication.
  631. BOOL ES5HeapArgumentsObject::SetWritableForFormal(uint32 index, PropertyId propertyId, BOOL value)
  632. {
  633. AssertMsg(this->IsFormalArgument(index), "SetAccessorsForFormal: called for non-formal");
  634. AutoObjectArrayItemExistsValidator autoItemAddRelease(this, index);
  635. BOOL isDisconnected = IsFormalDisconnectedFromNamedArgument(index);
  636. if (!isDisconnected && !value)
  637. {
  638. // Settings writable to false causes disconnect.
  639. // It will be too late to copy the value after setting writable = false, as we would not be able to.
  640. // Since we are connected, it does not matter the value is, so it's safe (no matter if SetWritable fails) to copy it here.
  641. this->SetObjectArrayItem(index, this->frameObject->GetSlot(index), PropertyOperation_None);
  642. }
  643. BOOL result = this->DynamicObject::SetWritable(propertyId, value); // Note: this will convert objectArray to ES5Array.
  644. if (result && !value && !isDisconnected)
  645. {
  646. this->DisconnectFormalFromNamedArgument(index);
  647. }
  648. autoItemAddRelease.m_isReleaseItemNeeded = !result;
  649. return result;
  650. }
  651. // Helper method for SetPropertyWithAttributes, just to avoid code duplication.
  652. BOOL ES5HeapArgumentsObject::SetAccessorsForFormal(uint32 index, PropertyId propertyId, Var getter, Var setter, PropertyOperationFlags flags)
  653. {
  654. AssertMsg(this->IsFormalArgument(index), "SetAccessorsForFormal: called for non-formal");
  655. AutoObjectArrayItemExistsValidator autoItemAddRelease(this, index);
  656. BOOL result = this->DynamicObject::SetAccessors(propertyId, getter, setter, flags);
  657. if (result)
  658. {
  659. this->DisconnectFormalFromNamedArgument(index);
  660. }
  661. autoItemAddRelease.m_isReleaseItemNeeded = !result;
  662. return result;
  663. }
  664. // Helper method for SetPropertyWithAttributes, just to avoid code duplication.
  665. BOOL ES5HeapArgumentsObject::SetPropertyWithAttributesForFormal(uint32 index, PropertyId propertyId, Var value, PropertyAttributes attributes, PropertyValueInfo* info, PropertyOperationFlags flags, SideEffects possibleSideEffects)
  666. {
  667. AssertMsg(this->IsFormalArgument(propertyId), "SetPropertyWithAttributesForFormal: called for non-formal");
  668. BOOL result = this->DynamicObject::SetPropertyWithAttributes(propertyId, value, attributes, info, flags, possibleSideEffects);
  669. if (result)
  670. {
  671. if ((attributes & PropertyWritable) == 0)
  672. {
  673. // Setting writable to false should cause disconnect.
  674. this->DisconnectFormalFromNamedArgument(index);
  675. }
  676. if (!this->IsFormalDisconnectedFromNamedArgument(index))
  677. {
  678. // Update the (connected with named param) value, as above call could cause change of the value.
  679. BOOL tempResult = this->SetItemAt(index, value); // Update the value in frameObject.
  680. AssertMsg(tempResult, "this->SetItem(index, value)");
  681. }
  682. }
  683. return result;
  684. }
  685. //---------------------- ES5HeapArgumentsObject::AutoObjectArrayItemExistsValidator -------------------------------
  686. ES5HeapArgumentsObject::AutoObjectArrayItemExistsValidator::AutoObjectArrayItemExistsValidator(ES5HeapArgumentsObject* args, uint32 index)
  687. : m_args(args), m_index(index), m_isReleaseItemNeeded(false)
  688. {
  689. AssertMsg(args, "args");
  690. AssertMsg(args->IsFormalArgument(index), "AutoObjectArrayItemExistsValidator: called for non-formal");
  691. if (!args->HasObjectArrayItem(index))
  692. {
  693. m_isReleaseItemNeeded = args->SetObjectArrayItem(index, args->frameObject->GetSlot(index), PropertyOperation_None) != FALSE;
  694. }
  695. }
  696. ES5HeapArgumentsObject::AutoObjectArrayItemExistsValidator::~AutoObjectArrayItemExistsValidator()
  697. {
  698. if (m_isReleaseItemNeeded)
  699. {
  700. m_args->DeleteObjectArrayItem(m_index, PropertyOperation_None);
  701. }
  702. }
  703. #if ENABLE_TTD
  704. TTD::NSSnapObjects::SnapObjectType ES5HeapArgumentsObject::GetSnapTag_TTD() const
  705. {
  706. return TTD::NSSnapObjects::SnapObjectType::SnapES5HeapArgumentsObject;
  707. }
  708. void ES5HeapArgumentsObject::ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc)
  709. {
  710. this->ExtractSnapObjectDataInto_Helper<TTD::NSSnapObjects::SnapObjectType::SnapES5HeapArgumentsObject>(objData, alloc);
  711. }
  712. #endif
  713. }