JavascriptArrayIterator.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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. JavascriptArrayIterator::JavascriptArrayIterator(DynamicType* type, Var iterable, JavascriptArrayIteratorKind kind):
  9. DynamicObject(type),
  10. m_iterableObject(iterable),
  11. m_nextIndex(0),
  12. m_kind(kind)
  13. {
  14. Assert(type->GetTypeId() == TypeIds_ArrayIterator);
  15. if (m_iterableObject == this->GetLibrary()->GetUndefined())
  16. {
  17. m_iterableObject = nullptr;
  18. }
  19. }
  20. bool JavascriptArrayIterator::Is(Var aValue)
  21. {
  22. TypeId typeId = JavascriptOperators::GetTypeId(aValue);
  23. return typeId == TypeIds_ArrayIterator;
  24. }
  25. JavascriptArrayIterator* JavascriptArrayIterator::FromVar(Var aValue)
  26. {
  27. AssertMsg(Is(aValue), "Ensure var is actually a 'JavascriptArrayIterator'");
  28. return static_cast<JavascriptArrayIterator *>(RecyclableObject::FromVar(aValue));
  29. }
  30. Var JavascriptArrayIterator::EntryNext(RecyclableObject* function, CallInfo callInfo, ...)
  31. {
  32. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  33. ARGUMENTS(args, callInfo);
  34. ScriptContext* scriptContext = function->GetScriptContext();
  35. JavascriptLibrary* library = scriptContext->GetLibrary();
  36. Assert(!(callInfo.Flags & CallFlags_New));
  37. Var thisObj = args[0];
  38. if (!JavascriptArrayIterator::Is(thisObj))
  39. {
  40. JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedArrayIterator, _u("Array Iterator.prototype.next"));
  41. }
  42. JavascriptArrayIterator* iterator = JavascriptArrayIterator::FromVar(thisObj);
  43. Var iterable = iterator->m_iterableObject;
  44. if (iterable == nullptr)
  45. {
  46. return library->CreateIteratorResultObjectUndefinedTrue();
  47. }
  48. int64 length;
  49. JavascriptArray* pArr = nullptr;
  50. TypedArrayBase *typedArrayBase = nullptr;
  51. if (JavascriptArray::Is(iterable) && !JavascriptArray::FromVar(iterable)->IsCrossSiteObject())
  52. {
  53. #if ENABLE_COPYONACCESS_ARRAY
  54. Assert(!JavascriptCopyOnAccessNativeIntArray::Is(iterable));
  55. #endif
  56. pArr = JavascriptArray::FromAnyArray(iterable);
  57. length = pArr->GetLength();
  58. }
  59. else if (TypedArrayBase::Is(iterable))
  60. {
  61. typedArrayBase = TypedArrayBase::FromVar(iterable);
  62. if (typedArrayBase->IsDetachedBuffer())
  63. {
  64. JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray);
  65. }
  66. length = typedArrayBase->GetLength();
  67. }
  68. else
  69. {
  70. length = JavascriptConversion::ToLength(JavascriptOperators::OP_GetLength(iterable, scriptContext), scriptContext);
  71. }
  72. int64 index = iterator->m_nextIndex;
  73. if (index >= length)
  74. {
  75. // Nulling out the m_iterableObject field is important so that the iterator
  76. // does not keep the iterable object alive after iteration is completed.
  77. iterator->m_iterableObject = nullptr;
  78. return library->CreateIteratorResultObjectUndefinedTrue();
  79. }
  80. iterator->m_nextIndex += 1;
  81. if (iterator->m_kind == JavascriptArrayIteratorKind::Key)
  82. {
  83. return library->CreateIteratorResultObjectValueFalse(JavascriptNumber::ToVar(index, scriptContext));
  84. }
  85. Var value;
  86. if (pArr != nullptr)
  87. {
  88. Assert(index <= UINT_MAX);
  89. value = pArr->DirectGetItem((uint32)index);
  90. }
  91. else if (typedArrayBase != nullptr)
  92. {
  93. Assert(index <= UINT_MAX);
  94. value = typedArrayBase->DirectGetItem((uint32)index);
  95. }
  96. else
  97. {
  98. value = JavascriptOperators::OP_GetElementI(iterable, JavascriptNumber::ToVar(index, scriptContext), scriptContext);
  99. }
  100. if (iterator->m_kind == JavascriptArrayIteratorKind::Value)
  101. {
  102. return library->CreateIteratorResultObjectValueFalse(value);
  103. }
  104. Assert(iterator->m_kind == JavascriptArrayIteratorKind::KeyAndValue);
  105. JavascriptArray* keyValueTuple = library->CreateArray(2);
  106. keyValueTuple->SetItem(0, JavascriptNumber::ToVar(index, scriptContext), PropertyOperation_None);
  107. keyValueTuple->SetItem(1, value, PropertyOperation_None);
  108. return library->CreateIteratorResultObjectValueFalse(keyValueTuple);
  109. }
  110. } //namespace Js