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); }
EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncAll(ExecState* exec) { // -- Promise.all(iterable) -- JSValue iterable = exec->argument(0); VM& vm = exec->vm(); // 1. Let 'C' be the this value. JSValue C = exec->thisValue(); // 2. Let 'deferred' be the result of calling GetDeferred(C). JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C); // 3. ReturnIfAbrupt(deferred). if (exec->hadException()) return JSValue::encode(jsUndefined()); // NOTE: A non-abrupt completion of createJSPromiseDeferredFromConstructor implies that // C and deferredValue are objects. JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue); // 4. Let 'iterator' be the result of calling GetIterator(iterable). JSValue iteratorFunction = iterable.get(exec, vm.propertyNames->iteratorSymbol); if (exec->hadException()) return JSValue::encode(abruptRejection(exec, deferred)); CallData iteratorFunctionCallData; CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData); if (iteratorFunctionCallType == CallTypeNone) { throwTypeError(exec); return JSValue::encode(abruptRejection(exec, deferred)); } ArgList iteratorFunctionArguments; JSValue iterator = call(exec, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments); // 5. RejectIfAbrupt(iterator, deferred). if (exec->hadException()) return JSValue::encode(abruptRejection(exec, deferred)); JSValue result = performPromiseAll(exec, iterator, C, deferred); if (exec->hadException()) { iteratorClose(exec, iterator); if (exec->hadException()) return JSValue::encode(abruptRejection(exec, deferred)); } return JSValue::encode(result); }
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 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); }