blob: 6bd164d1543c09549fc3ec3ebe95252a4700c9d4 [file] [log] [blame]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "RuntimeLibraryPch.h"
namespace Js
{
JavascriptArrayIterator::JavascriptArrayIterator(DynamicType* type, Var iterable, JavascriptArrayIteratorKind kind):
DynamicObject(type),
m_iterableObject(iterable),
m_nextIndex(0),
m_kind(kind)
{
Assert(type->GetTypeId() == TypeIds_ArrayIterator);
if (m_iterableObject == this->GetLibrary()->GetUndefined())
{
m_iterableObject = nullptr;
}
}
bool JavascriptArrayIterator::Is(Var aValue)
{
TypeId typeId = JavascriptOperators::GetTypeId(aValue);
return typeId == TypeIds_ArrayIterator;
}
JavascriptArrayIterator* JavascriptArrayIterator::FromVar(Var aValue)
{
AssertOrFailFastMsg(Is(aValue), "Ensure var is actually a 'JavascriptArrayIterator'");
return static_cast<JavascriptArrayIterator *>(aValue);
}
JavascriptArrayIterator* JavascriptArrayIterator::UnsafeFromVar(Var aValue)
{
AssertMsg(Is(aValue), "Ensure var is actually a 'JavascriptArrayIterator'");
return static_cast<JavascriptArrayIterator *>(aValue);
}
Var JavascriptArrayIterator::EntryNext(RecyclableObject* function, CallInfo callInfo, ...)
{
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
ARGUMENTS(args, callInfo);
ScriptContext* scriptContext = function->GetScriptContext();
#ifdef ENABLE_JS_BUILTINS
Assert(!scriptContext->IsJsBuiltInEnabled());
#endif
JavascriptLibrary* library = scriptContext->GetLibrary();
Assert(!(callInfo.Flags & CallFlags_New));
Var thisObj = args[0];
if (!JavascriptArrayIterator::Is(thisObj))
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_This_NeedArrayIterator, _u("Array Iterator.prototype.next"));
}
JavascriptArrayIterator* iterator = JavascriptArrayIterator::FromVar(thisObj);
Var iterable = iterator->m_iterableObject;
if (iterable == nullptr)
{
return library->CreateIteratorResultObjectUndefinedTrue();
}
int64 length;
JavascriptArray* pArr = nullptr;
TypedArrayBase *typedArrayBase = nullptr;
if (JavascriptArray::Is(iterable) && !JavascriptArray::FromVar(iterable)->IsCrossSiteObject())
{
#if ENABLE_COPYONACCESS_ARRAY
Assert(!JavascriptCopyOnAccessNativeIntArray::Is(iterable));
#endif
pArr = JavascriptArray::FromAnyArray(iterable);
length = pArr->GetLength();
}
else if (TypedArrayBase::Is(iterable))
{
typedArrayBase = TypedArrayBase::UnsafeFromVar(iterable);
if (typedArrayBase->IsDetachedBuffer())
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_DetachedTypedArray);
}
length = typedArrayBase->GetLength();
}
else
{
length = JavascriptConversion::ToLength(JavascriptOperators::OP_GetLength(iterable, scriptContext), scriptContext);
}
int64 index = iterator->m_nextIndex;
if (index >= length)
{
// Nulling out the m_iterableObject field is important so that the iterator
// does not keep the iterable object alive after iteration is completed.
iterator->m_iterableObject = nullptr;
return library->CreateIteratorResultObjectUndefinedTrue();
}
iterator->m_nextIndex += 1;
if (iterator->m_kind == JavascriptArrayIteratorKind::Key)
{
return library->CreateIteratorResultObjectValueFalse(JavascriptNumber::ToVar(index, scriptContext));
}
Var value;
if (pArr != nullptr)
{
Assert(index <= UINT_MAX);
value = pArr->DirectGetItem((uint32)index);
}
else if (typedArrayBase != nullptr)
{
Assert(index <= UINT_MAX);
value = typedArrayBase->DirectGetItem((uint32)index);
}
else
{
value = JavascriptOperators::OP_GetElementI(iterable, JavascriptNumber::ToVar(index, scriptContext), scriptContext);
}
if (iterator->m_kind == JavascriptArrayIteratorKind::Value)
{
return library->CreateIteratorResultObjectValueFalse(value);
}
Assert(iterator->m_kind == JavascriptArrayIteratorKind::KeyAndValue);
JavascriptArray* keyValueTuple = library->CreateArray(2);
keyValueTuple->SetItem(0, JavascriptNumber::ToVar(index, scriptContext), PropertyOperation_None);
keyValueTuple->SetItem(1, value, PropertyOperation_None);
return library->CreateIteratorResultObjectValueFalse(keyValueTuple);
}
} //namespace Js