mirror of
https://github.com/Samsung/escargot.git
synced 2026-06-22 10:01:50 +00:00
2267 lines
112 KiB
C++
2267 lines
112 KiB
C++
/*
|
||
* Copyright (c) 2016-present Samsung Electronics Co., Ltd
|
||
*
|
||
* This library is free software; you can redistribute it and/or
|
||
* modify it under the terms of the GNU Lesser General Public
|
||
* License as published by the Free Software Foundation; either
|
||
* version 2.1 of the License, or (at your option) any later version.
|
||
*
|
||
* This library is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
* Lesser General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU Lesser General Public
|
||
* License along with this library; if not, write to the Free Software
|
||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||
* USA
|
||
*/
|
||
|
||
#include "Escargot.h"
|
||
#include "runtime/GlobalObject.h"
|
||
#include "runtime/Context.h"
|
||
#include "runtime/VMInstance.h"
|
||
#include "runtime/ArrayObject.h"
|
||
#include "runtime/IteratorObject.h"
|
||
#include "runtime/ToStringRecursionPreventer.h"
|
||
#include "runtime/ErrorObject.h"
|
||
#include "runtime/NativeFunctionObject.h"
|
||
#include "interpreter/ByteCodeInterpreter.h"
|
||
|
||
namespace Escargot {
|
||
|
||
Value builtinArrayConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
bool interpretArgumentsAsElements = false;
|
||
uint64_t size = 0;
|
||
if (argc > 1) {
|
||
size = argc;
|
||
interpretArgumentsAsElements = true;
|
||
} else if (argc == 1) {
|
||
Value& val = argv[0];
|
||
if (val.isNumber()) {
|
||
if (val.equalsTo(state, Value(val.toUint32(state)))) {
|
||
size = val.toNumber(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
} else {
|
||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, ErrorObject::Messages::GlobalObject_InvalidArrayLength);
|
||
}
|
||
} else {
|
||
size = 1;
|
||
interpretArgumentsAsElements = true;
|
||
}
|
||
}
|
||
|
||
// If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget.
|
||
if (!newTarget.hasValue()) {
|
||
newTarget = state.resolveCallee();
|
||
}
|
||
|
||
// Let proto be ? GetPrototypeFromConstructor(newTarget, "%ArrayPrototype%").
|
||
// Let array be ! ArrayCreate(0, proto).
|
||
Object* proto = Object::getPrototypeFromConstructor(state, newTarget.value(), [](ExecutionState& state, Context* constructorRealm) -> Object* {
|
||
return constructorRealm->globalObject()->arrayPrototype();
|
||
});
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
ArrayObject* array = new ArrayObject(state, proto, size);
|
||
|
||
if (interpretArgumentsAsElements) {
|
||
if (argc > 1 || !argv[0].isNumber()) {
|
||
if (array->isFastModeArray()) {
|
||
for (size_t idx = 0; idx < argc; idx++) {
|
||
array->m_fastModeData[idx] = argv[idx];
|
||
}
|
||
} else {
|
||
Value val = argv[0];
|
||
for (size_t idx = 0; idx < argc; idx++) {
|
||
array->defineOwnProperty(state, ObjectPropertyName(state, idx), ObjectPropertyDescriptor(argv[idx], ObjectPropertyDescriptor::AllPresent));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return array;
|
||
}
|
||
|
||
#define CHECK_ARRAY_LENGTH(COND) \
|
||
if (COND) { \
|
||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, ErrorObject::Messages::GlobalObject_InvalidArrayLength); \
|
||
}
|
||
|
||
static Object* arraySpeciesCreate(ExecutionState& state, Object* originalArray, const int64_t length)
|
||
{
|
||
ASSERT(originalArray != nullptr);
|
||
// Assert: length is an integer Number >= 0.
|
||
ASSERT(length >= 0);
|
||
|
||
// Let C be undefined.
|
||
Value C;
|
||
// Let isArray be IsArray(originalArray).
|
||
// If isArray is true, then
|
||
if (originalArray->isArray(state)) {
|
||
// Let C be Get(originalArray, "constructor").
|
||
C = originalArray->get(state, ObjectPropertyName(state.context()->staticStrings().constructor)).value(state, originalArray);
|
||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||
|
||
// If IsConstructor(C) is true, then
|
||
if (C.isConstructor()) {
|
||
// Let thisRealm be the running execution context’s Realm.
|
||
Context* thisRealm = state.context();
|
||
// Let realmC be GetFunctionRealm(C).
|
||
Context* realmC = C.asObject()->getFunctionRealm(state);
|
||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||
|
||
// ReturnIfAbrupt(realmC).
|
||
// If thisRealm and realmC are not the same Realm Record, then
|
||
// If SameValue(C, realmC.[[intrinsics]].[[%Array%]]) is true, let C be undefined.
|
||
if (thisRealm != realmC) {
|
||
if (C.asPointerValue() == realmC->globalObject()->array()) {
|
||
C = Value();
|
||
}
|
||
}
|
||
}
|
||
// If Type(C) is Object, then
|
||
if (C.isObject()) {
|
||
// a. Set C be Get(C, @@species).
|
||
C = C.asObject()->get(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().species)).value(state, C);
|
||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||
if (C.isNull()) { // b. If C is null, set C to undefined.
|
||
C = Value();
|
||
}
|
||
}
|
||
}
|
||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||
|
||
// If C is undefined, return ArrayCreate(length).
|
||
if (C.isUndefined()) {
|
||
return new ArrayObject(state, static_cast<uint64_t>(length));
|
||
}
|
||
// If IsConstructor(C) is false, throw a TypeError exception.
|
||
if (!C.isConstructor()) {
|
||
THROW_BUILTIN_ERROR_RETURN_NULL(state, ErrorCode::TypeError, state.context()->staticStrings().Array.string(), false, String::emptyString, ErrorObject::Messages::GlobalObject_ThisNotConstructor);
|
||
}
|
||
// Return Construct(C, <<length>>).
|
||
Value argv[1] = { Value(length) };
|
||
Value result = Object::construct(state, C, 1, argv);
|
||
RETURN_NULL_IF_PENDING_EXCEPTION
|
||
return result.toObject(state);
|
||
}
|
||
|
||
// http://ecma-international.org/ecma-262/10.0/#sec-flattenintoarray
|
||
// FlattenIntoArray(target, source, sourceLen, start, depth [ , mapperFunction, thisArg ])
|
||
static int64_t flattenIntoArray(ExecutionState& state, Value target, Value source, int64_t sourceLen, int64_t start, double depth, Value mappedValue = Value(Value::EmptyValue), Value thisArg = Value(Value::EmptyValue))
|
||
{
|
||
ASSERT(target.isObject());
|
||
ASSERT(source.isObject());
|
||
ASSERT(sourceLen >= 0);
|
||
|
||
int64_t targetIndex = start;
|
||
int64_t sourceIndex = 0;
|
||
|
||
while (sourceIndex < sourceLen) {
|
||
String* p = Value(sourceIndex).toString(state);
|
||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||
ObjectHasPropertyResult exists = source.asObject()->hasIndexedProperty(state, p);
|
||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||
if (exists) {
|
||
Value element = exists.value(state, ObjectPropertyName(state, p), source);
|
||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||
if (!mappedValue.isEmpty()) {
|
||
Value args[] = { element, Value(sourceIndex), source };
|
||
ASSERT(!thisArg.isEmpty() && depth == 1);
|
||
element = Object::call(state, mappedValue, thisArg, 3, args);
|
||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||
}
|
||
if (depth > 0 && element.isObject() && element.asObject()->isArray(state)) {
|
||
int64_t elementLen = element.asObject()->length(state);
|
||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||
targetIndex = flattenIntoArray(state, target, element, elementLen, targetIndex, depth - 1);
|
||
|
||
} else {
|
||
if (targetIndex >= std::numeric_limits<int64_t>::max()) {
|
||
THROW_BUILTIN_ERROR_RETURN_ZERO(state, ErrorCode::TypeError, "invalid index");
|
||
}
|
||
target.asObject()->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, targetIndex),
|
||
ObjectPropertyDescriptor(element, ObjectPropertyDescriptor::AllPresent));
|
||
targetIndex++;
|
||
}
|
||
RETURN_ZERO_IF_PENDING_EXCEPTION
|
||
}
|
||
sourceIndex++;
|
||
}
|
||
return targetIndex;
|
||
}
|
||
|
||
static Value builtinArrayIsArray(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
ASSERT(argv != nullptr);
|
||
|
||
return Value(argv[0].isObject() && argv[0].asObject()->isArray(state));
|
||
}
|
||
|
||
// Array.from ( items [ , mapfn [ , thisArg ] ] )#
|
||
static Value builtinArrayFrom(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
Value items = argv[0];
|
||
Value mapfn;
|
||
if (argc > 1) {
|
||
mapfn = argv[1];
|
||
}
|
||
Value thisArg;
|
||
if (argc > 2) {
|
||
thisArg = argv[2];
|
||
}
|
||
// Let C be the this value.
|
||
Value C = thisValue;
|
||
Value T;
|
||
// If mapfn is undefined, let mapping be false.
|
||
bool mapping = false;
|
||
if (!mapfn.isUndefined()) {
|
||
// If IsCallable(mapfn) is false, throw a TypeError exception.
|
||
if (!mapfn.isCallable()) {
|
||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, "argument map function should be undefined or function");
|
||
}
|
||
// If thisArg was supplied, let T be thisArg; else let T be undefined.
|
||
T = thisArg;
|
||
// Let mapping be true.
|
||
mapping = true;
|
||
}
|
||
|
||
// Let usingIterator be ? GetMethod(items, @@iterator).
|
||
Value usingIterator = Object::getMethod(state, items, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().iterator));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// If usingIterator is not undefined, then
|
||
if (!usingIterator.isUndefined()) {
|
||
Object* A;
|
||
// If IsConstructor(C) is true, then
|
||
if (C.isConstructor()) {
|
||
// Let A be ? Construct(C).
|
||
Value cons = Object::construct(state, C, 0, nullptr);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
A = cons.toObject(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
} else {
|
||
// Let A be ArrayCreate(0).
|
||
A = new ArrayObject(state);
|
||
}
|
||
// Let iteratorRecord be ? GetIterator(items, sync, usingIterator).
|
||
IteratorRecord* iteratorRecord = IteratorObject::getIterator(state, items, true, usingIterator);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// Let k be 0.
|
||
int64_t k = 0;
|
||
// Repeat
|
||
while (true) {
|
||
// If k ≥ 2^53-1, then
|
||
if (k >= ((1LL << 53LL) - 1LL)) {
|
||
// Let error be ThrowCompletion(a newly created TypeError object).
|
||
// Return ? IteratorClose(iteratorRecord, error).
|
||
Value throwCompletion = ErrorObject::createError(state, ErrorCode::TypeError, new ASCIIString("Got invalid index"));
|
||
return IteratorObject::iteratorClose(state, iteratorRecord, throwCompletion, true);
|
||
}
|
||
// Let Pk be ! ToString(k).
|
||
ObjectPropertyName pk(state, k);
|
||
// Let next be ? IteratorStep(iteratorRecord).
|
||
Optional<Object*> next = IteratorObject::iteratorStep(state, iteratorRecord);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// If next is false, then
|
||
if (!next.hasValue()) {
|
||
// Perform ? Set(A, "length", k, true).
|
||
A->setThrowsException(state, ObjectPropertyName(state, state.context()->staticStrings().length), Value(k), A);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Return A.
|
||
return A;
|
||
}
|
||
// Let nextValue be ? IteratorValue(next).
|
||
Value nextValue = IteratorObject::iteratorValue(state, next.value());
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
Value mappedValue;
|
||
// If mapping is true, then
|
||
if (mapping) {
|
||
// Let mappedValue be Call(mapfn, T, « nextValue, k »).
|
||
// If mappedValue is an abrupt completion, return ? IteratorClose(iteratorRecord, mappedValue).
|
||
// Set mappedValue to mappedValue.[[Value]].
|
||
Value argv[] = { nextValue, Value(k) };
|
||
mappedValue = Object::call(state, mapfn, T, 2, argv);
|
||
if (UNLIKELY(state.hasPendingException())) {
|
||
ASSERT(mappedValue.isException());
|
||
Value exceptionValue = state.detachPendingException();
|
||
return IteratorObject::iteratorClose(state, iteratorRecord, exceptionValue, true);
|
||
}
|
||
} else {
|
||
mappedValue = nextValue;
|
||
}
|
||
|
||
// Let defineStatus be CreateDataPropertyOrThrow(A, Pk, mappedValue).
|
||
A->defineOwnPropertyThrowsException(state, pk, ObjectPropertyDescriptor(mappedValue, ObjectPropertyDescriptor::AllPresent));
|
||
if (UNLIKELY(state.hasPendingException())) {
|
||
// If defineStatus is an abrupt completion, return ? IteratorClose(iteratorRecord, defineStatus).
|
||
Value exceptionValue = state.detachPendingException();
|
||
return IteratorObject::iteratorClose(state, iteratorRecord, exceptionValue, true);
|
||
}
|
||
// Increase k by 1.
|
||
k++;
|
||
}
|
||
}
|
||
// NOTE: items is not an Iterable so assume it is an array-like object.
|
||
// Let arrayLike be ! ToObject(items).
|
||
Object* arrayLike = items.toObject(state);
|
||
// Let len be ? ToLength(? Get(arrayLike, "length")).
|
||
uint64_t len = arrayLike->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// If IsConstructor(C) is true, then
|
||
Object* A;
|
||
if (C.isConstructor()) {
|
||
// Let A be ? Construct(C, « len »).
|
||
Value vlen(len);
|
||
Value cons = Object::construct(state, C, 1, &vlen);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
A = cons.toObject(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
} else {
|
||
// Else,
|
||
// Let A be ? ArrayCreate(len).
|
||
A = new ArrayObject(state, len);
|
||
}
|
||
|
||
// Let k be 0.
|
||
uint64_t k = 0;
|
||
// Repeat, while k < len
|
||
while (k < len) {
|
||
// Let Pk be ! ToString(k).
|
||
ObjectPropertyName Pk(state, k);
|
||
// Let kValue be ? Get(arrayLike, Pk).
|
||
Value kValue = arrayLike->getIndexedProperty(state, Value(k)).value(state, arrayLike);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// If mapping is true, then
|
||
Value mappedValue;
|
||
if (mapping) {
|
||
// Let mappedValue be ? Call(mapfn, T, « kValue, k »).
|
||
Value argv[] = { kValue, Value(k) };
|
||
mappedValue = Object::call(state, mapfn, T, 2, argv);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
} else {
|
||
// Else, let mappedValue be kValue.
|
||
mappedValue = kValue;
|
||
}
|
||
// Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
|
||
A->defineOwnPropertyThrowsException(state, Pk, ObjectPropertyDescriptor(mappedValue, ObjectPropertyDescriptor::AllPresent));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Increase k by 1.
|
||
k++;
|
||
}
|
||
// Perform ? Set(A, "length", len, true).
|
||
A->setThrowsException(state, ObjectPropertyName(state, state.context()->staticStrings().length), Value(len), A);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Return A.
|
||
return A;
|
||
}
|
||
|
||
// Array.of ( ...items )
|
||
static Value builtinArrayOf(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
size_t len = argc;
|
||
Value C = thisValue;
|
||
|
||
Object* A;
|
||
if (C.isConstructor()) {
|
||
Value arg[1] = { Value(len) };
|
||
Value cons = Object::construct(state, C, 1, arg);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
A = cons.toObject(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
} else {
|
||
A = new ArrayObject(state, static_cast<uint64_t>(len));
|
||
}
|
||
|
||
size_t k = 0;
|
||
while (k < len) {
|
||
Value kValue = argv[k];
|
||
ObjectPropertyName Pk(state, k);
|
||
A->defineOwnPropertyThrowsException(state, Pk, ObjectPropertyDescriptor(kValue, ObjectPropertyDescriptor::AllPresent));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
k++;
|
||
}
|
||
A->setThrowsException(state, ObjectPropertyName(state, state.context()->staticStrings().length), Value(len), A);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
return A;
|
||
}
|
||
|
||
static Value builtinArrayJoin(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(thisBinded, Array, join);
|
||
int64_t len = thisBinded->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
Value separator = argv[0];
|
||
String* sep;
|
||
|
||
if (separator.isUndefined()) {
|
||
sep = state.context()->staticStrings().asciiTable[(size_t)','].string();
|
||
} else {
|
||
sep = separator.toString(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
}
|
||
|
||
if (!state.context()->toStringRecursionPreventer()->canInvokeToString(thisBinded)) {
|
||
return String::emptyString;
|
||
}
|
||
ToStringRecursionPreventerItemAutoHolder holder(state, thisBinded);
|
||
|
||
StringBuilder builder;
|
||
int64_t prevIndex = 0;
|
||
int64_t curIndex = 0;
|
||
while (curIndex < len) {
|
||
if (curIndex != 0 && sep->length() > 0) {
|
||
if (static_cast<double>(builder.contentLength()) > static_cast<double>(STRING_MAXIMUM_LENGTH - (curIndex - prevIndex - 1) * (int64_t)sep->length())) {
|
||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, ErrorObject::Messages::String_InvalidStringLength);
|
||
}
|
||
while (curIndex - prevIndex > 1) {
|
||
builder.appendString(sep);
|
||
prevIndex++;
|
||
}
|
||
builder.appendString(sep);
|
||
}
|
||
Value elem = thisBinded->getIndexedProperty(state, Value(curIndex)).value(state, thisBinded);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
if (!elem.isUndefinedOrNull()) {
|
||
String* str = elem.toString(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
builder.appendString(str);
|
||
}
|
||
prevIndex = curIndex;
|
||
if (elem.isUndefined()) {
|
||
struct Data {
|
||
bool exists;
|
||
int64_t cur;
|
||
int64_t ret;
|
||
} data;
|
||
data.exists = false;
|
||
data.cur = curIndex;
|
||
data.ret = len;
|
||
|
||
Value ptr = thisBinded;
|
||
while (ptr.isObject()) {
|
||
if (!ptr.asObject()->isOrdinary()) {
|
||
curIndex++;
|
||
break;
|
||
}
|
||
ptr.asObject()->enumeration(state, [](ExecutionState& state, Object* self, const ObjectPropertyName& name, const ObjectStructurePropertyDescriptor& desc, void* data) {
|
||
int64_t index;
|
||
Data* e = (Data*)data;
|
||
int64_t* ret = &e->ret;
|
||
Value key = name.toPlainValue();
|
||
index = key.toNumber(state);
|
||
if ((uint64_t)index != Value::InvalidIndexValue) {
|
||
if (self->get(state, name).value(state, self).isUndefined()) {
|
||
return true;
|
||
}
|
||
if (index > e->cur && e->ret > index) {
|
||
e->ret = std::min(index, e->ret);
|
||
}
|
||
}
|
||
return true;
|
||
},
|
||
&data);
|
||
ptr = ptr.asObject()->getPrototype(state);
|
||
}
|
||
curIndex = data.ret;
|
||
} else {
|
||
curIndex++;
|
||
}
|
||
}
|
||
if (sep->length() > 0) {
|
||
if (static_cast<double>(builder.contentLength()) > static_cast<double>(STRING_MAXIMUM_LENGTH - (curIndex - prevIndex - 1) * (int64_t)sep->length())) {
|
||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::RangeError, ErrorObject::Messages::String_InvalidStringLength);
|
||
}
|
||
while (curIndex - prevIndex > 1) {
|
||
builder.appendString(sep);
|
||
prevIndex++;
|
||
}
|
||
}
|
||
return builder.finalize(&state);
|
||
}
|
||
|
||
static Value builtinArrayReverse(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Array, reverse);
|
||
int64_t len = O->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
int64_t middle = std::floor(len / 2);
|
||
int64_t lower = 0;
|
||
while (middle > lower) {
|
||
int64_t upper = len - lower - 1;
|
||
ObjectPropertyName upperP = ObjectPropertyName(state, upper);
|
||
ObjectPropertyName lowerP = ObjectPropertyName(state, lower);
|
||
|
||
auto lowerExists = O->hasIndexedProperty(state, Value(lower));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
Value lowerValue;
|
||
if (lowerExists) {
|
||
lowerValue = lowerExists.value(state, lowerP, O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
}
|
||
auto upperExists = O->hasIndexedProperty(state, Value(upper));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
Value upperValue;
|
||
if (upperExists) {
|
||
upperValue = upperExists.value(state, upperP, O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
}
|
||
if (lowerExists && upperExists) {
|
||
O->setThrowsException(state, lowerP, upperValue, O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
O->setThrowsException(state, upperP, lowerValue, O);
|
||
} else if (!lowerExists && upperExists) {
|
||
O->setThrowsException(state, lowerP, upperValue, O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
O->deleteOwnPropertyThrowsException(state, upperP);
|
||
} else if (lowerExists && !upperExists) {
|
||
O->deleteOwnPropertyThrowsException(state, lowerP);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
O->setThrowsException(state, upperP, lowerValue, O);
|
||
} else {
|
||
int64_t result;
|
||
Object::nextIndexForward(state, O, lower, middle, result);
|
||
int64_t nextLower = result;
|
||
Object::nextIndexBackward(state, O, upper, middle, result);
|
||
int64_t nextUpper = result;
|
||
int64_t x = middle - nextLower;
|
||
int64_t y = nextUpper - middle;
|
||
int64_t lowerCandidate;
|
||
if (x > y) {
|
||
lowerCandidate = nextLower;
|
||
} else {
|
||
lowerCandidate = len - nextUpper - 1;
|
||
}
|
||
if (lower == lowerCandidate)
|
||
break;
|
||
lower = lowerCandidate;
|
||
continue;
|
||
}
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
lower++;
|
||
}
|
||
|
||
return O;
|
||
}
|
||
|
||
static Value builtinArraySort(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(thisObject, Array, sort);
|
||
Value cmpfn = argv[0];
|
||
if (!cmpfn.isUndefined() && !cmpfn.isCallable()) {
|
||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Array.string(), true, state.context()->staticStrings().sort.string(), ErrorObject::Messages::GlobalObject_FirstArgumentNotCallable);
|
||
}
|
||
bool defaultSort = (argc == 0) || cmpfn.isUndefined();
|
||
|
||
int64_t len = thisObject->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
thisObject->sort(state, len, [defaultSort, &cmpfn, &state](const Value& a, const Value& b) -> bool {
|
||
if (a.isEmpty() && b.isUndefined())
|
||
return false;
|
||
if (a.isUndefined() && b.isEmpty())
|
||
return true;
|
||
if (a.isEmpty() || a.isUndefined())
|
||
return false;
|
||
if (b.isEmpty() || b.isUndefined())
|
||
return true;
|
||
Value arg[2] = { a, b };
|
||
if (defaultSort) {
|
||
String* vala = a.toString(state);
|
||
String* valb = b.toString(state);
|
||
return *vala < *valb;
|
||
} else {
|
||
Value ret = Object::call(state, cmpfn, Value(), 2, arg);
|
||
ASSERT(!state.hasPendingException());
|
||
return (ret.toNumber(state) < 0);
|
||
} });
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
return thisObject;
|
||
}
|
||
|
||
static Value builtinArraySplice(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
// TODO(ES6): the number of actual arguments is used.
|
||
// e.g. var arr = [1, 2, 3, 4, 5];
|
||
// Different: arr.splice(2) vs. arr.splice(2, undefined)
|
||
|
||
// Let O be the result of calling ToObject passing the this value as the argument.
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Array, splice);
|
||
|
||
// Let lenVal be the result of calling the [[Get]] internal method of O with argument "length".
|
||
// Let len be ToLength(Get(O, "length")).
|
||
int64_t len = O->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// Let relativeStart be ToInteger(start).
|
||
double relativeStart = argv[0].toInteger(state);
|
||
|
||
// If relativeStart is negative, let actualStart be max((len + relativeStart),0); else let actualStart be min(relativeStart, len).
|
||
int64_t actualStart = (relativeStart < 0) ? std::max(len + relativeStart, 0.0) : std::min(relativeStart, (double)len);
|
||
|
||
int64_t insertCount;
|
||
int64_t actualDeleteCount;
|
||
|
||
// If the number of actual arguments is 0, then
|
||
if (argc == 0) {
|
||
// Let insertCount be 0.
|
||
insertCount = 0;
|
||
// Let actualDeleteCount be 0.
|
||
actualDeleteCount = 0;
|
||
} else if (argc == 1) {
|
||
// Else if the number of actual arguments is 1, then
|
||
// Let insertCount be 0.
|
||
insertCount = 0;
|
||
// Let actualDeleteCount be len – actualStart.
|
||
actualDeleteCount = len - actualStart;
|
||
} else {
|
||
// Else,
|
||
// Let insertCount be the number of actual arguments minus 2.
|
||
insertCount = argc - 2;
|
||
// Let dc be ToInteger(deleteCount).
|
||
double dc = argv[1].toInteger(state);
|
||
// Let actualDeleteCount be min(max(dc,0), len – actualStart).
|
||
actualDeleteCount = std::min(std::max(dc, 0.0), (double)(len - actualStart));
|
||
}
|
||
// If len+insertCount−actualDeleteCount > 2^53-1, throw a TypeError exception.
|
||
CHECK_ARRAY_LENGTH(len + insertCount - actualDeleteCount > Value::maximumLength());
|
||
// Let A be ArraySpeciesCreate(O, actualDeleteCount).
|
||
Object* A = arraySpeciesCreate(state, O, actualDeleteCount);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// Let k be 0.
|
||
int64_t k = 0;
|
||
|
||
// Repeat, while k < actualDeleteCount
|
||
while (k < actualDeleteCount) {
|
||
// Let from be ToString(actualStart+k).
|
||
// Let fromPresent be the result of calling the [[HasProperty]] internal method of O with argument from.
|
||
// If fromPresent is true, then
|
||
// Let fromValue be the result of calling the [[Get]] internal method of O with argument from.
|
||
ObjectHasPropertyResult fromValue = O->hasIndexedProperty(state, Value(actualStart + k));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
if (fromValue) {
|
||
// Call the [[DefineOwnProperty]] internal method of A with arguments ToString(k), Property Descriptor {[[Value]]: fromValue, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
|
||
ObjectPropertyName from(state, Value(actualStart + k));
|
||
Value val = fromValue.value(state, from, O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
A->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, k),
|
||
ObjectPropertyDescriptor(val, ObjectPropertyDescriptor::AllPresent));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
}
|
||
// Increment k by 1.
|
||
k++;
|
||
}
|
||
// Let setStatus be Set(A, "length", actualDeleteCount, true).
|
||
A->setThrowsException(state, ObjectPropertyName(state.context()->staticStrings().length), Value(actualDeleteCount), A);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// Let items be an internal List whose elements are, in left to right order, the portion of the actual argument list starting with item1. The list will be empty if no such items are present.
|
||
Value* items = nullptr;
|
||
int64_t itemCount = 0;
|
||
|
||
if (argc > 2) {
|
||
items = argv + 2;
|
||
itemCount = argc - 2;
|
||
}
|
||
|
||
// If itemCount < actualDeleteCount, then
|
||
if (itemCount < actualDeleteCount) {
|
||
// Let k be actualStart.
|
||
k = actualStart;
|
||
// move [actualStart + deleteCnt, len) to [actualStart + insertCnt, len - deleteCnt + insertCnt)
|
||
while (k < len - actualDeleteCount) {
|
||
// Let from be ToString(k+actualDeleteCount).
|
||
int64_t from = k + actualDeleteCount;
|
||
// Let to be ToString(k+itemCount).
|
||
int64_t to = k + itemCount;
|
||
// Let fromPresent be the result of calling the [[HasProperty]] internal method of O with argument from.
|
||
ObjectHasPropertyResult fromValue = O->hasIndexedProperty(state, Value(from));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// If fromPresent is true, then
|
||
if (fromValue) {
|
||
// Let fromValue be the result of calling the [[Get]] internal method of O with argument from.
|
||
// Call the [[Put]] internal method of O with arguments to, fromValue, and true.
|
||
Value val = fromValue.value(state, ObjectPropertyName(state, from), O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
O->setIndexedPropertyThrowsException(state, Value(to), val);
|
||
} else {
|
||
// Else, fromPresent is false
|
||
|
||
// Call the [[Delete]] internal method of O with arguments to and true.
|
||
O->deleteOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(to)));
|
||
}
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
k++;
|
||
}
|
||
// delete [len - deleteCnt + itemCount, len)
|
||
// Let k be len.
|
||
k = len;
|
||
// Repeat, while k > (len – actualDeleteCount + itemCount)
|
||
while (k > len - actualDeleteCount + itemCount) {
|
||
// Call the [[Delete]] internal method of O with arguments ToString(k–1) and true.
|
||
O->deleteOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(k - 1)));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Decrease k by 1.
|
||
k--;
|
||
}
|
||
} else if (itemCount > actualDeleteCount) {
|
||
// Else if itemCount > actualDeleteCount, then
|
||
|
||
// Let k be (len – actualDeleteCount).
|
||
k = len - actualDeleteCount;
|
||
|
||
// Repeat, while k > actualStart
|
||
while (k > actualStart) {
|
||
// Let from be ToString(k + actualDeleteCount – 1).
|
||
// Let to be ToString(k + itemCount – 1)
|
||
|
||
// Let fromPresent be the result of calling the [[HasProperty]] internal method of O with argument from.
|
||
ObjectHasPropertyResult fromValue = O->hasIndexedProperty(state, Value(k + actualDeleteCount - 1));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// If fromPresent is true, then
|
||
if (fromValue) {
|
||
// Let fromValue be the result of calling the [[Get]] internal method of O with argument from.
|
||
// Call the [[Put]] internal method of O with arguments to, fromValue, and true.
|
||
ObjectPropertyName from(state, k + actualDeleteCount - 1);
|
||
Value val = fromValue.value(state, from, O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
O->setIndexedPropertyThrowsException(state, Value(k + itemCount - 1), val);
|
||
} else {
|
||
// Else, fromPresent is false
|
||
// Call the [[Delete]] internal method of O with argument to and true.
|
||
ObjectPropertyName to(state, k + itemCount - 1);
|
||
O->deleteOwnPropertyThrowsException(state, to);
|
||
}
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Decrease k by 1.
|
||
k--;
|
||
}
|
||
}
|
||
|
||
// Let k be actualStart.
|
||
k = actualStart;
|
||
|
||
// while items is not empty
|
||
int64_t itemsIndex = 0;
|
||
while (itemsIndex < itemCount) {
|
||
// Remove the first element from items and let E be the value of that element.
|
||
Value E = items[itemsIndex++];
|
||
// Call the [[Put]] internal method of O with arguments ToString(k), E, and true.
|
||
O->setIndexedPropertyThrowsException(state, Value(k), E);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Increase k by 1.
|
||
k++;
|
||
}
|
||
|
||
O->setThrowsException(state, ObjectPropertyName(state.context()->staticStrings().length), Value(len - actualDeleteCount + itemCount), O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
return A;
|
||
}
|
||
|
||
static Value builtinArrayConcat(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(thisObject, Array, concat);
|
||
Object* obj = arraySpeciesCreate(state, thisObject, 0);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
int64_t n = 0;
|
||
for (size_t i = 0; i < argc + 1; i++) {
|
||
Value argi = (i == 0) ? thisObject : argv[i - 1];
|
||
if (argi.isObject()) {
|
||
Object* arr = argi.asObject();
|
||
|
||
// Let spreadable be IsConcatSpreadable(E).
|
||
bool spreadable = arr->isConcatSpreadable(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
if (spreadable) {
|
||
// Let k be 0.
|
||
int64_t k = 0;
|
||
// Let len be the result of calling the [[Get]] internal method of E with argument "length".
|
||
int64_t len = arr->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// If n + len > 2^53 - 1, throw a TypeError exception.
|
||
CHECK_ARRAY_LENGTH(n + len > Value::maximumLength());
|
||
|
||
// Repeat, while k < len
|
||
while (k < len) {
|
||
// Let exists be the result of calling the [[HasProperty]] internal method of E with P.
|
||
ObjectHasPropertyResult exists = arr->hasIndexedProperty(state, Value(k));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
if (exists) {
|
||
Value val = exists.value(state, ObjectPropertyName(state, k), arr);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
obj->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(n + k)), ObjectPropertyDescriptor(val, ObjectPropertyDescriptor::AllPresent));
|
||
k++;
|
||
} else {
|
||
int64_t result;
|
||
Object::nextIndexForward(state, arr, k, len, result);
|
||
k = result;
|
||
}
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
}
|
||
|
||
n += len;
|
||
obj->setThrowsException(state, ObjectPropertyName(state.context()->staticStrings().length), Value(n), obj);
|
||
} else {
|
||
// If n >= 2^53 - 1, throw a TypeError exception.
|
||
CHECK_ARRAY_LENGTH(n >= Value::maximumLength());
|
||
|
||
obj->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(n)), ObjectPropertyDescriptor(arr, ObjectPropertyDescriptor::AllPresent));
|
||
n++;
|
||
}
|
||
} else {
|
||
obj->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(n++)), ObjectPropertyDescriptor(argi, ObjectPropertyDescriptor::AllPresent));
|
||
}
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
}
|
||
|
||
return obj;
|
||
}
|
||
|
||
static Value builtinArraySlice(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(thisObject, Array, slice);
|
||
int64_t len = thisObject->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
double relativeStart = argv[0].toInteger(state);
|
||
int64_t k = (relativeStart < 0) ? std::max((double)len + relativeStart, 0.0) : std::min(relativeStart, (double)len);
|
||
int64_t kStart = k;
|
||
double relativeEnd = (argv[1].isUndefined()) ? len : argv[1].toInteger(state);
|
||
int64_t finalEnd = (relativeEnd < 0) ? std::max((double)len + relativeEnd, 0.0) : std::min(relativeEnd, (double)len);
|
||
|
||
int64_t n = 0;
|
||
// Let count be max(final - k, 0).
|
||
// Let A be ArraySpeciesCreate(O, count).
|
||
Object* ArrayObject = arraySpeciesCreate(state, thisObject, std::max(((int64_t)finalEnd - (int64_t)k), (int64_t)0));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
while (k < finalEnd) {
|
||
ObjectHasPropertyResult exists = thisObject->hasIndexedProperty(state, Value(k));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
if (exists) {
|
||
Value val = exists.value(state, ObjectPropertyName(state, k), thisObject);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
ArrayObject->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(n)),
|
||
ObjectPropertyDescriptor(val, ObjectPropertyDescriptor::AllPresent));
|
||
k++;
|
||
n++;
|
||
} else {
|
||
int64_t result;
|
||
Object::nextIndexForward(state, thisObject, k, len, result);
|
||
n += result - k;
|
||
k = result;
|
||
}
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
}
|
||
if (finalEnd - kStart > 0) {
|
||
ArrayObject->setThrowsException(state, ObjectPropertyName(state.context()->staticStrings().length), Value(finalEnd - kStart), Value(ArrayObject));
|
||
} else {
|
||
ArrayObject->setThrowsException(state, ObjectPropertyName(state.context()->staticStrings().length), Value(0), Value(ArrayObject));
|
||
}
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
return ArrayObject;
|
||
}
|
||
|
||
static Value builtinArrayForEach(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(thisObject, Array, forEach);
|
||
int64_t len = thisObject->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
Value callbackfn = argv[0];
|
||
if (!callbackfn.isCallable()) {
|
||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Array.string(), true,
|
||
state.context()->staticStrings().forEach.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||
}
|
||
|
||
// If thisArg was supplied, let T be thisArg; else let T be undefined.
|
||
Value T;
|
||
if (argc > 1)
|
||
T = argv[1];
|
||
|
||
int64_t k = 0;
|
||
while (k < len) {
|
||
Value Pk = Value(k);
|
||
auto res = thisObject->hasProperty(state, ObjectPropertyName(state, Pk));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
if (res) {
|
||
Value kValue = res.value(state, ObjectPropertyName(state, k), thisObject);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
Value args[3] = { kValue, Pk, thisObject };
|
||
Object::call(state, callbackfn, T, 3, args);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
k++;
|
||
} else {
|
||
int64_t result;
|
||
Object::nextIndexForward(state, thisObject, k, len, result);
|
||
k = result;
|
||
continue;
|
||
}
|
||
}
|
||
return Value();
|
||
}
|
||
|
||
static Value builtinArrayIndexOf(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
// Let O be the result of calling ToObject passing the this value as the argument.
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Array, indexOf);
|
||
// Let lenValue be the result of calling the [[Get]] internal method of O with the argument "length".
|
||
// Let len be ToLength(Get(O, "length")).
|
||
int64_t len = O->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// If len is 0, return -1.
|
||
if (len == 0) {
|
||
return Value(-1);
|
||
}
|
||
|
||
// If argument fromIndex was passed let n be ToInteger(fromIndex); else let n be 0.
|
||
double n = 0;
|
||
if (argc > 1) {
|
||
n = argv[1].toInteger(state);
|
||
}
|
||
|
||
// If n ≥ len, return -1.
|
||
if (n >= len) {
|
||
return Value(-1);
|
||
}
|
||
|
||
double doubleK;
|
||
// If n ≥ 0, then
|
||
if (n >= 0) {
|
||
// Let k be n.
|
||
doubleK = (n == -0) ? 0 : n;
|
||
} else {
|
||
// Else, n<0
|
||
// Let k be len - abs(n).
|
||
doubleK = len - std::abs(n);
|
||
|
||
// If k is less than 0, then let k be 0.
|
||
if (doubleK < 0) {
|
||
doubleK = 0;
|
||
}
|
||
}
|
||
|
||
ASSERT(doubleK >= 0);
|
||
int64_t k = doubleK;
|
||
|
||
// Repeat, while k<len
|
||
while (k < len) {
|
||
// Let kPresent be the result of calling the [[HasProperty]] internal method of O with argument ToString(k).
|
||
auto kPresent = O->hasIndexedProperty(state, Value(k));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// If kPresent is true, then
|
||
if (kPresent) {
|
||
// Let elementK be the result of calling the [[Get]] internal method of O with the argument ToString(k).
|
||
Value elementK = kPresent.value(state, ObjectPropertyName(state, k), O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// Let same be the result of applying the Strict Equality Comparison Algorithm to searchElement and elementK.
|
||
if (elementK.equalsTo(state, argv[0])) {
|
||
// If same is true, return k.
|
||
return Value(k);
|
||
}
|
||
} else {
|
||
int64_t result;
|
||
Object::nextIndexForward(state, O, k, len, result);
|
||
k = result;
|
||
continue;
|
||
}
|
||
// Increase k by 1.
|
||
k++;
|
||
}
|
||
|
||
// Return -1.
|
||
return Value(-1);
|
||
}
|
||
|
||
static Value builtinArrayLastIndexOf(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
// Let O be the result of calling ToObject passing the this value as the argument.
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Array, lastIndexOf);
|
||
// Let lenValue be the result of calling the [[Get]] internal method of O with the argument "length".
|
||
// Let len be ToLength(Get(O, "length")).
|
||
double len = O->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// If len is 0, return -1.
|
||
if (len == 0) {
|
||
return Value(-1);
|
||
}
|
||
|
||
// If argument fromIndex was passed let n be ToInteger(fromIndex); else let n be len-1.
|
||
double n;
|
||
if (argc > 1) {
|
||
n = argv[1].toInteger(state);
|
||
} else {
|
||
n = len - 1;
|
||
}
|
||
|
||
// If n ≥ 0, then let k be min(n, len – 1).
|
||
double doubleK;
|
||
if (n >= 0) {
|
||
doubleK = (n == -0) ? 0 : std::min(n, len - 1.0);
|
||
} else {
|
||
// Else, n < 0
|
||
// Let k be len - abs(n).
|
||
doubleK = len - std::abs(n);
|
||
}
|
||
|
||
// NOTE in android arm32, -Inf to int64 generates wrong result
|
||
if (doubleK < 0) {
|
||
return Value(-1);
|
||
}
|
||
|
||
int64_t k = doubleK;
|
||
// Repeat, while k≥ 0
|
||
while (k >= 0) {
|
||
// Let kPresent be the result of calling the [[HasProperty]] internal method of O with argument ToString(k).
|
||
auto kPresent = O->hasIndexedProperty(state, Value(k));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// If kPresent is true, then
|
||
if (kPresent) {
|
||
// Let elementK be the result of calling the [[Get]] internal method of O with the argument ToString(k).
|
||
Value elementK = kPresent.value(state, ObjectPropertyName(state, k), O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// Let same be the result of applying the Strict Equality Comparison Algorithm to searchElement and elementK.
|
||
if (elementK.equalsTo(state, argv[0])) {
|
||
// If same is true, return k.
|
||
return Value(k);
|
||
}
|
||
} else {
|
||
int64_t result;
|
||
Object::nextIndexBackward(state, O, k, -1, result);
|
||
k = result;
|
||
continue;
|
||
}
|
||
// Decrease k by 1.
|
||
k--;
|
||
}
|
||
|
||
// Return -1.
|
||
return Value(-1);
|
||
}
|
||
|
||
static Value builtinArrayEvery(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Array, every);
|
||
// Let lenValue be the result of calling the [[Get]] internal method of O with the argument "length".
|
||
// Let len be ToLength(Get(O, "length")).
|
||
int64_t len = O->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// If IsCallable(callbackfn) is false, throw a TypeError exception.
|
||
Value callbackfn = argv[0];
|
||
if (!callbackfn.isCallable()) {
|
||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Array.string(), true,
|
||
state.context()->staticStrings().every.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||
}
|
||
|
||
// If thisArg was supplied, let T be thisArg; else let T be undefined.
|
||
Value T;
|
||
if (argc > 1)
|
||
T = argv[1];
|
||
|
||
// Let k be 0.
|
||
int64_t k = 0;
|
||
|
||
while (k < len) {
|
||
// Let Pk be ToString(k).
|
||
// Let kPresent be the result of calling the [[HasProperty]] internal method of O with argument Pk.
|
||
auto kPresent = O->hasIndexedProperty(state, Value(k));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// If kPresent is true, then
|
||
if (kPresent) {
|
||
// Let kValue be the result of calling the [[Get]] internal method of O with argument Pk.
|
||
Value kValue = kPresent.value(state, ObjectPropertyName(state, k), O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Let testResult be the result of calling the [[Call]] internal method of callbackfn with T as the this value and argument list containing kValue, k, and O.
|
||
Value args[] = { kValue, Value(k), O };
|
||
Value testResult = Object::call(state, callbackfn, T, 3, args);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
if (!testResult.toBoolean(state)) {
|
||
return Value(false);
|
||
}
|
||
|
||
// Increae k by 1.
|
||
k++;
|
||
} else {
|
||
int64_t result;
|
||
Object::nextIndexForward(state, O, k, len, result);
|
||
k = result;
|
||
}
|
||
}
|
||
return Value(true);
|
||
}
|
||
|
||
static Value builtinArrayFill(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Array, fill);
|
||
// Let lenValue be the result of calling the [[Get]] internal method of O with the argument "length".
|
||
// Let len be ToLength(Get(O, "length")).
|
||
int64_t len = O->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// Let relativeStart be ToInteger(start).
|
||
double relativeStart = 0;
|
||
if (argc > 1) {
|
||
relativeStart = argv[1].toInteger(state);
|
||
}
|
||
|
||
// If relativeStart < 0, let k be max((len + relativeStart),0); else let k be min(relativeStart, len).
|
||
int64_t k = (relativeStart < 0) ? std::max(len + relativeStart, 0.0) : std::min(relativeStart, (double)len);
|
||
|
||
// If end is undefined, let relativeEnd be len; else let relativeEnd be ToInteger(end).
|
||
double relativeEnd = len;
|
||
if (argc > 2 && !argv[2].isUndefined()) {
|
||
relativeEnd = argv[2].toInteger(state);
|
||
}
|
||
|
||
// If relativeEnd < 0, let final be max((len + relativeEnd),0); else let final be min(relativeEnd, len).
|
||
int64_t fin = (relativeEnd < 0) ? std::max(len + relativeEnd, 0.0) : std::min(relativeEnd, (double)len);
|
||
|
||
Value value = argv[0];
|
||
while (k < fin) {
|
||
O->setIndexedPropertyThrowsException(state, Value(k), value);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
k++;
|
||
}
|
||
// return O.
|
||
return O;
|
||
}
|
||
|
||
static Value builtinArrayFilter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
// Let O be the result of calling ToObject passing the this value as the argument.
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Array, filter);
|
||
|
||
// Let lenValue be the result of calling the [[Get]] internal method of O with the argument "length".
|
||
// Let len be ToLength(Get(O, "length")).
|
||
int64_t len = O->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// If IsCallable(callbackfn) is false, throw a TypeError exception.
|
||
Value callbackfn = argv[0];
|
||
if (!callbackfn.isCallable()) {
|
||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Array.string(), true,
|
||
state.context()->staticStrings().every.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||
}
|
||
|
||
// If thisArg was supplied, let T be thisArg; else let T be undefined.
|
||
Value T;
|
||
if (argc > 1)
|
||
T = argv[1];
|
||
|
||
// Let A be ArraySpeciesCreate(O, 0).
|
||
Object* A = arraySpeciesCreate(state, O, 0);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// Let k be 0.
|
||
int64_t k = 0;
|
||
// Let to be 0.
|
||
int64_t to = 0;
|
||
// Repeat, while k < len
|
||
while (k < len) {
|
||
// Let Pk be ToString(k).
|
||
// Let kPresent be the result of calling the [[HasProperty]] internal method of O with argument Pk.
|
||
ObjectHasPropertyResult kPresent = O->hasIndexedProperty(state, Value(k));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// If kPresent is true, then
|
||
if (kPresent) {
|
||
// Let kValue be the result of calling the [[Get]] internal method of O with argument Pk.
|
||
Value kValue = kPresent.value(state, ObjectPropertyName(state, k), O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// Let selected be the result of calling the [[Call]] internal method of callbackfn with T as the this value and argument list containing kValue, k, and O.
|
||
Value v[] = { kValue, Value(k), O };
|
||
Value selected = Object::call(state, callbackfn, T, 3, v);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// If ToBoolean(selected) is true, then
|
||
if (selected.toBoolean(state)) {
|
||
// Let status be CreateDataPropertyOrThrow (A, ToString(to), kValue).
|
||
ASSERT(A != nullptr);
|
||
A->defineOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(to)), ObjectPropertyDescriptor(kValue, ObjectPropertyDescriptor::AllPresent));
|
||
// Increase to by 1
|
||
to++;
|
||
}
|
||
|
||
k++;
|
||
} else {
|
||
int64_t result;
|
||
Object::nextIndexForward(state, O, k, len, result);
|
||
k = result;
|
||
}
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Increase k by 1.
|
||
}
|
||
|
||
// Return A.
|
||
return A;
|
||
}
|
||
|
||
static Value builtinArrayMap(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
// Let O be the result of calling ToObject passing the this value as the argument.
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Array, map);
|
||
// Let lenValue be the result of calling the [[Get]] internal method of O with the argument "length".
|
||
// Let len be ToLength(Get(O, "length")).
|
||
int64_t len = O->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// If IsCallable(callbackfn) is false, throw a TypeError exception.
|
||
Value callbackfn = argv[0];
|
||
if (!callbackfn.isCallable()) {
|
||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Array.string(), true,
|
||
state.context()->staticStrings().every.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||
}
|
||
// If thisArg was supplied, let T be thisArg; else let T be undefined.
|
||
Value T;
|
||
if (argc > 1)
|
||
T = argv[1];
|
||
|
||
// Let A be ArraySpeciesCreate(O, len).
|
||
Object* A = arraySpeciesCreate(state, O, len);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// Let k be 0.
|
||
int64_t k = 0;
|
||
|
||
// Repeat, while k < len
|
||
while (k < len) {
|
||
// Let Pk be ToString(k).
|
||
// Let kPresent be the result of calling the [[HasProperty]] internal method of O with argument Pk.
|
||
auto kPresent = O->hasIndexedProperty(state, Value(k));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// If kPresent is true, then
|
||
if (kPresent) {
|
||
// Let kValue be the result of calling the [[Get]] internal method of O with argument Pk.
|
||
auto Pk = ObjectPropertyName(state, k);
|
||
Value kValue = kPresent.value(state, Pk, O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Let mappedValue be the result of calling the [[Call]] internal method of callbackfn with T as the this value and argument list containing kValue, k, and O.
|
||
Value v[] = { kValue, Value(k), O };
|
||
Value mappedValue = Object::call(state, callbackfn, T, 3, v);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Let status be CreateDataPropertyOrThrow (A, Pk, mappedValue).
|
||
A->defineOwnPropertyThrowsException(state, Pk, ObjectPropertyDescriptor(mappedValue, ObjectPropertyDescriptor::AllPresent));
|
||
k++;
|
||
} else {
|
||
int64_t result;
|
||
Object::nextIndexForward(state, O, k, len, result);
|
||
k = result;
|
||
}
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Increase k by 1.
|
||
}
|
||
|
||
return A;
|
||
}
|
||
|
||
static Value builtinArraySome(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
// Let O be the result of calling ToObject passing the this value as the argument.
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Array, some);
|
||
// Let lenValue be the result of calling the [[Get]] internal method of O with the argument "length".
|
||
// Let len be ToLength(Get(O, "length")).
|
||
int64_t len = O->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// If IsCallable(callbackfn) is false, throw a TypeError exception.
|
||
Value callbackfn = argv[0];
|
||
if (!callbackfn.isCallable()) {
|
||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Array.string(), true,
|
||
state.context()->staticStrings().some.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||
}
|
||
Value T;
|
||
// If thisArg was supplied, let T be thisArg; else let T be undefined.
|
||
if (argc > 1) {
|
||
T = argv[1];
|
||
}
|
||
|
||
// Let k be 0.
|
||
int64_t k = 0;
|
||
// Repeat, while k < len
|
||
while (k < len) {
|
||
// Let Pk be ToString(k).
|
||
// Let kPresent be the result of calling the [[HasProperty]] internal method of O with argument Pk.
|
||
ObjectHasPropertyResult kPresent = O->hasIndexedProperty(state, Value(k));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// If kPresent is true, then
|
||
if (kPresent) {
|
||
// Let kValue be the result of calling the [[Get]] internal method of O with argument Pk.
|
||
ObjectPropertyName Pk(state, k);
|
||
Value kValue = kPresent.value(state, Pk, O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Let testResult be the result of calling the [[Call]] internal method of callbackfn with T as the this value and argument list containing kValue, k, and O.
|
||
Value argv[] = { kValue, Value(k), O };
|
||
Value testResult = Object::call(state, callbackfn, T, 3, argv);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// If ToBoolean(testResult) is true, return true.
|
||
if (testResult.toBoolean(state)) {
|
||
return Value(true);
|
||
}
|
||
} else {
|
||
int64_t result;
|
||
Object::nextIndexForward(state, O, k, len, result);
|
||
k = result;
|
||
continue;
|
||
}
|
||
// Increase k by 1.
|
||
k++;
|
||
}
|
||
// Return false.
|
||
return Value(false);
|
||
}
|
||
|
||
// Array.prototype.includes ( searchElement [ , fromIndex ] )
|
||
static Value builtinArrayIncludes(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
// Let O be ? ToObject(this value).
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Array, includes);
|
||
// Let len be ? ToLength(? Get(O, "length")).
|
||
int64_t len = O->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// If len is 0, return false.
|
||
if (len == 0) {
|
||
return Value(false);
|
||
}
|
||
|
||
Value searchElement = argv[0];
|
||
// Let n be ? ToInteger(fromIndex). (If fromIndex is undefined, this step produces the value 0.)
|
||
double n = argc >= 2 ? argv[1].toInteger(state) : 0;
|
||
double doubleK;
|
||
// If n ≥ 0, then
|
||
if (n >= 0) {
|
||
// Let k be n.
|
||
doubleK = n;
|
||
} else {
|
||
// Else n < 0,
|
||
// Let k be len + n.
|
||
doubleK = len + n;
|
||
}
|
||
|
||
// If k < 0, let k be 0.
|
||
if (doubleK < 0) {
|
||
doubleK = 0;
|
||
}
|
||
|
||
ASSERT(doubleK >= 0);
|
||
|
||
// Repeat, while k < len
|
||
while (doubleK < len) {
|
||
// Let elementK be the result of ? Get(O, ! ToString(k)).
|
||
Value elementK = O->get(state, ObjectPropertyName(state, Value(Value::DoubleToIntConvertibleTestNeeds, doubleK))).value(state, O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// If SameValueZero(searchElement, elementK) is true, return true.
|
||
if (elementK.equalsToByTheSameValueZeroAlgorithm(state, searchElement)) {
|
||
return Value(true);
|
||
}
|
||
// Increase k by 1.
|
||
doubleK++;
|
||
}
|
||
|
||
// Return false.
|
||
return Value(false);
|
||
}
|
||
|
||
static Value builtinArrayToLocaleString(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
// https://www.ecma-international.org/ecma-402/6.0/index.html#sup-array.prototype.tolocalestring
|
||
// Let array be the result of calling ToObject passing the this value as the argument.
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(array, Array, toLocaleString);
|
||
|
||
if (!state.context()->toStringRecursionPreventer()->canInvokeToString(array)) {
|
||
return String::emptyString;
|
||
}
|
||
ToStringRecursionPreventerItemAutoHolder holder(state, array);
|
||
|
||
// Let len be ? ToLength(? Get(array, "length")).
|
||
uint64_t len = array->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// Let separator be the String value for the list-separator String appropriate for the host environment’s current locale (this is derived in an implementation-defined way).
|
||
String* separator = state.context()->staticStrings().asciiTable[(size_t)','].string();
|
||
|
||
// Let R be the empty String.
|
||
String* R = String::emptyString;
|
||
|
||
// Let k be 0.
|
||
uint64_t k = 0;
|
||
|
||
// Repeat, while k < len
|
||
while (k < len) {
|
||
// If k > 0, then
|
||
if (k > 0) {
|
||
// Set R to the string-concatenation of R and separator.
|
||
StringBuilder builder;
|
||
builder.appendString(R);
|
||
builder.appendString(separator);
|
||
R = builder.finalize(&state);
|
||
}
|
||
// Let nextElement be ? Get(array, ! ToString(k)).
|
||
Value nextElement = array->getIndexedProperty(state, Value(k)).value(state, array);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// If nextElement is not undefined or null, then
|
||
if (!nextElement.isUndefinedOrNull()) {
|
||
// Let S be ? ToString(? Invoke(nextElement, "toLocaleString", « locales, options »)).
|
||
Value func = nextElement.toObject(state)->get(state, state.context()->staticStrings().toLocaleString).value(state, nextElement);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
Value val = Object::call(state, func, nextElement, argc, argv);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
String* S = val.toString(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Set R to the string-concatenation of R and S.
|
||
StringBuilder builder;
|
||
builder.appendString(R);
|
||
builder.appendString(S);
|
||
R = builder.finalize(&state);
|
||
}
|
||
// Increase k by 1.
|
||
k++;
|
||
}
|
||
|
||
// Return R.
|
||
return R;
|
||
}
|
||
|
||
static Value builtinArrayReduce(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
// Let O be the result of calling ToObject passing the this value as the argument.
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Array, reduce);
|
||
int64_t len = O->length(state); // 2-3
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
Value callbackfn = argv[0];
|
||
Value initialValue = Value(Value::EmptyValue);
|
||
if (argc > 1) {
|
||
initialValue = argv[1];
|
||
}
|
||
|
||
if (!callbackfn.isCallable()) // 4
|
||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Array.string(), true, state.context()->staticStrings().reduce.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||
|
||
if (len == 0 && (initialValue.isUndefined() || initialValue.isEmpty())) // 5
|
||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Array.string(), true, state.context()->staticStrings().reduce.string(), ErrorObject::Messages::GlobalObject_ReduceError);
|
||
|
||
int64_t k = 0; // 6
|
||
Value accumulator;
|
||
if (!initialValue.isEmpty()) { // 7
|
||
accumulator = initialValue;
|
||
} else { // 8
|
||
ObjectHasPropertyResult kPresent; // 8.a
|
||
while (!kPresent && k < len) { // 8.b
|
||
kPresent = O->hasIndexedProperty(state, Value(k)); // 8.b.ii
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
if (kPresent) {
|
||
accumulator = kPresent.value(state, ObjectPropertyName(state, k), O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
}
|
||
k++; // 8.b.iv
|
||
}
|
||
if (!kPresent)
|
||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Array.string(), true, state.context()->staticStrings().reduce.string(), ErrorObject::Messages::GlobalObject_ReduceError);
|
||
}
|
||
while (k < len) { // 9
|
||
ObjectHasPropertyResult kPresent = O->hasIndexedProperty(state, Value(k)); // 9.b
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
if (kPresent) { // 9.c
|
||
Value kValue = kPresent.value(state, ObjectPropertyName(state, k), O); // 9.c.i
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
const int fnargc = 4;
|
||
Value fnargs[] = { accumulator, kValue, Value(k), O };
|
||
accumulator = Object::call(state, callbackfn, Value(), fnargc, fnargs);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
k++;
|
||
} else {
|
||
int64_t result;
|
||
Object::nextIndexForward(state, O, k, len, result);
|
||
k = result;
|
||
}
|
||
}
|
||
return accumulator;
|
||
}
|
||
|
||
static Value builtinArrayReduceRight(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
// Let O be the result of calling ToObject passing the this value as the argument.
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Array, reduceRight);
|
||
|
||
// Let lenValue be the result of calling the [[Get]] internal method of O with the argument "length".
|
||
// Let len be ToLength(Get(O, "length")).
|
||
int64_t len = O->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// If IsCallable(callbackfn) is false, throw a TypeError exception.
|
||
Value callbackfn = argv[0];
|
||
if (!callbackfn.isCallable()) {
|
||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Array.string(), true,
|
||
state.context()->staticStrings().reduceRight.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||
}
|
||
|
||
// If len is 0 and initialValue is not present, throw a TypeError exception.
|
||
if (len == 0 && argc < 2) {
|
||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Array.string(), true, state.context()->staticStrings().reduceRight.string(), ErrorObject::Messages::GlobalObject_ReduceError);
|
||
}
|
||
|
||
// Let k be len-1.
|
||
int64_t k = len - 1;
|
||
|
||
Value accumulator;
|
||
// If initialValue is present, then
|
||
if (argc > 1) {
|
||
// Set accumulator to initialValue.
|
||
accumulator = argv[1];
|
||
} else {
|
||
// Else, initialValue is not present
|
||
// Let kPresent be false.
|
||
ObjectHasPropertyResult kPresent;
|
||
|
||
// Repeat, while kPresent is false and k ≥ 0
|
||
while (!kPresent && k >= 0) {
|
||
// Let Pk be ToString(k).
|
||
// Let kPresent be the result of calling the [[HasProperty]] internal method of O with argument Pk.
|
||
kPresent = O->hasIndexedProperty(state, Value(k));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// If kPresent is true, then
|
||
if (kPresent) {
|
||
// Let accumulator be the result of calling the [[Get]] internal method of O with argument Pk.
|
||
accumulator = kPresent.value(state, ObjectPropertyName(state, k), O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
}
|
||
|
||
// Decrease k by 1.
|
||
int64_t result;
|
||
Object::nextIndexBackward(state, O, k, -1, result);
|
||
k = result;
|
||
}
|
||
// If kPresent is false, throw a TypeError exception.
|
||
if (!kPresent) {
|
||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Array.string(), true, state.context()->staticStrings().reduceRight.string(), ErrorObject::Messages::GlobalObject_ReduceError);
|
||
}
|
||
}
|
||
|
||
// Repeat, while k ≥ 0
|
||
while (k >= 0) {
|
||
// Let Pk be ToString(k).
|
||
ObjectPropertyName Pk(state, k);
|
||
// Let kPresent be the result of calling the [[HasProperty]] internal method of O with argument Pk.
|
||
ObjectHasPropertyResult kPresent = O->hasIndexedProperty(state, Value(k));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// If kPresent is true, then
|
||
if (kPresent) {
|
||
// Let kValue be the result of calling the [[Get]] internal method of O with argument Pk.
|
||
Value kValue = kPresent.value(state, ObjectPropertyName(state, k), O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// Let accumulator be the result of calling the [[Call]] internal method of callbackfn with undefined as the this value and argument list containing accumulator, kValue, k, and O.
|
||
Value v[] = { accumulator, kValue, Value(k), O };
|
||
accumulator = Object::call(state, callbackfn, Value(), 4, v);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
}
|
||
|
||
// Decrease k by 1.
|
||
int64_t result;
|
||
Object::nextIndexBackward(state, O, k, -1, result);
|
||
k = result;
|
||
}
|
||
|
||
// Return accumulator.
|
||
return accumulator;
|
||
}
|
||
|
||
static Value builtinArrayPop(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
// Let O be the result of calling ToObject passing the this value as the argument.
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Array, pop);
|
||
|
||
// Let lenVal be the result of calling the [[Get]] internal method of O with argument "length".
|
||
// Let len be ToUint32(lenVal).
|
||
int64_t len = O->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// If len is zero,
|
||
if (len == 0) {
|
||
// Call the [[Put]] internal method of O with arguments "length", 0, and true.
|
||
O->setThrowsException(state, ObjectPropertyName(state.context()->staticStrings().length), Value(0), O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Return undefined.
|
||
return Value();
|
||
} else {
|
||
// Else, len > 0
|
||
// Let indx be ToString(len–1).
|
||
ObjectPropertyName indx(state, len - 1);
|
||
// Let element be the result of calling the [[Get]] internal method of O with argument indx.
|
||
Value element = O->get(state, indx).value(state, O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Call the [[Delete]] internal method of O with arguments indx and true.
|
||
O->deleteOwnPropertyThrowsException(state, indx);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Call the [[Put]] internal method of O with arguments "length", indx, and true.
|
||
O->setThrowsException(state, ObjectPropertyName(state.context()->staticStrings().length), Value(len - 1), O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Return element.
|
||
return element;
|
||
}
|
||
}
|
||
|
||
static Value builtinArrayPush(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
// Array.prototype.push ( [ item1 [ , item2 [ , … ] ] ] )
|
||
// Let O be the result of calling ToObject passing the this value as the argument.
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Array, push);
|
||
|
||
// Let lenVal be the result of calling the [[Get]] internal method of O with argument "length".
|
||
// Let len be ToLength(Get(O, "length")).
|
||
int64_t n = O->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// If len + argCount > 2^53 - 1, throw a TypeError exception.
|
||
CHECK_ARRAY_LENGTH((uint64_t)n + argc > Value::maximumLength());
|
||
|
||
// Let items be an internal List whose elements are, in left to right order, the arguments that were passed to this function invocation.
|
||
// Repeat, while items is not empty
|
||
// Remove the first element from items and let E be the value of the element.
|
||
for (size_t i = 0; i < argc; i++) {
|
||
// Call the [[Put]] internal method of O with arguments ToString(n), E, and true.
|
||
O->setIndexedPropertyThrowsException(state, Value(n), argv[i]);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Increase n by 1.
|
||
n++;
|
||
}
|
||
|
||
// Call the [[Put]] internal method of O with arguments "length", n, and true.
|
||
O->setThrowsExceptionWhenStrictMode(state, ObjectPropertyName(state, state.context()->staticStrings().length), Value(n), O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// Return n.
|
||
return Value(n);
|
||
}
|
||
|
||
// https://www.ecma-international.org/ecma-262/10.0/#sec-array.prototype.flat
|
||
// Array.prototype.flat( [ depth ] )
|
||
static Value builtinArrayFlat(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Array, flat);
|
||
int64_t sourceLen = O->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
double depthNum = 1;
|
||
if (argc > 0 && !argv[0].isUndefined()) {
|
||
depthNum = argv[0].toInteger(state);
|
||
}
|
||
Object* A = arraySpeciesCreate(state, O, 0);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
flattenIntoArray(state, A, O, sourceLen, 0, depthNum);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
return A;
|
||
}
|
||
|
||
// https://www.ecma-international.org/ecma-262/10.0/#sec-array.prototype.flatmap
|
||
// Array.prototype.flatMap ( mapperFunction [ , thisArg ] )
|
||
static Value builtinArrayFlatMap(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Array, flatMap);
|
||
int64_t sourceLen = O->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
if (!argv[0].isCallable()) {
|
||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Array.string(), true, state.context()->staticStrings().flatMap.string(), ErrorObject::Messages::GlobalObject_FirstArgumentNotCallable);
|
||
}
|
||
Value t;
|
||
if (argc > 1) {
|
||
t = argv[1];
|
||
}
|
||
Object* A = arraySpeciesCreate(state, O, 0);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
flattenIntoArray(state, A, O, sourceLen, 0, 1, argv[0], t);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
return A;
|
||
}
|
||
|
||
static Value builtinArrayShift(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
// Let O be the result of calling ToObject passing the this value as the argument.
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Array, shift);
|
||
// Let lenVal be the result of calling the [[Get]] internal method of O with argument "length".
|
||
// Let len be ToLength(Get(O, "length")).
|
||
int64_t len = O->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// If len is zero, then
|
||
if (len == 0) {
|
||
// Call the [[Put]] internal method of O with arguments "length", 0, and true.
|
||
O->setThrowsException(state, ObjectPropertyName(state.context()->staticStrings().length), Value(0), O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Return undefined.
|
||
return Value();
|
||
}
|
||
// Let first be the result of calling the [[Get]] internal method of O with argument "0".
|
||
Value first = O->get(state, ObjectPropertyName(state, Value(0))).value(state, O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Let k be 1.
|
||
int64_t k = 1;
|
||
// Repeat, while k < len
|
||
while (k < len) {
|
||
// Let from be ToString(k).
|
||
ObjectPropertyName from(state, k);
|
||
// Let to be ToString(k–1).
|
||
ObjectPropertyName to(state, k - 1);
|
||
// Let fromPresent be the result of calling the [[HasProperty]] internal method of O with argument from.
|
||
auto fromPresent = O->hasIndexedProperty(state, Value(k));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// If fromPresent is true, then
|
||
if (fromPresent) {
|
||
// Let fromVal be the result of calling the [[Get]] internal method of O with argument from.
|
||
Value fromVal = fromPresent.value(state, from, O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Call the [[Put]] internal method of O with arguments to, fromVal, and true.
|
||
O->setThrowsException(state, to, fromVal, O);
|
||
} else {
|
||
// Else, fromPresent is false
|
||
// Call the [[Delete]] internal method of O with arguments to and true.
|
||
O->deleteOwnPropertyThrowsException(state, to);
|
||
}
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// Increase k by 1.
|
||
if (fromPresent) {
|
||
k++;
|
||
} else {
|
||
int64_t result;
|
||
Object::nextIndexForward(state, O, k, len, result);
|
||
int64_t r = result;
|
||
if (r > k) {
|
||
k = r;
|
||
} else {
|
||
k--;
|
||
}
|
||
}
|
||
}
|
||
// Call the [[Delete]] internal method of O with arguments ToString(len–1) and true.
|
||
O->deleteOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(len - 1)));
|
||
// Call the [[Put]] internal method of O with arguments "length", (len–1) , and true.
|
||
O->setThrowsException(state, ObjectPropertyName(state.context()->staticStrings().length), Value(len - 1), O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Return first.
|
||
return first;
|
||
}
|
||
|
||
static Value builtinArrayUnshift(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
// Let O be the result of calling ToObject passing the this value as the argument.
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Array, unshift);
|
||
// Let lenVal be the result of calling the [[Get]] internal method of O with argument "length".
|
||
// Let len be ToLength(Get(O, "length")).
|
||
int64_t len = O->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// Let argCount be the number of actual arguments.
|
||
int64_t argCount = argc;
|
||
// Let k be len.
|
||
int64_t k = len;
|
||
|
||
// If argCount > 0, then
|
||
// this line add in newer version ECMAScript than ECMAScript 5.1
|
||
// http://www.ecma-international.org/ecma-262/6.0/index.html#sec-array.prototype.unshift
|
||
// http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.13
|
||
if (argCount) {
|
||
// If len + argCount > 2^53 - 1, throw a TypeError exception.
|
||
CHECK_ARRAY_LENGTH(len + argCount > Value::maximumLength());
|
||
|
||
// Repeat, while k > 0,
|
||
while (k > 0) {
|
||
// Let from be ToString(k–1).
|
||
// Let to be ToString(k+argCount –1).
|
||
ObjectPropertyName to(state, k + argCount - 1);
|
||
|
||
// Let fromPresent be the result of calling the [[HasProperty]] internal method of O with argument from.
|
||
ObjectHasPropertyResult fromPresent = O->hasIndexedProperty(state, Value(k - 1));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// If fromPresent is true, then
|
||
if (fromPresent) {
|
||
// Let fromValue be the result of calling the [[Get]] internal method of O with argument from.
|
||
ObjectPropertyName from(state, k - 1);
|
||
Value fromValue = fromPresent.value(state, from, O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Call the [[Put]] internal method of O with arguments to, fromValue, and true.
|
||
O->setThrowsException(state, to, fromValue, O);
|
||
} else {
|
||
// Else, fromPresent is false
|
||
// Call the [[Delete]] internal method of O with arguments to, and true.
|
||
O->deleteOwnPropertyThrowsException(state, to);
|
||
}
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
if (fromPresent) {
|
||
// Decrease k by 1.
|
||
k--;
|
||
} else {
|
||
int64_t result;
|
||
Object::nextIndexBackward(state, O, k, -1, result);
|
||
int64_t r = std::max(result + 1, result - argCount + 1);
|
||
if (r < k && std::abs(r - k) > argCount) {
|
||
k = r;
|
||
} else {
|
||
k--;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Let j be 0.
|
||
int64_t j = 0;
|
||
// Let items be an internal List whose elements are, in left to right order, the arguments that were passed to this function invocation.
|
||
Value* items = argv;
|
||
|
||
// Repeat, while items is not empty
|
||
while (j < argCount) {
|
||
// Remove the first element from items and let E be the value of that element.
|
||
Value E = items[j];
|
||
// Call the [[Put]] internal method of O with arguments ToString(j), E, and true.
|
||
O->setThrowsException(state, ObjectPropertyName(state, Value(j)), E, O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Increase j by 1.
|
||
j++;
|
||
}
|
||
}
|
||
|
||
// Call the [[Put]] internal method of O with arguments "length", len+argCount, and true.
|
||
O->setThrowsException(state, state.context()->staticStrings().length, Value(len + argCount), O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
|
||
// Return len+argCount.
|
||
return Value(len + argCount);
|
||
}
|
||
|
||
// Array.prototype.find ( predicate [ , thisArg ] )#
|
||
static Value builtinArrayFind(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
Value predicate = argv[0];
|
||
Value thisArg = argc > 1 ? argv[1] : Value();
|
||
// Let O be ? ToObject(this value).
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Array, find);
|
||
// Let len be ? ToLength(? Get(O, "length")).
|
||
uint64_t len = O->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// If IsCallable(predicate) is false, throw a TypeError exception.
|
||
if (!predicate.isCallable()) {
|
||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Array.string(), true, state.context()->staticStrings().find.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||
}
|
||
|
||
// Let k be 0.
|
||
uint64_t k = 0;
|
||
// Repeat, while k < len
|
||
while (k < len) {
|
||
// Let Pk be ! ToString(k).
|
||
// Let kValue be ? Get(O, Pk).
|
||
Value kValue = O->get(state, ObjectPropertyName(state, Value(k))).value(state, O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Let testResult be ToBoolean(? Call(predicate, thisArg, « kValue, k, O »)).
|
||
Value v[] = { kValue, Value(k), O };
|
||
Value res = Object::call(state, argv[0], thisArg, 3, v);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
bool testResult = res.toBoolean(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// If testResult is true, return kValue.
|
||
if (testResult) {
|
||
return kValue;
|
||
}
|
||
// Increase k by 1.
|
||
k++;
|
||
}
|
||
// Return undefined.
|
||
return Value();
|
||
}
|
||
|
||
// Array.prototype.findIndex ( predicate [ , thisArg ] )#
|
||
static Value builtinArrayFindIndex(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
Value predicate = argv[0];
|
||
Value thisArg = argc > 1 ? argv[1] : Value();
|
||
// Let O be ? ToObject(this value).
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Array, findIndex);
|
||
// Let len be ? ToLength(? Get(O, "length")).
|
||
uint64_t len = O->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// If IsCallable(predicate) is false, throw a TypeError exception.
|
||
if (!predicate.isCallable()) {
|
||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Array.string(), true, state.context()->staticStrings().findIndex.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||
}
|
||
|
||
// Let k be 0.
|
||
uint64_t k = 0;
|
||
// Repeat, while k < len
|
||
while (k < len) {
|
||
// Let Pk be ! ToString(k).
|
||
// Let kValue be ? Get(O, Pk).
|
||
Value kValue = O->get(state, ObjectPropertyName(state, Value(k))).value(state, O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Let testResult be ToBoolean(? Call(predicate, thisArg, « kValue, k, O »)).
|
||
Value v[] = { kValue, Value(k), O };
|
||
Value res = Object::call(state, argv[0], thisArg, 3, v);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
bool testResult = res.toBoolean(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// If testResult is true, return k.
|
||
if (testResult) {
|
||
return Value(k);
|
||
}
|
||
// Increase k by 1.
|
||
k++;
|
||
}
|
||
// Return -1
|
||
return Value(-1);
|
||
}
|
||
|
||
// Array.prototype.copyWithin (target, start [ , end ] )
|
||
static Value builtinArrayCopyWithin(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
// Let O be ToObject(this value).
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Array, copyWithin);
|
||
// Let len be ToLength(Get(O, "length")).
|
||
double len = O->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Let relativeTarget be ToInteger(target).
|
||
double relativeTarget = argv[0].toInteger(state);
|
||
// If relativeTarget < 0, let to be max((len + relativeTarget),0); else let to be min(relativeTarget, len).
|
||
double to = (relativeTarget < 0.0) ? std::max((len + relativeTarget), 0.0) : std::min(relativeTarget, len);
|
||
// Let relativeStart be ToInteger(start).
|
||
double relativeStart = argv[1].toInteger(state);
|
||
// If relativeStart < 0, let from be max((len + relativeStart),0); else let from be min(relativeStart, len).
|
||
double from = (relativeStart < 0.0) ? std::max((len + relativeStart), 0.0) : std::min(relativeStart, len);
|
||
// If end is undefined, let relativeEnd be len; else let relativeEnd be ToInteger(end).
|
||
double relativeEnd = (argc < 3 || argv[2].isUndefined()) ? len : argv[2].toInteger(state);
|
||
// If relativeEnd < 0, let final be max((len + relativeEnd),0); else let final be min(relativeEnd, len).
|
||
double finalEnd = (relativeEnd < 0.0) ? std::max((len + relativeEnd), 0.0) : std::min(relativeEnd, len);
|
||
// Let count be min(final-from, len-to).
|
||
double count = std::min(finalEnd - from, len - to);
|
||
int8_t direction;
|
||
// If from<to and to<from+count
|
||
if (from < to && to < from + count) {
|
||
// Let direction be -1.
|
||
direction = -1;
|
||
// Let from be from + count -1.
|
||
from = from + count - 1;
|
||
// Let to be to + count -1.
|
||
to = to + count - 1;
|
||
} else {
|
||
// Let direction = 1.
|
||
direction = 1;
|
||
}
|
||
|
||
int64_t intCount = count;
|
||
int64_t intFrom = from;
|
||
int64_t intTo = to;
|
||
|
||
// Repeat, while count > 0
|
||
while (intCount > 0) {
|
||
// Let fromPresent be HasProperty(O, fromKey).
|
||
ObjectHasPropertyResult fromValue = O->hasIndexedProperty(state, Value(intFrom));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// If fromPresent is true, then
|
||
if (fromValue) {
|
||
// Let setStatus be Set(O, toKey, fromVal, true).
|
||
Value val = fromValue.value(state, ObjectPropertyName(state, intFrom), O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
O->setIndexedPropertyThrowsException(state, Value(intTo), val);
|
||
} else {
|
||
// Let deleteStatus be DeletePropertyOrThrow(O, toKey).
|
||
O->deleteOwnPropertyThrowsException(state, ObjectPropertyName(state, Value(intTo)));
|
||
}
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// Let from be from + direction.
|
||
intFrom += direction;
|
||
// Let to be to + direction.
|
||
intTo += direction;
|
||
// Let count be count − 1.
|
||
intCount--;
|
||
}
|
||
// Return O.
|
||
return O;
|
||
}
|
||
|
||
static Value builtinArrayKeys(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(M, Array, keys);
|
||
return M->keys(state);
|
||
}
|
||
|
||
static Value builtinArrayValues(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(M, Array, values);
|
||
return M->values(state);
|
||
}
|
||
|
||
static Value builtinArrayEntries(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(M, Array, entries);
|
||
return M->entries(state);
|
||
}
|
||
|
||
static Value builtinArrayIteratorNext(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
if (!thisValue.isObject() || !thisValue.asObject()->isArrayIteratorObject()) {
|
||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().ArrayIterator.string(), true, state.context()->staticStrings().next.string(), ErrorObject::Messages::GlobalObject_CalledOnIncompatibleReceiver);
|
||
}
|
||
|
||
ArrayIteratorObject* iter = thisValue.asObject()->asIteratorObject()->asArrayIteratorObject();
|
||
return iter->next(state);
|
||
}
|
||
|
||
static Value builtinArrayAt(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(obj, Array, at);
|
||
size_t len = obj->length(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
double relativeIndex = argv[0].toInteger(state);
|
||
double k = (relativeIndex < 0) ? len + relativeIndex : relativeIndex;
|
||
|
||
if (UNLIKELY(k < 0 || k >= len)) {
|
||
return Value();
|
||
}
|
||
|
||
return obj->getIndexedProperty(state, Value(Value::DoubleToIntConvertibleTestNeeds, k)).value(state, thisValue);
|
||
}
|
||
|
||
static Value builtinArrayFindLast(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
// https://tc39.es/proposal-array-find-from-last/index.html#sec-array.prototype.findlast
|
||
Value predicate = argv[0];
|
||
Value thisArg = argc > 1 ? argv[1] : Value();
|
||
// 1. Let O be ? ToObject(this value).
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Array, findLast);
|
||
// 2. Let len be ? LengthOfArrayLike(O).
|
||
int64_t len = static_cast<int64_t>(O->length(state));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// 3. If IsCallable(predicate) is false, throw a TypeError exception.
|
||
if (!predicate.isCallable()) {
|
||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Array.string(), true, state.context()->staticStrings().findLast.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||
}
|
||
// 4. Let k be len - 1.
|
||
int64_t k = len - 1;
|
||
// 5. Repeat, while k ≥ 0,
|
||
while (k >= 0) {
|
||
// a. Let Pk be ! ToString(𝔽(k)).
|
||
// b. Let kValue be ? Get(O, Pk).
|
||
Value kValue = O->getIndexedProperty(state, Value(k)).value(state, O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// c. Let testResult be ! ToBoolean(? Call(predicate, thisArg, « kValue, 𝔽(k), O »)).
|
||
Value predicateArgv[] = {
|
||
kValue, Value(k), Value(O)
|
||
};
|
||
Value res = Object::call(state, predicate, thisArg, 3, predicateArgv);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
bool testResult = res.toBoolean(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// d. If testResult is true, return kValue.
|
||
if (testResult) {
|
||
return kValue;
|
||
}
|
||
// e. Set k to k - 1.
|
||
k--;
|
||
}
|
||
|
||
return Value();
|
||
}
|
||
|
||
static Value builtinArrayFindLastIndex(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
|
||
{
|
||
// https://tc39.es/proposal-array-find-from-last/index.html#sec-array.prototype.findlastindex
|
||
Value predicate = argv[0];
|
||
Value thisArg = argc > 1 ? argv[1] : Value();
|
||
// 1. Let O be ? ToObject(this value).
|
||
RESOLVE_THIS_BINDING_TO_OBJECT(O, Array, findLastIndex);
|
||
// 2. Let len be ? LengthOfArrayLike(O).
|
||
int64_t len = static_cast<int64_t>(O->length(state));
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// 3. If IsCallable(predicate) is false, throw a TypeError exception.
|
||
if (!predicate.isCallable()) {
|
||
THROW_BUILTIN_ERROR_RETURN_VALUE(state, ErrorCode::TypeError, state.context()->staticStrings().Array.string(), true, state.context()->staticStrings().findLastIndex.string(), ErrorObject::Messages::GlobalObject_CallbackNotCallable);
|
||
}
|
||
// 4. Let k be len - 1.
|
||
int64_t k = len - 1;
|
||
// 5. Repeat, while k ≥ 0,
|
||
while (k >= 0) {
|
||
// a. Let Pk be ! ToString(𝔽(k)).
|
||
// b. Let kValue be ? Get(O, Pk).
|
||
Value kValue = O->getIndexedProperty(state, Value(k)).value(state, O);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// c. Let testResult be ! ToBoolean(? Call(predicate, thisArg, « kValue, 𝔽(k), O »)).
|
||
Value predicateArgv[] = {
|
||
kValue, Value(k), Value(O)
|
||
};
|
||
Value res = Object::call(state, predicate, thisArg, 3, predicateArgv);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
bool testResult = res.toBoolean(state);
|
||
RETURN_VALUE_IF_PENDING_EXCEPTION
|
||
// d. If testResult is true, return kValue.
|
||
if (testResult) {
|
||
return Value(k);
|
||
}
|
||
// e. Set k to k - 1.
|
||
k--;
|
||
}
|
||
|
||
return Value(-1);
|
||
}
|
||
|
||
void GlobalObject::initializeArray(ExecutionState& state)
|
||
{
|
||
ObjectPropertyNativeGetterSetterData* nativeData = new ObjectPropertyNativeGetterSetterData(true, false, true,
|
||
[](ExecutionState& state, Object* self, const Value& receiver, const EncodedValue& privateDataFromObjectPrivateArea) -> Value {
|
||
ASSERT(self->isGlobalObject());
|
||
return self->asGlobalObject()->array();
|
||
},
|
||
nullptr);
|
||
|
||
defineNativeDataAccessorProperty(state, ObjectPropertyName(state.context()->staticStrings().Array), nativeData, Value(Value::EmptyValue));
|
||
}
|
||
|
||
void GlobalObject::installArray(ExecutionState& state)
|
||
{
|
||
ASSERT(!!m_iteratorPrototype);
|
||
ASSERT(!!m_arrayToString);
|
||
|
||
m_array = new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().Array, builtinArrayConstructor, 1), NativeFunctionObject::__ForBuiltinConstructor__);
|
||
m_array->setGlobalIntrinsicObject(state);
|
||
|
||
{
|
||
JSGetterSetter gs(
|
||
new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().getSymbolSpecies, builtinSpeciesGetter, 0, NativeFunctionInfo::Strict)), Value(Value::EmptyValue));
|
||
ObjectPropertyDescriptor desc(gs, ObjectPropertyDescriptor::ConfigurablePresent);
|
||
m_array->directDefineOwnProperty(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().species), desc);
|
||
}
|
||
|
||
m_arrayPrototype = new ArrayPrototypeObject(state);
|
||
m_arrayPrototype->setGlobalIntrinsicObject(state, true);
|
||
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().constructor), ObjectPropertyDescriptor(m_array, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
|
||
m_array->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().isArray),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().isArray, builtinArrayIsArray, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
|
||
m_array->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().from),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().from, builtinArrayFrom, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
|
||
m_array->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().of),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().of, builtinArrayOf, 0, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().concat),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().concat, builtinArrayConcat, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().forEach),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().forEach, builtinArrayForEach, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().indexOf),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().indexOf, builtinArrayIndexOf, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().lastIndexOf),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().lastIndexOf, builtinArrayLastIndexOf, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().join),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().join, builtinArrayJoin, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().sort),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().sort, builtinArraySort, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().splice),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().splice, builtinArraySplice, 2, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().slice),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().slice, builtinArraySlice, 2, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().every),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().every, builtinArrayEvery, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().fill),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().fill, builtinArrayFill, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().includes),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().includes, builtinArrayIncludes, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().filter),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().filter, builtinArrayFilter, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().reduce),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().reduce, builtinArrayReduce, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().reduceRight),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().reduceRight, builtinArrayReduceRight, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().pop),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().pop, builtinArrayPop, 0, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().push),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().push, builtinArrayPush, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().shift),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().shift, builtinArrayShift, 0, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().reverse),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().reverse, builtinArrayReverse, 0, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().toString),
|
||
ObjectPropertyDescriptor(m_arrayToString, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().map),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().map, builtinArrayMap, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().some),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().some, builtinArraySome, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().toLocaleString),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().toLocaleString, builtinArrayToLocaleString, 0, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().unshift),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().unshift, builtinArrayUnshift, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().keys),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().keys, builtinArrayKeys, 0, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().find),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().find, builtinArrayFind, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().findIndex),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().findIndex, builtinArrayFindIndex, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().copyWithin),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().copyWithin, builtinArrayCopyWithin, 2, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().flat),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().flat, builtinArrayFlat, 0, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().flatMap),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().flatMap, builtinArrayFlatMap, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().at),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().at, builtinArrayAt, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().findLast),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().findLast, builtinArrayFindLast, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().findLastIndex),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().findLastIndex, builtinArrayFindLastIndex, 1, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
|
||
Object* blackList = new Object(state, Object::PrototypeIsNull);
|
||
blackList->markThisObjectDontNeedStructureTransitionTable();
|
||
blackList->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().at), ObjectPropertyDescriptor(Value(true), ObjectPropertyDescriptor::AllPresent));
|
||
blackList->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().copyWithin), ObjectPropertyDescriptor(Value(true), ObjectPropertyDescriptor::AllPresent));
|
||
blackList->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().entries), ObjectPropertyDescriptor(Value(true), ObjectPropertyDescriptor::AllPresent));
|
||
blackList->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().fill), ObjectPropertyDescriptor(Value(true), ObjectPropertyDescriptor::AllPresent));
|
||
blackList->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().find), ObjectPropertyDescriptor(Value(true), ObjectPropertyDescriptor::AllPresent));
|
||
blackList->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().findLast), ObjectPropertyDescriptor(Value(true), ObjectPropertyDescriptor::AllPresent));
|
||
blackList->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().findLastIndex), ObjectPropertyDescriptor(Value(true), ObjectPropertyDescriptor::AllPresent));
|
||
blackList->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().findIndex), ObjectPropertyDescriptor(Value(true), ObjectPropertyDescriptor::AllPresent));
|
||
blackList->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().keys), ObjectPropertyDescriptor(Value(true), ObjectPropertyDescriptor::AllPresent));
|
||
blackList->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().values), ObjectPropertyDescriptor(Value(true), ObjectPropertyDescriptor::AllPresent));
|
||
blackList->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().includes), ObjectPropertyDescriptor(Value(true), ObjectPropertyDescriptor::AllPresent));
|
||
blackList->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().flat), ObjectPropertyDescriptor(Value(true), ObjectPropertyDescriptor::AllPresent));
|
||
blackList->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().flatMap), ObjectPropertyDescriptor(Value(true), ObjectPropertyDescriptor::AllPresent));
|
||
|
||
FunctionObject* values = new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().values, builtinArrayValues, 0, NativeFunctionInfo::Strict));
|
||
// Well-Known Intrinsic Objects : %ArrayProto_values%
|
||
// The initial value of the values data property of %ArrayPrototype%
|
||
m_arrayPrototypeValues = values;
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().values),
|
||
ObjectPropertyDescriptor(values, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().iterator),
|
||
ObjectPropertyDescriptor(values,
|
||
(ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().entries),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().entries, builtinArrayEntries, 0, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
|
||
m_arrayPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().unscopables),
|
||
ObjectPropertyDescriptor(blackList, ObjectPropertyDescriptor::ConfigurablePresent));
|
||
|
||
m_array->setFunctionPrototype(state, m_arrayPrototype);
|
||
|
||
m_arrayIteratorPrototype = new PrototypeObject(state, m_iteratorPrototype);
|
||
m_arrayIteratorPrototype->setGlobalIntrinsicObject(state, true);
|
||
|
||
m_arrayIteratorPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().next),
|
||
ObjectPropertyDescriptor(new NativeFunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().next, builtinArrayIteratorNext, 0, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
m_arrayIteratorPrototype->directDefineOwnProperty(state, ObjectPropertyName(state.context()->vmInstance()->globalSymbols().toStringTag),
|
||
ObjectPropertyDescriptor(Value(String::fromASCII("Array Iterator")), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
|
||
redefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().Array),
|
||
ObjectPropertyDescriptor(m_array, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent)));
|
||
}
|
||
} // namespace Escargot
|