JavascriptSet.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  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. JavascriptSet::JavascriptSet(DynamicType* type)
  9. : DynamicObject(type)
  10. {
  11. }
  12. JavascriptSet* JavascriptSet::New(ScriptContext* scriptContext)
  13. {
  14. JavascriptSet* set = scriptContext->GetLibrary()->CreateSet();
  15. return set;
  16. }
  17. bool JavascriptSet::Is(Var aValue)
  18. {
  19. return JavascriptOperators::GetTypeId(aValue) == TypeIds_Set;
  20. }
  21. JavascriptSet* JavascriptSet::FromVar(Var aValue)
  22. {
  23. AssertOrFailFastMsg(Is(aValue), "Ensure var is actually a 'JavascriptSet'");
  24. return static_cast<JavascriptSet *>(aValue);
  25. }
  26. JavascriptSet* JavascriptSet::UnsafeFromVar(Var aValue)
  27. {
  28. AssertMsg(Is(aValue), "Ensure var is actually a 'JavascriptSet'");
  29. return static_cast<JavascriptSet *>(aValue);
  30. }
  31. JavascriptSet::SetDataList::Iterator JavascriptSet::GetIterator()
  32. {
  33. return this->list.GetIterator();
  34. }
  35. Var JavascriptSet::NewInstance(RecyclableObject* function, CallInfo callInfo, ...)
  36. {
  37. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  38. ARGUMENTS(args, callInfo);
  39. ScriptContext* scriptContext = function->GetScriptContext();
  40. JavascriptLibrary* library = scriptContext->GetLibrary();
  41. AUTO_TAG_NATIVE_LIBRARY_ENTRY(function, callInfo, _u("Set"));
  42. Var newTarget = args.GetNewTarget();
  43. bool isCtorSuperCall = JavascriptOperators::GetAndAssertIsConstructorSuperCall(args);
  44. CHAKRATEL_LANGSTATS_INC_LANGFEATURECOUNT(ES6, Set, scriptContext);
  45. JavascriptSet* setObject = nullptr;
  46. if (callInfo.Flags & CallFlags_New)
  47. {
  48. setObject = library->CreateSet();
  49. }
  50. else
  51. {
  52. JavascriptError::ThrowTypeErrorVar(scriptContext, JSERR_NeedObjectOfType, _u("Set"), _u("Set"));
  53. }
  54. Assert(setObject != nullptr);
  55. Var iterable = (args.Info.Count > 1) ? args[1] : library->GetUndefined();
  56. // REVIEW: This condition seems impossible?
  57. if (setObject->kind != SetKind::EmptySet)
  58. {
  59. Assert(UNREACHED);
  60. JavascriptError::ThrowTypeErrorVar(scriptContext, JSERR_ObjectIsAlreadyInitialized, _u("Set"), _u("Set"));
  61. }
  62. RecyclableObject* iter = nullptr;
  63. RecyclableObject* adder = nullptr;
  64. if (JavascriptConversion::CheckObjectCoercible(iterable, scriptContext))
  65. {
  66. iter = JavascriptOperators::GetIterator(iterable, scriptContext);
  67. Var adderVar = JavascriptOperators::GetPropertyNoCache(setObject, PropertyIds::add, scriptContext);
  68. if (!JavascriptConversion::IsCallable(adderVar))
  69. {
  70. JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedFunction);
  71. }
  72. adder = RecyclableObject::FromVar(adderVar);
  73. }
  74. if (iter != nullptr)
  75. {
  76. JavascriptOperators::DoIteratorStepAndValue(iter, scriptContext, [&](Var nextItem) {
  77. CALL_FUNCTION(scriptContext->GetThreadContext(), adder, CallInfo(CallFlags_Value, 2), setObject, nextItem);
  78. });
  79. }
  80. return isCtorSuperCall ?
  81. JavascriptOperators::OrdinaryCreateFromConstructor(RecyclableObject::FromVar(newTarget), setObject, nullptr, scriptContext) :
  82. setObject;
  83. }
  84. Var JavascriptSet::EntryAdd(RecyclableObject* function, CallInfo callInfo, ...)
  85. {
  86. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  87. ARGUMENTS(args, callInfo);
  88. ScriptContext* scriptContext = function->GetScriptContext();
  89. JavascriptSet* set = JavascriptOperators::TryFromVar<JavascriptSet>(args[0]);
  90. if (set == nullptr)
  91. {
  92. JavascriptError::ThrowTypeErrorVar(scriptContext, JSERR_NeedObjectOfType, _u("Set.prototype.add"), _u("Set"));
  93. }
  94. Var value = (args.Info.Count > 1) ? args[1] : scriptContext->GetLibrary()->GetUndefined();
  95. if (JavascriptNumber::Is(value) && JavascriptNumber::IsNegZero(JavascriptNumber::GetValue(value)))
  96. {
  97. // Normalize -0 to +0
  98. value = JavascriptNumber::New(0.0, scriptContext);
  99. }
  100. set->Add(value);
  101. return set;
  102. }
  103. Var JavascriptSet::EntryClear(RecyclableObject* function, CallInfo callInfo, ...)
  104. {
  105. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  106. ARGUMENTS(args, callInfo);
  107. ScriptContext* scriptContext = function->GetScriptContext();
  108. JavascriptSet* set = JavascriptOperators::TryFromVar<JavascriptSet>(args[0]);
  109. if (set == nullptr)
  110. {
  111. JavascriptError::ThrowTypeErrorVar(scriptContext, JSERR_NeedObjectOfType, _u("Set.prototype.clear"), _u("Set"));
  112. }
  113. set->Clear();
  114. return scriptContext->GetLibrary()->GetUndefined();
  115. }
  116. Var JavascriptSet::EntryDelete(RecyclableObject* function, CallInfo callInfo, ...)
  117. {
  118. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  119. ARGUMENTS(args, callInfo);
  120. ScriptContext* scriptContext = function->GetScriptContext();
  121. JavascriptSet* set = JavascriptOperators::TryFromVar<JavascriptSet>(args[0]);
  122. if (set == nullptr)
  123. {
  124. JavascriptError::ThrowTypeErrorVar(scriptContext, JSERR_NeedObjectOfType, _u("Set.prototype.delete"), _u("Set"));
  125. }
  126. Var value = (args.Info.Count > 1) ? args[1] : scriptContext->GetLibrary()->GetUndefined();
  127. bool didDelete = set->Delete(value);
  128. return scriptContext->GetLibrary()->CreateBoolean(didDelete);
  129. }
  130. Var JavascriptSet::EntryForEach(RecyclableObject* function, CallInfo callInfo, ...)
  131. {
  132. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  133. ARGUMENTS(args, callInfo);
  134. ScriptContext* scriptContext = function->GetScriptContext();
  135. AUTO_TAG_NATIVE_LIBRARY_ENTRY(function, callInfo, _u("Set.prototype.forEach"));
  136. JavascriptSet* set = JavascriptOperators::TryFromVar<JavascriptSet>(args[0]);
  137. if (set == nullptr)
  138. {
  139. JavascriptError::ThrowTypeErrorVar(scriptContext, JSERR_NeedObjectOfType, _u("Set.prototype.forEach"), _u("Set"));
  140. }
  141. if (args.Info.Count < 2 || !JavascriptConversion::IsCallable(args[1]))
  142. {
  143. JavascriptError::ThrowTypeError(scriptContext, JSERR_FunctionArgument_NeedFunction, _u("Set.prototype.forEach"));
  144. }
  145. RecyclableObject* callBackFn = RecyclableObject::FromVar(args[1]);
  146. Var thisArg = (args.Info.Count > 2) ? args[2] : scriptContext->GetLibrary()->GetUndefined();
  147. auto iterator = set->GetIterator();
  148. while (iterator.Next())
  149. {
  150. Var value = iterator.Current();
  151. CALL_FUNCTION(scriptContext->GetThreadContext(), callBackFn, CallInfo(CallFlags_Value, 4), thisArg, value, value, args[0]);
  152. }
  153. return scriptContext->GetLibrary()->GetUndefined();
  154. }
  155. Var JavascriptSet::EntryHas(RecyclableObject* function, CallInfo callInfo, ...)
  156. {
  157. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  158. ARGUMENTS(args, callInfo);
  159. ScriptContext* scriptContext = function->GetScriptContext();
  160. JavascriptSet* set = JavascriptOperators::TryFromVar<JavascriptSet>(args[0]);
  161. if (set == nullptr)
  162. {
  163. JavascriptError::ThrowTypeErrorVar(scriptContext, JSERR_NeedObjectOfType, _u("Set.prototype.has"), _u("Set"));
  164. }
  165. Var value = (args.Info.Count > 1) ? args[1] : scriptContext->GetLibrary()->GetUndefined();
  166. bool hasValue = set->Has(value);
  167. return scriptContext->GetLibrary()->CreateBoolean(hasValue);
  168. }
  169. Var JavascriptSet::EntrySizeGetter(RecyclableObject* function, CallInfo callInfo, ...)
  170. {
  171. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  172. ARGUMENTS(args, callInfo);
  173. ScriptContext* scriptContext = function->GetScriptContext();
  174. JavascriptSet* set = JavascriptOperators::TryFromVar<JavascriptSet>(args[0]);
  175. if (set == nullptr)
  176. {
  177. JavascriptError::ThrowTypeErrorVar(scriptContext, JSERR_NeedObjectOfType, _u("Set.prototype.size"), _u("Set"));
  178. }
  179. int size = set->Size();
  180. return JavascriptNumber::ToVar(size, scriptContext);
  181. }
  182. Var JavascriptSet::EntryEntries(RecyclableObject* function, CallInfo callInfo, ...)
  183. {
  184. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  185. ARGUMENTS(args, callInfo);
  186. ScriptContext* scriptContext = function->GetScriptContext();
  187. JavascriptSet* set = JavascriptOperators::TryFromVar<JavascriptSet>(args[0]);
  188. if (set == nullptr)
  189. {
  190. JavascriptError::ThrowTypeErrorVar(scriptContext, JSERR_NeedObjectOfType, _u("Set.prototype.entries"), _u("Set"));
  191. }
  192. return scriptContext->GetLibrary()->CreateSetIterator(set, JavascriptSetIteratorKind::KeyAndValue);
  193. }
  194. Var JavascriptSet::EntryValues(RecyclableObject* function, CallInfo callInfo, ...)
  195. {
  196. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  197. ARGUMENTS(args, callInfo);
  198. ScriptContext* scriptContext = function->GetScriptContext();
  199. JavascriptSet* set = JavascriptOperators::TryFromVar<JavascriptSet>(args[0]);
  200. if (set == nullptr)
  201. {
  202. JavascriptError::ThrowTypeErrorVar(scriptContext, JSERR_NeedObjectOfType, _u("Set.prototype.values"), _u("Set"));
  203. }
  204. return scriptContext->GetLibrary()->CreateSetIterator(set, JavascriptSetIteratorKind::Value);
  205. }
  206. Var JavascriptSet::EntryGetterSymbolSpecies(RecyclableObject* function, CallInfo callInfo, ...)
  207. {
  208. ARGUMENTS(args, callInfo);
  209. Assert(args.Info.Count > 0);
  210. return args[0];
  211. }
  212. template <typename T>
  213. T*
  214. JavascriptSet::CreateVarSetFromList(uint initialCapacity)
  215. {
  216. T* varSet = RecyclerNew(this->GetRecycler(), T, this->GetRecycler(), initialCapacity);
  217. JavascriptSet::SetDataList::Iterator iter = this->list.GetIterator();
  218. // TODO: we can use a more efficient Iterator, since we know there will be no side effects
  219. while (iter.Next())
  220. {
  221. varSet->Add(iter.Current(), iter.CurrentNode());
  222. }
  223. return varSet;
  224. }
  225. void
  226. JavascriptSet::PromoteToSimpleVarSet()
  227. {
  228. AssertOrFailFast(this->kind == SetKind::IntSet);
  229. SimpleVarDataSet* newSet = this->CreateVarSetFromList<SimpleVarDataSet>(this->u.intSet->Count() + 1);
  230. this->kind = SetKind::SimpleVarSet;
  231. this->u.simpleVarSet = newSet;
  232. }
  233. void
  234. JavascriptSet::PromoteToComplexVarSet()
  235. {
  236. uint setSize = 0;
  237. if (this->kind == SetKind::IntSet)
  238. {
  239. setSize = this->u.intSet->Count();
  240. }
  241. else
  242. {
  243. AssertOrFailFast(this->kind == SetKind::SimpleVarSet);
  244. setSize = this->u.simpleVarSet->Count();
  245. }
  246. ComplexVarDataSet* newSet = this->CreateVarSetFromList<ComplexVarDataSet>(setSize + 1);
  247. this->kind = SetKind::ComplexVarSet;
  248. this->u.complexVarSet = newSet;
  249. }
  250. void
  251. JavascriptSet::AddToEmptySet(Var value)
  252. {
  253. Assert(this->kind == SetKind::EmptySet);
  254. // We cannot store an int with value -1 inside of a bit vector
  255. Var taggedInt = JavascriptConversion::TryCanonicalizeAsTaggedInt<false /* allowNegOne */, false /* allowLossyConversion */>(value);
  256. if (taggedInt)
  257. {
  258. int32 intVal = TaggedInt::ToInt32(taggedInt);
  259. BVSparse<Recycler>* newIntSet = RecyclerNew(this->GetRecycler(), BVSparse<Recycler>, this->GetRecycler());
  260. newIntSet->Set(intVal);
  261. this->list.Append(taggedInt, this->GetRecycler());
  262. this->u.intSet = newIntSet;
  263. this->kind = SetKind::IntSet;
  264. return;
  265. }
  266. Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar<false /* allowLossyConversion */>(value);
  267. if (simpleVar)
  268. {
  269. SimpleVarDataSet* newSimpleSet = RecyclerNew(this->GetRecycler(), SimpleVarDataSet, this->GetRecycler());
  270. SetDataNode* node = this->list.Append(simpleVar, this->GetRecycler());
  271. newSimpleSet->Add(simpleVar, node);
  272. this->u.simpleVarSet = newSimpleSet;
  273. this->kind = SetKind::SimpleVarSet;
  274. return;
  275. }
  276. ComplexVarDataSet* newComplexSet = RecyclerNew(this->GetRecycler(), ComplexVarDataSet, this->GetRecycler());
  277. SetDataNode* node = this->list.Append(value, this->GetRecycler());
  278. newComplexSet->Add(value, node);
  279. this->u.complexVarSet = newComplexSet;
  280. this->kind = SetKind::ComplexVarSet;
  281. }
  282. bool
  283. JavascriptSet::TryAddToIntSet(Var value)
  284. {
  285. Assert(this->kind == SetKind::IntSet);
  286. Var taggedInt = JavascriptConversion::TryCanonicalizeAsTaggedInt<false /* allowNegOne */, false /* allowLossyConversion */>(value);
  287. if (!taggedInt)
  288. {
  289. return false;
  290. }
  291. int32 intVal = TaggedInt::ToInt32(taggedInt);
  292. if (!this->u.intSet->TestAndSet(intVal))
  293. {
  294. this->list.Append(taggedInt, this->GetRecycler());
  295. }
  296. return true;
  297. }
  298. bool
  299. JavascriptSet::TryAddToSimpleVarSet(Var value)
  300. {
  301. Assert(this->kind == SetKind::SimpleVarSet);
  302. Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar<false /* allowLossyConversion */>(value);
  303. if (!simpleVar)
  304. {
  305. return false;
  306. }
  307. if (!this->u.simpleVarSet->ContainsKey(simpleVar))
  308. {
  309. SetDataNode* node = this->list.Append(simpleVar, this->GetRecycler());
  310. this->u.simpleVarSet->Add(simpleVar, node);
  311. }
  312. return true;
  313. }
  314. void
  315. JavascriptSet::AddToComplexVarSet(Var value)
  316. {
  317. Assert(this->kind == SetKind::ComplexVarSet);
  318. if (!this->u.complexVarSet->ContainsKey(value))
  319. {
  320. SetDataNode* node = this->list.Append(value, this->GetRecycler());
  321. this->u.complexVarSet->Add(value, node);
  322. }
  323. }
  324. void
  325. JavascriptSet::Add(Var value)
  326. {
  327. JS_REENTRANCY_LOCK(jsReentLock, this->GetScriptContext()->GetThreadContext());
  328. switch (this->kind)
  329. {
  330. case SetKind::EmptySet:
  331. {
  332. this->AddToEmptySet(value);
  333. return;
  334. }
  335. case SetKind::IntSet:
  336. {
  337. if (this->TryAddToIntSet(value))
  338. {
  339. return;
  340. }
  341. Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar<false /* allowLossyConversion */>(value);
  342. if (simpleVar)
  343. {
  344. this->PromoteToSimpleVarSet();
  345. this->Add(simpleVar);
  346. return;
  347. }
  348. this->PromoteToComplexVarSet();
  349. this->Add(value);
  350. return;
  351. }
  352. case SetKind::SimpleVarSet:
  353. if (this->TryAddToSimpleVarSet(value))
  354. {
  355. return;
  356. }
  357. this->PromoteToComplexVarSet();
  358. this->Add(value);
  359. return;
  360. case SetKind::ComplexVarSet:
  361. this->AddToComplexVarSet(value);
  362. return;
  363. default:
  364. Assume(UNREACHED);
  365. }
  366. }
  367. void JavascriptSet::Clear()
  368. {
  369. JS_REENTRANCY_LOCK(jsReentLock, this->GetScriptContext()->GetThreadContext());
  370. this->list.Clear();
  371. switch (this->kind)
  372. {
  373. case SetKind::EmptySet:
  374. return;
  375. case SetKind::IntSet:
  376. this->u.intSet->ClearAll();
  377. return;
  378. case SetKind::SimpleVarSet:
  379. this->u.simpleVarSet->Clear();
  380. return;
  381. case SetKind::ComplexVarSet:
  382. this->u.complexVarSet->Clear();
  383. return;
  384. default:
  385. Assume(UNREACHED);
  386. }
  387. }
  388. bool
  389. JavascriptSet::IsInIntSet(Var value)
  390. {
  391. Assert(this->kind == SetKind::IntSet);
  392. Var taggedInt = JavascriptConversion::TryCanonicalizeAsTaggedInt<false /* allowNegOne */, true /* allowLossyConversion */>(value);
  393. if (!taggedInt)
  394. {
  395. return false;
  396. }
  397. int32 intVal = TaggedInt::ToInt32(taggedInt);
  398. return this->u.intSet->Test(intVal);
  399. }
  400. template <bool isComplex>
  401. bool
  402. JavascriptSet::DeleteFromVarSet(Var value)
  403. {
  404. Assert(this->kind == (isComplex ? SetKind::ComplexVarSet : SetKind::SimpleVarSet));
  405. SetDataNode * node = nullptr;
  406. if (isComplex
  407. ? !this->u.complexVarSet->TryGetValueAndRemove(value, &node)
  408. : !this->u.simpleVarSet->TryGetValueAndRemove(value, &node))
  409. {
  410. return false;
  411. }
  412. this->list.Remove(node);
  413. return true;
  414. }
  415. bool
  416. JavascriptSet::DeleteFromSimpleVarSet(Var value)
  417. {
  418. Assert(this->kind == SetKind::SimpleVarSet);
  419. Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar<true /* allowLossyConversion */>(value);
  420. if (!simpleVar)
  421. {
  422. return false;
  423. }
  424. return this->DeleteFromVarSet<false>(simpleVar);
  425. }
  426. bool JavascriptSet::Delete(Var value)
  427. {
  428. JS_REENTRANCY_LOCK(jsReentLock, this->GetScriptContext()->GetThreadContext());
  429. switch (this->kind)
  430. {
  431. case SetKind::EmptySet:
  432. return false;
  433. case SetKind::IntSet:
  434. if (!IsInIntSet(value))
  435. {
  436. return false;
  437. }
  438. // We don't have the list node pointer readily available, so deletion from int sets would require walking the list
  439. // Because of this, let's just promote to a var set
  440. //
  441. // If this promotion becomes an issue, we can consider options to improve this, e.g. deferring until an iterator is requested
  442. this->PromoteToSimpleVarSet();
  443. return this->Delete(value);
  444. case SetKind::SimpleVarSet:
  445. return this->DeleteFromSimpleVarSet(value);
  446. case SetKind::ComplexVarSet:
  447. return this->DeleteFromVarSet<true /* isComplex */>(value);
  448. default:
  449. Assume(UNREACHED);
  450. return false;
  451. }
  452. }
  453. bool JavascriptSet::Has(Var value)
  454. {
  455. JS_REENTRANCY_LOCK(jsReentLock, this->GetScriptContext()->GetThreadContext());
  456. switch (this->kind)
  457. {
  458. case SetKind::EmptySet:
  459. return false;
  460. case SetKind::IntSet:
  461. {
  462. Var taggedInt = JavascriptConversion::TryCanonicalizeAsTaggedInt<false /* allowNegOne */, true /* allowLossyConversion */ >(value);
  463. if (!taggedInt)
  464. {
  465. return false;
  466. }
  467. int32 intVal = TaggedInt::ToInt32(taggedInt);
  468. return this->u.intSet->Test(intVal);
  469. }
  470. case SetKind::SimpleVarSet:
  471. {
  472. // First check if the value is in the set
  473. if (this->u.simpleVarSet->ContainsKey(value))
  474. {
  475. return true;
  476. }
  477. // If the value isn't in the set, check if the canonical value is
  478. Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar<true /* allowLossyConversion */>(value);
  479. // If the simple value is the same as the original value, we know it isn't in the set
  480. if (!simpleVar || simpleVar == value)
  481. {
  482. return false;
  483. }
  484. return this->u.simpleVarSet->ContainsKey(simpleVar);
  485. }
  486. case SetKind::ComplexVarSet:
  487. return this->u.complexVarSet->ContainsKey(value);
  488. default:
  489. Assume(UNREACHED);
  490. return false;
  491. }
  492. }
  493. int JavascriptSet::Size()
  494. {
  495. JS_REENTRANCY_LOCK(jsReentLock, this->GetScriptContext()->GetThreadContext());
  496. switch (this->kind)
  497. {
  498. case SetKind::EmptySet:
  499. return 0;
  500. case SetKind::IntSet:
  501. return this->u.intSet->Count();
  502. case SetKind::SimpleVarSet:
  503. return this->u.simpleVarSet->Count();
  504. case SetKind::ComplexVarSet:
  505. return this->u.complexVarSet->Count();
  506. default:
  507. Assume(UNREACHED);
  508. return 0;
  509. }
  510. }
  511. BOOL JavascriptSet::GetDiagTypeString(StringBuilder<ArenaAllocator>* stringBuilder, ScriptContext* requestContext)
  512. {
  513. stringBuilder->AppendCppLiteral(_u("Set"));
  514. return TRUE;
  515. }
  516. #if ENABLE_TTD
  517. void JavascriptSet::MarkVisitKindSpecificPtrs(TTD::SnapshotExtractor* extractor)
  518. {
  519. auto iterator = this->GetIterator();
  520. while(iterator.Next())
  521. {
  522. extractor->MarkVisitVar(iterator.Current());
  523. }
  524. }
  525. TTD::NSSnapObjects::SnapObjectType JavascriptSet::GetSnapTag_TTD() const
  526. {
  527. return TTD::NSSnapObjects::SnapObjectType::SnapSetObject;
  528. }
  529. void JavascriptSet::ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc)
  530. {
  531. TTD::NSSnapObjects::SnapSetInfo* ssi = alloc.SlabAllocateStruct<TTD::NSSnapObjects::SnapSetInfo>();
  532. ssi->SetSize = 0;
  533. if(this->Size() == 0)
  534. {
  535. ssi->SetValueArray = nullptr;
  536. }
  537. else
  538. {
  539. ssi->SetValueArray = alloc.SlabAllocateArray<TTD::TTDVar>(this->Size());
  540. auto iter = this->GetIterator();
  541. while(iter.Next())
  542. {
  543. ssi->SetValueArray[ssi->SetSize] = iter.Current();
  544. ssi->SetSize++;
  545. }
  546. }
  547. TTD::NSSnapObjects::StdExtractSetKindSpecificInfo<TTD::NSSnapObjects::SnapSetInfo*, TTD::NSSnapObjects::SnapObjectType::SnapSetObject>(objData, ssi);
  548. }
  549. JavascriptSet* JavascriptSet::CreateForSnapshotRestore(ScriptContext* ctx)
  550. {
  551. JavascriptSet* res = ctx->GetLibrary()->CreateSet();
  552. return res;
  553. }
  554. #endif
  555. }