static std::error_code getDomainList(ExecState& exec, const JSObject* arrayObject, Vector<String>& vector) { VM& vm = exec.vm(); auto scope = DECLARE_THROW_SCOPE(vm); ASSERT(vector.isEmpty()); if (!arrayObject || !isJSArray(arrayObject)) return ContentExtensionError::JSONInvalidDomainList; const JSArray* array = jsCast<const JSArray*>(arrayObject); unsigned length = array->length(); for (unsigned i = 0; i < length; ++i) { const JSValue value = array->getIndex(&exec, i); if (scope.exception() || !value.isString()) return ContentExtensionError::JSONInvalidDomainList; // Domains should be punycode encoded lower case. const String& domain = jsCast<JSString*>(value)->value(&exec); if (domain.isEmpty()) return ContentExtensionError::JSONInvalidDomainList; if (!containsOnlyASCIIWithNoUppercase(domain)) return ContentExtensionError::JSONDomainNotLowerCaseASCII; vector.append(domain); } return { }; }
bool JSLocation::getOwnPropertySlotDelegate(ExecState* exec, PropertyName propertyName, PropertySlot& slot) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); Frame* frame = wrapped().frame(); if (!frame) { slot.setUndefined(); return true; } // When accessing Location cross-domain, functions are always the native built-in ones. // See JSDOMWindow::getOwnPropertySlotDelegate for additional details. // Our custom code is only needed to implement the Window cross-domain scheme, so if access is // allowed, return false so the normal lookup will take place. String message; if (shouldAllowAccessToFrame(exec, frame, message)) return false; // We only allow access to Location.replace() cross origin. // Make it read-only / non-configurable to prevent writes via defineProperty. if (propertyName == exec->propertyNames().replace) { slot.setCustom(this, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsLocationInstanceFunctionReplace, 1>); return true; } throwSecurityError(*exec, scope, message); slot.setUndefined(); return true; }
JSValue IntlNumberFormat::formatNumber(ExecState& state, double number) { VM& vm = state.vm(); auto scope = DECLARE_THROW_SCOPE(vm); // 11.3.4 FormatNumber abstract operation (ECMA-402 2.0) if (!m_initializedNumberFormat) return throwTypeError(&state, scope, "Intl.NumberFormat.prototype.format called on value that's not an object initialized as a NumberFormat"_s); // Map negative zero to positive zero. if (!number) number = 0.0; UErrorCode status = U_ZERO_ERROR; Vector<UChar, 32> buffer(32); auto length = unum_formatDouble(m_numberFormat.get(), number, buffer.data(), buffer.size(), nullptr, &status); if (status == U_BUFFER_OVERFLOW_ERROR) { buffer.grow(length); status = U_ZERO_ERROR; unum_formatDouble(m_numberFormat.get(), number, buffer.data(), length, nullptr, &status); } if (U_FAILURE(status)) return throwException(&state, scope, createError(&state, "Failed to format a number."_s)); return jsString(&state, String(buffer.data(), length)); }
bool JSDOMWindow::preventExtensions(JSObject*, ExecState* exec) { auto scope = DECLARE_THROW_SCOPE(exec->vm()); throwTypeError(exec, scope, ASCIILiteral("Cannot prevent extensions on this object")); return false; }
static EncodedJSValue JSC_HOST_CALL constructWeakSet(ExecState* exec) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSGlobalObject* globalObject = asInternalFunction(exec->jsCallee())->globalObject(); Structure* weakSetStructure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), globalObject->weakSetStructure()); RETURN_IF_EXCEPTION(scope, encodedJSValue()); JSWeakSet* weakSet = JSWeakSet::create(exec, weakSetStructure); JSValue iterable = exec->argument(0); if (iterable.isUndefinedOrNull()) return JSValue::encode(weakSet); JSValue adderFunction = weakSet->JSObject::get(exec, vm.propertyNames->add); RETURN_IF_EXCEPTION(scope, encodedJSValue()); CallData adderFunctionCallData; CallType adderFunctionCallType = getCallData(adderFunction, adderFunctionCallData); if (adderFunctionCallType == CallType::None) return JSValue::encode(throwTypeError(exec, scope)); scope.release(); forEachInIterable(exec, iterable, [&](VM&, ExecState* exec, JSValue nextValue) { MarkedArgumentBuffer arguments; arguments.append(nextValue); call(exec, adderFunction, adderFunctionCallType, adderFunctionCallData, weakSet, arguments); }); return JSValue::encode(weakSet); }
static void exportKey(ExecState& state, CryptoKeyFormat keyFormat, const CryptoKey& key, CryptoAlgorithm::VectorCallback callback, CryptoAlgorithm::VoidCallback failureCallback) { VM& vm = state.vm(); auto scope = DECLARE_THROW_SCOPE(vm); if (!key.extractable()) { throwTypeError(&state, scope, ASCIILiteral("Key is not extractable")); return; } switch (keyFormat) { case CryptoKeyFormat::Raw: { Vector<uint8_t> result; if (CryptoKeySerializationRaw::serialize(key, result)) callback(result); else failureCallback(); break; } case CryptoKeyFormat::JWK: { String result = JSCryptoKeySerializationJWK::serialize(&state, key); RETURN_IF_EXCEPTION(scope, void()); CString utf8String = result.utf8(StrictConversion); Vector<uint8_t> resultBuffer; resultBuffer.append(utf8String.data(), utf8String.length()); callback(resultBuffer); break; } default: throwTypeError(&state, scope, ASCIILiteral("Unsupported key format for export")); break; } }
JSValue Database::toJS(ExecState* exec) const { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSObject* result = constructEmptyObject(exec); JSArray* bytecodes = constructEmptyArray(exec, 0); RETURN_IF_EXCEPTION(scope, JSValue()); for (unsigned i = 0; i < m_bytecodes.size(); ++i) bytecodes->putDirectIndex(exec, i, m_bytecodes[i].toJS(exec)); result->putDirect(vm, exec->propertyNames().bytecodes, bytecodes); JSArray* compilations = constructEmptyArray(exec, 0); RETURN_IF_EXCEPTION(scope, JSValue()); for (unsigned i = 0; i < m_compilations.size(); ++i) compilations->putDirectIndex(exec, i, m_compilations[i]->toJS(exec)); result->putDirect(vm, exec->propertyNames().compilations, compilations); JSArray* events = constructEmptyArray(exec, 0); RETURN_IF_EXCEPTION(scope, JSValue()); for (unsigned i = 0; i < m_events.size(); ++i) events->putDirectIndex(exec, i, m_events[i].toJS(exec)); result->putDirect(vm, exec->propertyNames().events, events); return result; }
EncodedJSValue JSC_HOST_CALL webAssemblyModuleCustomSections(ExecState* exec) { VM& vm = exec->vm(); auto* globalObject = exec->lexicalGlobalObject(); auto throwScope = DECLARE_THROW_SCOPE(vm); JSWebAssemblyModule* module = jsDynamicCast<JSWebAssemblyModule*>(vm, exec->argument(0)); if (!module) return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, "WebAssembly.Module.customSections called with non WebAssembly.Module argument"_s))); const String sectionNameString = exec->argument(1).getString(exec); RETURN_IF_EXCEPTION(throwScope, { }); JSArray* result = constructEmptyArray(exec, nullptr, globalObject); RETURN_IF_EXCEPTION(throwScope, { }); const auto& customSections = module->moduleInformation().customSections; for (const Wasm::CustomSection& section : customSections) { if (String::fromUTF8(section.name) == sectionNameString) { auto buffer = ArrayBuffer::tryCreate(section.payload.data(), section.payload.size()); if (!buffer) return JSValue::encode(throwException(exec, throwScope, createOutOfMemoryError(exec))); result->push(exec, JSArrayBuffer::create(vm, globalObject->arrayBufferStructure(ArrayBufferSharingMode::Default), WTFMove(buffer))); RETURN_IF_EXCEPTION(throwScope, { }); } } return JSValue::encode(result); }
EncodedJSValue JSC_HOST_CALL webAssemblyModuleImports(ExecState* exec) { VM& vm = exec->vm(); auto* globalObject = exec->lexicalGlobalObject(); auto throwScope = DECLARE_THROW_SCOPE(vm); JSWebAssemblyModule* module = jsDynamicCast<JSWebAssemblyModule*>(vm, exec->argument(0)); if (!module) return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, "WebAssembly.Module.imports called with non WebAssembly.Module argument"_s))); JSArray* result = constructEmptyArray(exec, nullptr, globalObject); RETURN_IF_EXCEPTION(throwScope, { }); const auto& imports = module->moduleInformation().imports; if (imports.size()) { Identifier module = Identifier::fromString(exec, "module"); Identifier name = Identifier::fromString(exec, "name"); Identifier kind = Identifier::fromString(exec, "kind"); for (const Wasm::Import& imp : imports) { JSObject* obj = constructEmptyObject(exec); RETURN_IF_EXCEPTION(throwScope, { }); obj->putDirect(vm, module, jsString(exec, String::fromUTF8(imp.module))); obj->putDirect(vm, name, jsString(exec, String::fromUTF8(imp.field))); obj->putDirect(vm, kind, jsString(exec, String(makeString(imp.kind)))); result->push(exec, obj); RETURN_IF_EXCEPTION(throwScope, { }); } } return JSValue::encode(result); }
EncodedJSValue JSC_HOST_CALL constructJSWorker(ExecState& exec) { VM& vm = exec.vm(); auto scope = DECLARE_THROW_SCOPE(vm); DOMConstructorObject* jsConstructor = jsCast<DOMConstructorObject*>(exec.callee()); if (!exec.argumentCount()) return throwVMError(&exec, scope, createNotEnoughArgumentsError(&exec)); String scriptURL = exec.uncheckedArgument(0).toWTFString(&exec); if (exec.hadException()) return JSValue::encode(JSValue()); // See section 4.8.2 step 14 of WebWorkers for why this is the lexicalGlobalObject. DOMWindow& window = asJSDOMWindow(exec.lexicalGlobalObject())->wrapped(); ExceptionCode ec = 0; ASSERT(window.document()); RefPtr<Worker> worker = Worker::create(*window.document(), scriptURL, ec); if (ec) { setDOMException(&exec, ec); return JSValue::encode(JSValue()); } return JSValue::encode(toJSNewlyCreated(&exec, jsConstructor->globalObject(), WTFMove(worker))); }
JSValue ScriptFunctionCall::call(bool& hadException) { JSObject* thisObject = m_thisObject.jsObject(); VM& vm = m_exec->vm(); JSLockHolder lock(vm); auto scope = DECLARE_THROW_SCOPE(vm); JSValue function = thisObject->get(m_exec, Identifier::fromString(m_exec, m_name)); if (UNLIKELY(scope.exception())) { hadException = true; return { }; } CallData callData; CallType callType = getCallData(function, callData); if (callType == CallType::None) return { }; JSValue result; NakedPtr<Exception> exception; if (m_callHandler) result = m_callHandler(m_exec, function, callType, callData, thisObject, m_arguments, exception); else result = JSC::call(m_exec, function, callType, callData, thisObject, m_arguments, exception); if (exception) { // Do not treat a terminated execution exception as having an exception. Just treat it as an empty result. hadException = !isTerminatedExecutionException(exception); return { }; } return result; }
bool JSStorage::putDelegate(ExecState* state, PropertyName propertyName, JSValue value, PutPropertySlot&, bool& putResult) { VM& vm = state->vm(); auto scope = DECLARE_THROW_SCOPE(vm); // Only perform the custom put if the object doesn't have a native property by this name. // Since hasProperty() would end up calling canGetItemsForName() and be fooled, we need to check // the native property slots manually. PropertySlot slot { this, PropertySlot::InternalMethodType::GetOwnProperty }; JSValue prototype = this->getPrototypeDirect(); if (prototype.isObject() && asObject(prototype)->getPropertySlot(state, propertyName, slot)) return false; if (propertyName.isSymbol()) return false; String stringValue = value.toWTFString(state); RETURN_IF_EXCEPTION(scope, true); auto setItemResult = wrapped().setItem(propertyNameToString(propertyName), stringValue); if (setItemResult.hasException()) { propagateException(*state, scope, setItemResult.releaseException()); return true; } putResult = true; return true; }
static EncodedJSValue JSC_HOST_CALL constructArrayBuffer(ExecState* exec) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSArrayBufferConstructor* constructor = jsCast<JSArrayBufferConstructor*>(exec->jsCallee()); unsigned length; if (exec->argumentCount()) { length = exec->uncheckedArgument(0).toIndex(exec, "length"); RETURN_IF_EXCEPTION(scope, encodedJSValue()); } else { // Although the documentation doesn't say so, it is in fact correct to say // "new ArrayBuffer()". The result is the same as allocating an array buffer // with a zero length. length = 0; } auto buffer = ArrayBuffer::tryCreate(length, 1); if (!buffer) return JSValue::encode(throwOutOfMemoryError(exec, scope)); if (constructor->sharingMode() == ArrayBufferSharingMode::Shared) buffer->makeShared(); ASSERT(constructor->sharingMode() == buffer->sharingMode()); Structure* arrayBufferStructure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), constructor->globalObject()->arrayBufferStructure(constructor->sharingMode())); RETURN_IF_EXCEPTION(scope, encodedJSValue()); JSArrayBuffer* result = JSArrayBuffer::create(vm, arrayBufferStructure, WTFMove(buffer)); return JSValue::encode(result); }
static std::error_code getTypeFlags(ExecState& exec, const JSValue& typeValue, ResourceFlags& flags, uint16_t (*stringToType)(const String&)) { VM& vm = exec.vm(); auto scope = DECLARE_THROW_SCOPE(vm); if (!typeValue.isObject()) return { }; const JSObject* object = typeValue.toObject(&exec); ASSERT(!scope.exception()); if (!isJSArray(object)) return ContentExtensionError::JSONInvalidTriggerFlagsArray; const JSArray* array = jsCast<const JSArray*>(object); unsigned length = array->length(); for (unsigned i = 0; i < length; ++i) { const JSValue value = array->getIndex(&exec, i); if (scope.exception() || !value) return ContentExtensionError::JSONInvalidObjectInTriggerFlagsArray; String name = value.toWTFString(&exec); uint16_t type = stringToType(name); if (!type) return ContentExtensionError::JSONInvalidStringInTriggerFlagsArray; flags |= type; } return { }; }
JSValue IntlDateTimeFormat::format(ExecState& exec, double value) { VM& vm = exec.vm(); auto scope = DECLARE_THROW_SCOPE(vm); // 12.3.4 FormatDateTime abstract operation (ECMA-402 2.0) if (!m_initializedDateTimeFormat) { initializeDateTimeFormat(exec, jsUndefined(), jsUndefined()); ASSERT(!scope.exception()); } // 1. If x is not a finite Number, then throw a RangeError exception. if (!std::isfinite(value)) return throwRangeError(&exec, scope, ASCIILiteral("date value is not finite in DateTimeFormat format()")); // Delegate remaining steps to ICU. UErrorCode status = U_ZERO_ERROR; Vector<UChar, 32> result(32); auto resultLength = udat_format(m_dateFormat.get(), value, result.data(), result.size(), nullptr, &status); if (status == U_BUFFER_OVERFLOW_ERROR) { status = U_ZERO_ERROR; result.grow(resultLength); udat_format(m_dateFormat.get(), value, result.data(), resultLength, nullptr, &status); } if (U_FAILURE(status)) return throwTypeError(&exec, scope, ASCIILiteral("failed to format date value")); return jsString(&exec, String(result.data(), resultLength)); }
// HTMLAllCollections are strange objects, they support both get and call. static EncodedJSValue JSC_HOST_CALL callHTMLAllCollection(ExecState* exec) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); if (exec->argumentCount() < 1) return JSValue::encode(jsUndefined()); // Do not use thisObj here. It can be the JSHTMLDocument, in the document.forms(i) case. JSHTMLAllCollection* jsCollection = jsCast<JSHTMLAllCollection*>(exec->callee()); HTMLAllCollection& collection = jsCollection->wrapped(); // Also, do we need the TypeError test here ? if (exec->argumentCount() == 1) { // Support for document.all(<index>) etc. String string = exec->argument(0).toString(exec)->value(exec); RETURN_IF_EXCEPTION(scope, encodedJSValue()); if (Optional<uint32_t> index = parseIndex(*string.impl())) return JSValue::encode(toJS(exec, jsCollection->globalObject(), collection.item(index.value()))); // Support for document.images('<name>') etc. return JSValue::encode(namedItems(*exec, jsCollection, Identifier::fromString(exec, string))); } // The second arg, if set, is the index of the item we want String string = exec->argument(0).toString(exec)->value(exec); RETURN_IF_EXCEPTION(scope, encodedJSValue()); if (Optional<uint32_t> index = parseIndex(*exec->argument(1).toWTFString(exec).impl())) { if (auto* item = collection.namedItemWithIndex(string, index.value())) return JSValue::encode(toJS(exec, jsCollection->globalObject(), *item)); } return JSValue::encode(jsUndefined()); }
JSValue JSWebKitSubtleCrypto::digest(ExecState& state) { VM& vm = state.vm(); auto scope = DECLARE_THROW_SCOPE(vm); if (state.argumentCount() < 2) return throwException(&state, scope, createNotEnoughArgumentsError(&state)); auto algorithm = createAlgorithmFromJSValue(state, scope, state.uncheckedArgument(0)); RETURN_IF_EXCEPTION(scope, { }); auto parameters = JSCryptoAlgorithmDictionary::createParametersForDigest(state, scope, algorithm->identifier(), state.uncheckedArgument(0)); RETURN_IF_EXCEPTION(scope, { }); auto data = cryptoOperationDataFromJSValue(state, scope, state.uncheckedArgument(1)); RETURN_IF_EXCEPTION(scope, { }); RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow()); auto promise = wrapper->promise(); auto successCallback = [wrapper](const Vector<uint8_t>& result) mutable { fulfillPromiseWithArrayBuffer(wrapper.releaseNonNull(), result.data(), result.size()); }; auto failureCallback = [wrapper]() mutable { wrapper->reject(); // FIXME: This should reject with an Exception. }; auto result = algorithm->digest(*parameters, data, WTFMove(successCallback), WTFMove(failureCallback)); if (result.hasException()) { propagateException(state, scope, result.releaseException()); return { }; } return promise; }
EncodedJSValue JSC_HOST_CALL IntlCollatorPrototypeGetterCompare(ExecState* state) { VM& vm = state->vm(); auto scope = DECLARE_THROW_SCOPE(vm); // 10.3.3 Intl.Collator.prototype.compare (ECMA-402 2.0) // 1. Let collator be this Collator object. IntlCollator* collator = jsDynamicCast<IntlCollator*>(state->thisValue()); if (!collator) return JSValue::encode(throwTypeError(state, scope, ASCIILiteral("Intl.Collator.prototype.compare called on value that's not an object initialized as a Collator"))); JSBoundFunction* boundCompare = collator->boundCompare(); // 2. If collator.[[boundCompare]] is undefined, if (!boundCompare) { JSGlobalObject* globalObject = collator->globalObject(); // a. Let F be a new built-in function object as defined in 11.3.4. // b. The value of F’s length property is 2. JSFunction* targetObject = JSFunction::create(vm, globalObject, 2, ASCIILiteral("compare"), IntlCollatorFuncCompare, NoIntrinsic); // c. Let bc be BoundFunctionCreate(F, «this value»). boundCompare = JSBoundFunction::create(vm, state, globalObject, targetObject, collator, nullptr, 2, ASCIILiteral("compare")); RETURN_IF_EXCEPTION(scope, encodedJSValue()); // d. Set collator.[[boundCompare]] to bc. collator->setBoundCompare(vm, boundCompare); } // 3. Return collator.[[boundCompare]]. return JSValue::encode(boundCompare); }
JSValue JSWebKitSubtleCrypto::exportKey(ExecState& state) { VM& vm = state.vm(); auto scope = DECLARE_THROW_SCOPE(vm); if (state.argumentCount() < 2) return throwException(&state, scope, createNotEnoughArgumentsError(&state)); auto keyFormat = cryptoKeyFormatFromJSValue(state, scope, state.uncheckedArgument(0)); RETURN_IF_EXCEPTION(scope, { }); RefPtr<CryptoKey> key = JSCryptoKey::toWrapped(vm, state.uncheckedArgument(1)); if (!key) return throwTypeError(&state, scope); RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow()); auto promise = wrapper->promise(); auto successCallback = [wrapper](const Vector<uint8_t>& result) mutable { fulfillPromiseWithArrayBuffer(wrapper.releaseNonNull(), result.data(), result.size()); }; auto failureCallback = [wrapper]() mutable { wrapper->reject(); // FIXME: This should reject with an Exception. }; WebCore::exportKey(state, keyFormat, *key, WTFMove(successCallback), WTFMove(failureCallback)); RETURN_IF_EXCEPTION(scope, JSValue()); return promise; }
static EncodedJSValue JSC_HOST_CALL IntlCollatorFuncCompare(ExecState* state) { VM& vm = state->vm(); auto scope = DECLARE_THROW_SCOPE(vm); // 10.3.4 Collator Compare Functions (ECMA-402 2.0) // 1. Let collator be the this value. // 2. Assert: Type(collator) is Object and collator has an [[initializedCollator]] internal slot whose value is true. IntlCollator* collator = jsCast<IntlCollator*>(state->thisValue()); // 3. If x is not provided, let x be undefined. // 4. If y is not provided, let y be undefined. // 5. Let X be ToString(x). JSString* x = state->argument(0).toString(state); // 6. ReturnIfAbrupt(X). RETURN_IF_EXCEPTION(scope, encodedJSValue()); // 7. Let Y be ToString(y). JSString* y = state->argument(1).toString(state); // 8. ReturnIfAbrupt(Y). RETURN_IF_EXCEPTION(scope, encodedJSValue()); // 9. Return CompareStrings(collator, X, Y). auto xViewWithString = x->viewWithUnderlyingString(*state); RETURN_IF_EXCEPTION(scope, encodedJSValue()); auto yViewWithString = y->viewWithUnderlyingString(*state); RETURN_IF_EXCEPTION(scope, encodedJSValue()); scope.release(); return JSValue::encode(collator->compareStrings(*state, xViewWithString.view, yViewWithString.view)); }
ModuleProgramExecutable* ModuleProgramExecutable::create(ExecState* exec, const SourceCode& source) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSGlobalObject* globalObject = exec->lexicalGlobalObject(); ModuleProgramExecutable* executable = new (NotNull, allocateCell<ModuleProgramExecutable>(*exec->heap())) ModuleProgramExecutable(exec, source); executable->finishCreation(exec->vm()); ParserError error; DebuggerMode debuggerMode = globalObject->hasInteractiveDebugger() ? DebuggerOn : DebuggerOff; UnlinkedModuleProgramCodeBlock* unlinkedModuleProgramCode = vm.codeCache()->getUnlinkedModuleProgramCodeBlock( vm, executable, executable->source(), debuggerMode, error); if (globalObject->hasDebugger()) globalObject->debugger()->sourceParsed(exec, executable->source().provider(), error.line(), error.message()); if (error.isValid()) { throwVMError(exec, scope, error.toErrorObject(globalObject, executable->source())); return nullptr; } executable->m_unlinkedModuleProgramCodeBlock.set(exec->vm(), executable, unlinkedModuleProgramCode); executable->m_moduleEnvironmentSymbolTable.set(exec->vm(), executable, jsCast<SymbolTable*>(unlinkedModuleProgramCode->constantRegister(unlinkedModuleProgramCode->moduleEnvironmentSymbolTableConstantRegisterOffset()).get())->cloneScopePart(exec->vm())); return executable; }
IterationRecord iteratorForIterable(ExecState* state, JSValue iterable) { VM& vm = state->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSValue iteratorFunction = iterable.get(state, vm.propertyNames->iteratorSymbol); RETURN_IF_EXCEPTION(scope, { }); CallData iteratorFunctionCallData; CallType iteratorFunctionCallType = getCallData(vm, iteratorFunction, iteratorFunctionCallData); if (iteratorFunctionCallType == CallType::None) { throwTypeError(state, scope); return { }; } ArgList iteratorFunctionArguments; JSValue iterator = call(state, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments); RETURN_IF_EXCEPTION(scope, { }); if (!iterator.isObject()) { throwTypeError(state, scope); return { }; } JSValue nextMethod = iterator.getObject()->get(state, vm.propertyNames->next); RETURN_IF_EXCEPTION(scope, { }); return { iterator, nextMethod }; }
EncodedJSValue JSC_HOST_CALL mathProtoFuncHypot(ExecState* exec) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); unsigned argsCount = exec->argumentCount(); double max = 0; Vector<double, 8> args; args.reserveInitialCapacity(argsCount); for (unsigned i = 0; i < argsCount; ++i) { args.uncheckedAppend(exec->uncheckedArgument(i).toNumber(exec)); RETURN_IF_EXCEPTION(scope, encodedJSValue()); if (std::isinf(args[i])) return JSValue::encode(jsDoubleNumber(+std::numeric_limits<double>::infinity())); max = std::max(fabs(args[i]), max); } if (!max) max = 1; // Kahan summation algorithm significantly reduces the numerical error in the total obtained. double sum = 0; double compensation = 0; for (double argument : args) { double scaledArgument = argument / max; double summand = scaledArgument * scaledArgument - compensation; double preliminary = sum + summand; compensation = (preliminary - sum) - summand; sum = preliminary; } return JSValue::encode(jsDoubleNumber(sqrt(sum) * max)); }
JSValue iteratorNext(ExecState* exec, IterationRecord iterationRecord, JSValue argument) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSValue iterator = iterationRecord.iterator; JSValue nextFunction = iterationRecord.nextMethod; CallData nextFunctionCallData; CallType nextFunctionCallType = getCallData(vm, nextFunction, nextFunctionCallData); if (nextFunctionCallType == CallType::None) return throwTypeError(exec, scope); MarkedArgumentBuffer nextFunctionArguments; if (!argument.isEmpty()) nextFunctionArguments.append(argument); ASSERT(!nextFunctionArguments.hasOverflowed()); JSValue result = call(exec, nextFunction, nextFunctionCallType, nextFunctionCallData, iterator, nextFunctionArguments); RETURN_IF_EXCEPTION(scope, JSValue()); if (!result.isObject()) return throwTypeError(exec, scope, "Iterator result interface is not an object."_s); return result; }
static JSArray* getJSListenerFunctions(ExecState& state, Document* document, const EventListenerInfo& listenerInfo) { VM& vm = state.vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSArray* result = constructEmptyArray(&state, nullptr); RETURN_IF_EXCEPTION(scope, nullptr); size_t handlersCount = listenerInfo.eventListenerVector.size(); for (size_t i = 0, outputIndex = 0; i < handlersCount; ++i) { const JSEventListener* jsListener = JSEventListener::cast(&listenerInfo.eventListenerVector[i]->callback()); if (!jsListener) { ASSERT_NOT_REACHED(); continue; } // Hide listeners from other contexts. if (&jsListener->isolatedWorld() != ¤tWorld(&state)) continue; JSObject* function = jsListener->jsFunction(document); if (!function) continue; JSObject* listenerEntry = constructEmptyObject(&state); listenerEntry->putDirect(vm, Identifier::fromString(&state, "listener"), function); listenerEntry->putDirect(vm, Identifier::fromString(&state, "useCapture"), jsBoolean(listenerInfo.eventListenerVector[i]->useCapture())); result->putDirectIndex(&state, outputIndex++, JSValue(listenerEntry)); } return result; }
// Based on ErrorPrototype's errorProtoFuncToString(), but is modified to // have no observable side effects to the user (i.e. does not call proxies, // and getters). String ErrorInstance::sanitizedToString(ExecState* exec) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSValue nameValue; auto namePropertName = vm.propertyNames->name; PropertySlot nameSlot(this, PropertySlot::InternalMethodType::VMInquiry); JSValue currentObj = this; unsigned prototypeDepth = 0; // We only check the current object and its prototype (2 levels) because normal // Error objects may have a name property, and if not, its prototype should have // a name property for the type of error e.g. "SyntaxError". while (currentObj.isCell() && prototypeDepth++ < 2) { JSObject* obj = jsCast<JSObject*>(currentObj); if (JSObject::getOwnPropertySlot(obj, exec, namePropertName, nameSlot) && nameSlot.isValue()) { nameValue = nameSlot.getValue(exec, namePropertName); break; } currentObj = obj->getPrototypeDirect(); } ASSERT(!scope.exception()); String nameString; if (!nameValue) nameString = ASCIILiteral("Error"); else { nameString = nameValue.toWTFString(exec); RETURN_IF_EXCEPTION(scope, String()); } JSValue messageValue; auto messagePropertName = vm.propertyNames->message; PropertySlot messageSlot(this, PropertySlot::InternalMethodType::VMInquiry); if (JSObject::getOwnPropertySlot(this, exec, messagePropertName, messageSlot) && messageSlot.isValue()) messageValue = messageSlot.getValue(exec, messagePropertName); ASSERT(!scope.exception()); String messageString; if (!messageValue) messageString = String(); else { messageString = messageValue.toWTFString(exec); RETURN_IF_EXCEPTION(scope, String()); } if (!nameString.length()) return messageString; if (!messageString.length()) return nameString; StringBuilder builder; builder.append(nameString); builder.appendLiteral(": "); builder.append(messageString); return builder.toString(); }
bool JSLocation::putDelegate(ExecState* exec, PropertyName propertyName, JSValue, PutPropertySlot&, bool& putResult) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); putResult = false; Frame* frame = wrapped().frame(); if (!frame) return true; if (propertyName == exec->propertyNames().toString || propertyName == exec->propertyNames().valueOf) return true; String errorMessage; if (shouldAllowAccessToFrame(exec, frame, errorMessage)) return false; // Cross-domain access to the location is allowed when assigning the whole location, // but not when assigning the individual pieces, since that might inadvertently // disclose other parts of the original location. if (propertyName != exec->propertyNames().href) { throwSecurityError(*exec, scope, errorMessage); return true; } return false; }
JSObject* IntlCollator::resolvedOptions(ExecState& state) { VM& vm = state.vm(); auto scope = DECLARE_THROW_SCOPE(vm); // 10.3.5 Intl.Collator.prototype.resolvedOptions() (ECMA-402 2.0) // The function returns a new object whose properties and attributes are set as if // constructed by an object literal assigning to each of the following properties the // value of the corresponding internal slot of this Collator object (see 10.4): locale, // usage, sensitivity, ignorePunctuation, collation, as well as those properties shown // in Table 1 whose keys are included in the %Collator%[[relevantExtensionKeys]] // internal slot of the standard built-in object that is the initial value of // Intl.Collator. if (!m_initializedCollator) { initializeCollator(state, jsUndefined(), jsUndefined()); ASSERT_UNUSED(scope, !scope.exception()); } JSObject* options = constructEmptyObject(&state); options->putDirect(vm, vm.propertyNames->locale, jsString(&state, m_locale)); options->putDirect(vm, vm.propertyNames->usage, jsNontrivialString(&state, ASCIILiteral(usageString(m_usage)))); options->putDirect(vm, vm.propertyNames->sensitivity, jsNontrivialString(&state, ASCIILiteral(sensitivityString(m_sensitivity)))); options->putDirect(vm, vm.propertyNames->ignorePunctuation, jsBoolean(m_ignorePunctuation)); options->putDirect(vm, vm.propertyNames->collation, jsString(&state, m_collation)); options->putDirect(vm, vm.propertyNames->numeric, jsBoolean(m_numeric)); return options; }
JSValue JSDocument::getCSSCanvasContext(JSC::ExecState& state) { VM& vm = state.vm(); auto scope = DECLARE_THROW_SCOPE(vm); if (UNLIKELY(state.argumentCount() < 4)) return throwException(&state, scope, createNotEnoughArgumentsError(&state)); auto contextId = state.uncheckedArgument(0).toWTFString(&state); if (UNLIKELY(state.hadException())) return jsUndefined(); auto name = state.uncheckedArgument(1).toWTFString(&state); if (UNLIKELY(state.hadException())) return jsUndefined(); auto width = convert<int32_t>(state, state.uncheckedArgument(2), NormalConversion); if (UNLIKELY(state.hadException())) return jsUndefined(); auto height = convert<int32_t>(state, state.uncheckedArgument(3), NormalConversion); if (UNLIKELY(state.hadException())) return jsUndefined(); auto* context = wrapped().getCSSCanvasContext(WTFMove(contextId), WTFMove(name), WTFMove(width), WTFMove(height)); if (!context) return jsNull(); #if ENABLE(WEBGL) if (is<WebGLRenderingContextBase>(*context)) return toJS(&state, globalObject(), downcast<WebGLRenderingContextBase>(*context)); #endif return toJS(&state, globalObject(), downcast<CanvasRenderingContext2D>(*context)); }
EncodedJSValue JSC_HOST_CALL moduleLoaderPrototypeParseModule(ExecState* exec) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); const Identifier moduleKey = exec->argument(0).toPropertyKey(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); String source = exec->argument(1).toString(exec)->value(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); SourceCode sourceCode = makeSource(source, moduleKey.impl()); CodeProfiling profile(sourceCode); ParserError error; std::unique_ptr<ModuleProgramNode> moduleProgramNode = parse<ModuleProgramNode>( &vm, sourceCode, Identifier(), JSParserBuiltinMode::NotBuiltin, JSParserStrictMode::Strict, JSParserCommentMode::Module, SourceParseMode::ModuleAnalyzeMode, SuperBinding::NotNeeded, error); if (error.isValid()) { throwVMError(exec, scope, error.toErrorObject(exec->lexicalGlobalObject(), sourceCode)); return JSValue::encode(jsUndefined()); } ASSERT(moduleProgramNode); ModuleAnalyzer moduleAnalyzer(exec, moduleKey, sourceCode, moduleProgramNode->varDeclarations(), moduleProgramNode->lexicalVariables()); JSModuleRecord* moduleRecord = moduleAnalyzer.analyze(*moduleProgramNode); return JSValue::encode(moduleRecord); }