ArgumentsObject.cpp 34 KB

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