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; }
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); }
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; }
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(); }
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); }
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); }