Ejemplo n.º 1
0
JSValue JSInjectedScriptHost::iteratorEntries(ExecState* exec)
{
    if (exec->argumentCount() < 1)
        return jsUndefined();

    VM& vm = exec->vm();
    JSValue iterator;
    JSValue value = exec->uncheckedArgument(0);
    if (JSMapIterator* mapIterator = jsDynamicCast<JSMapIterator*>(value))
        iterator = mapIterator->clone(exec);
    else if (JSSetIterator* setIterator = jsDynamicCast<JSSetIterator*>(value))
        iterator = setIterator->clone(exec);
    else if (JSStringIterator* stringIterator = jsDynamicCast<JSStringIterator*>(value))
        iterator = stringIterator->clone(exec);
    else if (JSPropertyNameIterator* propertyNameIterator = jsDynamicCast<JSPropertyNameIterator*>(value)) {
        iterator = propertyNameIterator->clone(exec);
        if (UNLIKELY(vm.exception()))
            return JSValue();
    } else {
        if (JSObject* iteratorObject = jsDynamicCast<JSObject*>(value)) {
            // Array Iterators are created in JS for performance reasons. Thus the only way to know we have one is to
            // look for a property that is unique to them.
            if (JSValue nextIndex = iteratorObject->getDirect(vm, vm.propertyNames->builtinNames().arrayIteratorNextIndexPrivateName()))
                iterator = cloneArrayIteratorObject(exec, vm, iteratorObject, nextIndex);
        }
    }
    if (!iterator)
        return jsUndefined();

    unsigned numberToFetch = 5;
    JSValue numberToFetchArg = exec->argument(1);
    double fetchDouble = numberToFetchArg.toInteger(exec);
    if (fetchDouble >= 0)
        numberToFetch = static_cast<unsigned>(fetchDouble);

    JSArray* array = constructEmptyArray(exec, nullptr);
    if (UNLIKELY(vm.exception()))
        return jsUndefined();

    for (unsigned i = 0; i < numberToFetch; ++i) {
        JSValue next = iteratorStep(exec, iterator);
        if (UNLIKELY(vm.exception()))
            break;
        if (next.isFalse())
            break;

        JSValue nextValue = iteratorValue(exec, next);
        if (UNLIKELY(vm.exception()))
            break;

        JSObject* entry = constructEmptyObject(exec);
        entry->putDirect(exec->vm(), Identifier::fromString(exec, "value"), nextValue);
        array->putDirectIndex(exec, i, entry);
    }

    iteratorClose(exec, iterator);

    return array;
}
Ejemplo n.º 2
0
static EncodedJSValue JSC_HOST_CALL constructWeakSet(ExecState* exec)
{
    JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject();
    Structure* weakSetStructure = globalObject->weakSetStructure();
    JSWeakSet* weakSet = JSWeakSet::create(exec, weakSetStructure);
    JSValue iterable = exec->argument(0);
    if (iterable.isUndefinedOrNull())
        return JSValue::encode(weakSet);

    JSValue adderFunction = weakSet->JSObject::get(exec, exec->propertyNames().add);
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    CallData adderFunctionCallData;
    CallType adderFunctionCallType = getCallData(adderFunction, adderFunctionCallData);
    if (adderFunctionCallType == CallTypeNone)
        return JSValue::encode(throwTypeError(exec));

    JSValue iteratorFunction = iterable.get(exec, exec->propertyNames().iteratorSymbol);
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    CallData iteratorFunctionCallData;
    CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData);
    if (iteratorFunctionCallType == CallTypeNone)
        return JSValue::encode(throwTypeError(exec));

    ArgList iteratorFunctionArguments;
    JSValue iterator = call(exec, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments);
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    if (!iterator.isObject())
        return JSValue::encode(throwTypeError(exec));

    while (true) {
        JSValue next = iteratorStep(exec, iterator);
        if (exec->hadException())
            return JSValue::encode(jsUndefined());

        if (next.isFalse())
            return JSValue::encode(weakSet);

        JSValue nextValue = iteratorValue(exec, next);
        if (exec->hadException())
            return JSValue::encode(jsUndefined());

        MarkedArgumentBuffer arguments;
        arguments.append(nextValue);
        call(exec, adderFunction, adderFunctionCallType, adderFunctionCallData, weakSet, arguments);
        if (exec->hadException()) {
            iteratorClose(exec, iterator);
            return JSValue::encode(jsUndefined());
        }
    }
    RELEASE_ASSERT_NOT_REACHED();
    return JSValue::encode(weakSet);
}
Ejemplo n.º 3
0
JSValue JSInjectedScriptHost::iteratorEntries(ExecState* exec)
{
    if (exec->argumentCount() < 1)
        return jsUndefined();

    JSValue iterator;
    JSValue value = exec->uncheckedArgument(0);
    if (JSArrayIterator* arrayIterator = jsDynamicCast<JSArrayIterator*>(value))
        iterator = arrayIterator->clone(exec);
    else if (JSMapIterator* mapIterator = jsDynamicCast<JSMapIterator*>(value))
        iterator = mapIterator->clone(exec);
    else if (JSSetIterator* setIterator = jsDynamicCast<JSSetIterator*>(value))
        iterator = setIterator->clone(exec);
    else if (JSStringIterator* stringIterator = jsDynamicCast<JSStringIterator*>(value))
        iterator = stringIterator->clone(exec);
    else if (JSPropertyNameIterator* propertyNameIterator = jsDynamicCast<JSPropertyNameIterator*>(value))
        iterator = propertyNameIterator->clone(exec);
    else
        return jsUndefined();

    unsigned numberToFetch = 5;
    JSValue numberToFetchArg = exec->argument(1);
    double fetchDouble = numberToFetchArg.toInteger(exec);
    if (fetchDouble >= 0)
        numberToFetch = static_cast<unsigned>(fetchDouble);

    JSArray* array = constructEmptyArray(exec, nullptr);

    for (unsigned i = 0; i < numberToFetch; ++i) {
        JSValue next = iteratorStep(exec, iterator);
        if (exec->hadException())
            break;
        if (next.isFalse())
            break;

        JSValue nextValue = iteratorValue(exec, next);
        if (exec->hadException())
            break;

        JSObject* entry = constructEmptyObject(exec);
        entry->putDirect(exec->vm(), Identifier::fromString(exec, "value"), nextValue);
        array->putDirectIndex(exec, i, entry);
    }

    iteratorClose(exec, iterator);

    return array;
}
Ejemplo n.º 4
0
static JSValue performPromiseAll(ExecState* exec, JSValue iterator, JSValue C, JSPromiseDeferred* deferred)
{
    JSObject* thisObject = asObject(C);
    VM& vm = exec->vm();

    // 6. Let 'values' be the result of calling ArrayCreate(0).
    JSArray* values = constructEmptyArray(exec, nullptr, thisObject->globalObject());

    // 7. Let 'countdownHolder' be Record { [[Countdown]]: 0 }.
    NumberObject* countdownHolder = constructNumber(exec, thisObject->globalObject(), JSValue(0));

    // 8. Let 'index' be 0.
    unsigned index = 0;

    // 9. Repeat.
    do {
        // i. Let 'next' be the result of calling IteratorStep(iterator).
        JSValue next = iteratorStep(exec, iterator);
        if (exec->hadException())
            return jsUndefined();

        // iii. If 'next' is false,
        if (next.isFalse()) {
            // a. If 'index' is 0,
            if (!index) {
                // a. Let 'resolveResult' be the result of calling the [[Call]] internal method
                //    of deferred.[[Resolve]] with undefined as thisArgument and a List containing
                //    values as argumentsList.
                performDeferredResolve(exec, deferred, values);

                // b. ReturnIfAbrupt(resolveResult).
                if (exec->hadException())
                    return jsUndefined();
            }

            // b. Return deferred.[[Promise]].
            return deferred->promise();
        }

        // iv. Let 'nextValue' be the result of calling IteratorValue(next).
        // v. RejectIfAbrupt(nextValue, deferred).
        JSValue nextValue = iteratorValue(exec, next);
        if (exec->hadException())
            return jsUndefined();

        values->push(exec, jsUndefined());

        // vi. Let 'nextPromise' be the result of calling Invoke(C, "resolve", (nextValue)).
        JSValue resolveFunction = C.get(exec, vm.propertyNames->resolve);
        if (exec->hadException())
            return jsUndefined();

        CallData resolveFunctionCallData;
        CallType resolveFunctionCallType = getCallData(resolveFunction, resolveFunctionCallData);
        if (resolveFunctionCallType == CallTypeNone) {
            throwTypeError(exec);
            return jsUndefined();
        }

        MarkedArgumentBuffer resolveFunctionArguments;
        resolveFunctionArguments.append(nextValue);
        JSValue nextPromise = call(exec, resolveFunction, resolveFunctionCallType, resolveFunctionCallData, C, resolveFunctionArguments);

        // vii. RejectIfAbrupt(nextPromise, deferred).
        if (exec->hadException())
            return jsUndefined();

        // viii. Let 'countdownFunction' be a new built-in function object as defined in Promise.all Countdown Functions.
        JSFunction* countdownFunction = createPromiseAllCountdownFunction(vm, thisObject->globalObject());

        // ix. Set the [[Index]] internal slot of 'countdownFunction' to 'index'.
        countdownFunction->putDirect(vm, vm.propertyNames->indexPrivateName, JSValue(index));

        // x. Set the [[Values]] internal slot of 'countdownFunction' to 'values'.
        countdownFunction->putDirect(vm, vm.propertyNames->valuesPrivateName, values);

        // xi. Set the [[Deferred]] internal slot of 'countdownFunction' to 'deferred'.
        countdownFunction->putDirect(vm, vm.propertyNames->deferredPrivateName, deferred);

        // xii. Set the [[CountdownHolder]] internal slot of 'countdownFunction' to 'countdownHolder'.
        countdownFunction->putDirect(vm, vm.propertyNames->countdownHolderPrivateName, countdownHolder);

        // xiii. Let 'result' be the result of calling Invoke(nextPromise, "then", (countdownFunction, deferred.[[Reject]])).
        JSValue thenFunction = nextPromise.get(exec, vm.propertyNames->then);
        if (exec->hadException())
            return jsUndefined();

        CallData thenFunctionCallData;
        CallType thenFunctionCallType = getCallData(thenFunction, thenFunctionCallData);
        if (thenFunctionCallType == CallTypeNone) {
            throwTypeError(exec);
            return jsUndefined();
        }

        MarkedArgumentBuffer thenFunctionArguments;
        thenFunctionArguments.append(countdownFunction);
        thenFunctionArguments.append(deferred->reject());

        call(exec, thenFunction, thenFunctionCallType, thenFunctionCallData, nextPromise, thenFunctionArguments);

        // xiv. RejectIfAbrupt(result, deferred).
        if (exec->hadException())
            return jsUndefined();

        // xv. Set index to index + 1.
        index++;

        // xvi. Set countdownHolder.[[Countdown]] to countdownHolder.[[Countdown]] + 1.
        uint32_t newCountdownValue = countdownHolder->internalValue().asUInt32() + 1;
        countdownHolder->setInternalValue(vm, JSValue(newCountdownValue));
    } while (true);
    ASSERT_NOT_REACHED();
    return jsUndefined();
}
Ejemplo n.º 5
0
static void performPromiseRaceLoop(ExecState* exec, JSValue iterator, JSPromiseDeferred* deferred, JSValue C)
{
    // 6. Repeat
    do {
        // i. Let 'next' be the result of calling IteratorStep(iterator).
        JSValue next = iteratorStep(exec, iterator);

        // ii. RejectIfAbrupt(next, deferred).
        if (exec->hadException())
            return;

        // iii. If 'next' is false, return deferred.[[Promise]].
        if (next.isFalse())
            return;

        // iv. Let 'nextValue' be the result of calling IteratorValue(next).
        // v. RejectIfAbrupt(nextValue, deferred).
        JSValue nextValue = iteratorValue(exec, next);
        if (exec->hadException())
            return;

        // vi. Let 'nextPromise' be the result of calling Invoke(C, "resolve", (nextValue)).
        JSValue resolveFunction = C.get(exec, exec->vm().propertyNames->resolve);
        if (exec->hadException())
            return;

        CallData resolveFunctionCallData;
        CallType resolveFunctionCallType = getCallData(resolveFunction, resolveFunctionCallData);
        if (resolveFunctionCallType == CallTypeNone) {
            throwTypeError(exec);
            return;
        }

        MarkedArgumentBuffer resolveFunctionArguments;
        resolveFunctionArguments.append(nextValue);
        JSValue nextPromise = call(exec, resolveFunction, resolveFunctionCallType, resolveFunctionCallData, C, resolveFunctionArguments);

        // vii. RejectIfAbrupt(nextPromise, deferred).
        if (exec->hadException())
            return;

        // viii. Let 'result' be the result of calling Invoke(nextPromise, "then", (deferred.[[Resolve]], deferred.[[Reject]])).
        JSValue thenFunction = nextPromise.get(exec, exec->vm().propertyNames->then);
        if (exec->hadException())
            return;

        CallData thenFunctionCallData;
        CallType thenFunctionCallType = getCallData(thenFunction, thenFunctionCallData);
        if (thenFunctionCallType == CallTypeNone) {
            throwTypeError(exec);
            return;
        }

        MarkedArgumentBuffer thenFunctionArguments;
        thenFunctionArguments.append(deferred->resolve());
        thenFunctionArguments.append(deferred->reject());

        call(exec, thenFunction, thenFunctionCallType, thenFunctionCallData, nextPromise, thenFunctionArguments);

        // ix. RejectIfAbrupt(result, deferred).
        if (exec->hadException())
            return;
    } while (true);
}
Ejemplo n.º 6
0
static EncodedJSValue JSC_HOST_CALL constructMap(ExecState* exec)
{
    JSValue prototype = JSValue();
    JSValue newTarget = exec->newTarget();

    if (newTarget != exec->callee())
        prototype = newTarget.get(exec, exec->propertyNames().prototype);

    JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject();
    Structure* mapStructure = Structure::createSubclassStructure(exec->vm(), globalObject->mapStructure(), prototype);
    JSMap* map = JSMap::create(exec, mapStructure);
    JSValue iterable = exec->argument(0);
    if (iterable.isUndefinedOrNull())
        return JSValue::encode(map);

    JSValue adderFunction = map->JSObject::get(exec, exec->propertyNames().set);
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    CallData adderFunctionCallData;
    CallType adderFunctionCallType = getCallData(adderFunction, adderFunctionCallData);
    if (adderFunctionCallType == CallTypeNone)
        return JSValue::encode(throwTypeError(exec));

    JSValue iteratorFunction = iterable.get(exec, exec->propertyNames().iteratorSymbol);
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    CallData iteratorFunctionCallData;
    CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData);
    if (iteratorFunctionCallType == CallTypeNone)
        return JSValue::encode(throwTypeError(exec));

    ArgList iteratorFunctionArguments;
    JSValue iterator = call(exec, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments);
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    if (!iterator.isObject())
        return JSValue::encode(throwTypeError(exec));

    while (true) {
        JSValue next = iteratorStep(exec, iterator);
        if (exec->hadException())
            return JSValue::encode(jsUndefined());

        if (next.isFalse())
            return JSValue::encode(map);

        JSValue nextItem = iteratorValue(exec, next);
        if (exec->hadException())
            return JSValue::encode(jsUndefined());

        if (!nextItem.isObject()) {
            throwTypeError(exec);
            iteratorClose(exec, iterator);
            return JSValue::encode(jsUndefined());
        }

        JSValue key = nextItem.get(exec, 0);
        if (exec->hadException()) {
            iteratorClose(exec, iterator);
            return JSValue::encode(jsUndefined());
        }

        JSValue value = nextItem.get(exec, 1);
        if (exec->hadException()) {
            iteratorClose(exec, iterator);
            return JSValue::encode(jsUndefined());
        }

        MarkedArgumentBuffer arguments;
        arguments.append(key);
        arguments.append(value);
        call(exec, adderFunction, adderFunctionCallType, adderFunctionCallData, map, arguments);
        if (exec->hadException()) {
            iteratorClose(exec, iterator);
            return JSValue::encode(jsUndefined());
        }
    }
    RELEASE_ASSERT_NOT_REACHED();
    return JSValue::encode(map);
}