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); RETURN_IF_EXCEPTION(scope, encodedJSValue()); auto* jsSourceCode = jsDynamicCast<JSSourceCode*>(vm, exec->argument(1)); if (!jsSourceCode) return throwVMTypeError(exec, scope); SourceCode sourceCode = jsSourceCode->sourceCode(); CodeProfiling profile(sourceCode); ParserError error; std::unique_ptr<ModuleProgramNode> moduleProgramNode = parse<ModuleProgramNode>( &vm, sourceCode, Identifier(), JSParserBuiltinMode::NotBuiltin, JSParserStrictMode::Strict, JSParserScriptMode::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()); RETURN_IF_EXCEPTION(scope, encodedJSValue()); JSModuleRecord* moduleRecord = moduleAnalyzer.analyze(*moduleProgramNode); return JSValue::encode(moduleRecord); }
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); }
JSValue iteratorForIterable(ExecState* state, JSValue iterable) { VM& vm = state->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSValue iteratorFunction = iterable.get(state, state->propertyNames().iteratorSymbol); RETURN_IF_EXCEPTION(scope, JSValue()); CallData iteratorFunctionCallData; CallType iteratorFunctionCallType = getCallData(iteratorFunction, iteratorFunctionCallData); if (iteratorFunctionCallType == CallType::None) { throwTypeError(state, scope); return JSValue(); } ArgList iteratorFunctionArguments; JSValue iterator = call(state, iteratorFunction, iteratorFunctionCallType, iteratorFunctionCallData, iterable, iteratorFunctionArguments); RETURN_IF_EXCEPTION(scope, JSValue()); if (!iterator.isObject()) { throwTypeError(state, scope); return JSValue(); } return iterator; }
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 }; }
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_IF_EXCEPTION(scope, nullptr); } 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(); }
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)); }
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); }
// 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()); }
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); }
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); }
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; }
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; }
static EncodedJSValue JSC_HOST_CALL webAssemblyTableProtoFuncSet(ExecState* exec) { VM& vm = exec->vm(); auto throwScope = DECLARE_THROW_SCOPE(vm); JSWebAssemblyTable* table = getTable(exec, vm, exec->thisValue()); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); JSValue value = exec->argument(1); WebAssemblyFunction* wasmFunction; WebAssemblyWrapperFunction* wasmWrapperFunction; if (!value.isNull() && !isWebAssemblyHostFunction(vm, value, wasmFunction, wasmWrapperFunction)) return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, "WebAssembly.Table.prototype.set expects the second argument to be null or an instance of WebAssembly.Function"_s))); uint32_t index = toNonWrappingUint32(exec, exec->argument(0)); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); if (index >= table->length()) return JSValue::encode(throwException(exec, throwScope, createRangeError(exec, "WebAssembly.Table.prototype.set expects an integer less than the length of the table"_s))); if (value.isNull()) table->clearFunction(index); else { ASSERT(value.isObject() && isWebAssemblyHostFunction(vm, jsCast<JSObject*>(value), wasmFunction, wasmWrapperFunction)); ASSERT(!!wasmFunction || !!wasmWrapperFunction); if (wasmFunction) table->setFunction(vm, index, wasmFunction); else table->setFunction(vm, index, wasmWrapperFunction); } 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; }
// ECMA-262 5.1, 15.11.4.4 EncodedJSValue JSC_HOST_CALL errorProtoFuncToString(ExecState* exec) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); // 1. Let O be the this value. JSValue thisValue = exec->thisValue(); // 2. If Type(O) is not Object, throw a TypeError exception. if (!thisValue.isObject()) return throwVMTypeError(exec, scope); JSObject* thisObj = asObject(thisValue); // Guard against recursion! StringRecursionChecker checker(exec, thisObj); ASSERT(!scope.exception() || checker.earlyReturnValue()); if (JSValue earlyReturnValue = checker.earlyReturnValue()) return JSValue::encode(earlyReturnValue); // 3. Let name be the result of calling the [[Get]] internal method of O with argument "name". JSValue name = thisObj->get(exec, exec->propertyNames().name); RETURN_IF_EXCEPTION(scope, encodedJSValue()); // 4. If name is undefined, then let name be "Error"; else let name be ToString(name). String nameString; if (name.isUndefined()) nameString = ASCIILiteral("Error"); else { nameString = name.toWTFString(exec); RETURN_IF_EXCEPTION(scope, encodedJSValue()); } // 5. Let msg be the result of calling the [[Get]] internal method of O with argument "message". JSValue message = thisObj->get(exec, exec->propertyNames().message); RETURN_IF_EXCEPTION(scope, encodedJSValue()); // (sic) // 6. If msg is undefined, then let msg be the empty String; else let msg be ToString(msg). // 7. If msg is undefined, then let msg be the empty String; else let msg be ToString(msg). String messageString; if (message.isUndefined()) messageString = String(); else { messageString = message.toWTFString(exec); RETURN_IF_EXCEPTION(scope, encodedJSValue()); } // 8. If name is the empty String, return msg. if (!nameString.length()) return JSValue::encode(message.isString() ? message : jsString(exec, messageString)); // 9. If msg is the empty String, return name. if (!messageString.length()) return JSValue::encode(name.isString() ? name : jsString(exec, nameString)); // 10. Return the result of concatenating name, ":", a single space character, and msg. scope.release(); return JSValue::encode(jsMakeNontrivialString(exec, nameString, ": ", messageString)); }
JSValue JSWebKitSubtleCrypto::wrapKey(ExecState& state) { VM& vm = state.vm(); auto scope = DECLARE_THROW_SCOPE(vm); if (state.argumentCount() < 4) 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<CryptoKey> wrappingKey = JSCryptoKey::toWrapped(vm, state.uncheckedArgument(2)); if (!key) return throwTypeError(&state, scope); if (!wrappingKey->allows(CryptoKeyUsageWrapKey)) { wrapped().document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'wrapKey'")); throwNotSupportedError(state, scope); return jsUndefined(); } auto algorithm = createAlgorithmFromJSValue(state, scope, state.uncheckedArgument(3)); RETURN_IF_EXCEPTION(scope, { }); auto parameters = JSCryptoAlgorithmDictionary::createParametersForEncrypt(state, scope, algorithm->identifier(), state.uncheckedArgument(3)); RETURN_IF_EXCEPTION(scope, { }); RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow()); auto promise = wrapper->promise(); auto exportSuccessCallback = [keyFormat, algorithm, parameters, wrappingKey, wrapper](const Vector<uint8_t>& exportedKeyData) mutable { auto encryptSuccessCallback = [wrapper](const Vector<uint8_t>& encryptedData) mutable { fulfillPromiseWithArrayBuffer(wrapper.releaseNonNull(), encryptedData.data(), encryptedData.size()); }; auto encryptFailureCallback = [wrapper]() mutable { wrapper->reject(); // FIXME: This should reject with an Exception. }; auto result = algorithm->encryptForWrapKey(*parameters, *wrappingKey, std::make_pair(exportedKeyData.data(), exportedKeyData.size()), WTFMove(encryptSuccessCallback), WTFMove(encryptFailureCallback)); if (result.hasException()) { // FIXME: Report failure details to console, and possibly to calling script once there is a standardized way to pass errors to WebCrypto promise reject functions. wrapper->reject(); // FIXME: This should reject with an Exception. } }; auto exportFailureCallback = [wrapper]() mutable { wrapper->reject(); // FIXME: This should reject with an Exception. }; WebCore::exportKey(state, keyFormat, *key, WTFMove(exportSuccessCallback), WTFMove(exportFailureCallback)); return promise; }
static void importKey(ExecState& state, CryptoKeyFormat keyFormat, CryptoOperationData data, RefPtr<CryptoAlgorithm> algorithm, RefPtr<CryptoAlgorithmParametersDeprecated> parameters, bool extractable, CryptoKeyUsageBitmap keyUsages, CryptoAlgorithm::KeyCallback callback, CryptoAlgorithm::VoidCallback failureCallback) { VM& vm = state.vm(); auto scope = DECLARE_THROW_SCOPE(vm); std::unique_ptr<CryptoKeySerialization> keySerialization; switch (keyFormat) { case CryptoKeyFormat::Raw: keySerialization = CryptoKeySerializationRaw::create(data); break; case CryptoKeyFormat::JWK: { String jwkString = String::fromUTF8(data.first, data.second); if (jwkString.isNull()) { throwTypeError(&state, scope, ASCIILiteral("JWK JSON serialization is not valid UTF-8")); return; } keySerialization = std::make_unique<JSCryptoKeySerializationJWK>(&state, jwkString); RETURN_IF_EXCEPTION(scope, void()); break; } default: throwTypeError(&state, scope, ASCIILiteral("Unsupported key format for import")); return; } ASSERT(keySerialization); std::optional<CryptoAlgorithmPair> reconciledResult = keySerialization->reconcileAlgorithm(algorithm.get(), parameters.get()); if (!reconciledResult) { if (!scope.exception()) throwTypeError(&state, scope, ASCIILiteral("Algorithm specified in key is not compatible with one passed to importKey as argument")); return; } RETURN_IF_EXCEPTION(scope, void()); algorithm = reconciledResult->algorithm; parameters = reconciledResult->parameters; if (!algorithm) { throwTypeError(&state, scope, ASCIILiteral("Neither key nor function argument has crypto algorithm specified")); return; } ASSERT(parameters); keySerialization->reconcileExtractable(extractable); RETURN_IF_EXCEPTION(scope, void()); keySerialization->reconcileUsages(keyUsages); RETURN_IF_EXCEPTION(scope, void()); auto keyData = keySerialization->keyData(); RETURN_IF_EXCEPTION(scope, void()); propagateException(state, scope, algorithm->importKey(*parameters, *keyData, extractable, keyUsages, WTFMove(callback), WTFMove(failureCallback))); }
JSArray* JSBoundFunction::boundArgsCopy(ExecState* exec) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSArray* result = constructEmptyArray(exec, nullptr, globalObject()); RETURN_IF_EXCEPTION(scope, nullptr); for (unsigned i = 0; i < m_boundArgs->length(); ++i) { result->push(exec, m_boundArgs->getIndexQuickly(i)); RETURN_IF_EXCEPTION(scope, nullptr); } return result; }
EncodedJSValue JSC_HOST_CALL symbolConstructorFor(ExecState* exec) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSString* stringKey = exec->argument(0).toString(exec); RETURN_IF_EXCEPTION(scope, encodedJSValue()); String string = stringKey->value(exec); RETURN_IF_EXCEPTION(scope, encodedJSValue()); return JSValue::encode(Symbol::create(exec->vm(), exec->vm().symbolRegistry().symbolForKey(string))); }
JSValue OSRExitSite::toJS(ExecState* exec) const { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSArray* result = constructEmptyArray(exec, 0); RETURN_IF_EXCEPTION(scope, { }); for (unsigned i = 0; i < m_codeAddresses.size(); ++i) { result->putDirectIndex(exec, i, jsString(exec, toString(RawPointer(m_codeAddresses[i])))); RETURN_IF_EXCEPTION(scope, { }); } return result; }
JSValue iteratorStep(ExecState* exec, IterationRecord iterationRecord) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSValue result = iteratorNext(exec, iterationRecord); RETURN_IF_EXCEPTION(scope, JSValue()); bool done = iteratorComplete(exec, result); RETURN_IF_EXCEPTION(scope, JSValue()); if (done) return jsBoolean(false); return result; }
JSObject* constructRegExp(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, JSObject* callee, JSValue newTarget) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSValue patternArg = args.at(0); JSValue flagsArg = args.at(1); bool isPatternRegExp = patternArg.inherits(vm, RegExpObject::info()); bool constructAsRegexp = isRegExp(vm, exec, patternArg); RETURN_IF_EXCEPTION(scope, nullptr); if (newTarget.isUndefined() && constructAsRegexp && flagsArg.isUndefined()) { JSValue constructor = patternArg.get(exec, vm.propertyNames->constructor); RETURN_IF_EXCEPTION(scope, nullptr); if (callee == constructor) { // We know that patternArg is a object otherwise constructAsRegexp would be false. return patternArg.getObject(); } } if (isPatternRegExp) { RegExp* regExp = jsCast<RegExpObject*>(patternArg)->regExp(); Structure* structure = getRegExpStructure(exec, globalObject, newTarget); RETURN_IF_EXCEPTION(scope, nullptr); if (!flagsArg.isUndefined()) { RegExpFlags flags = toFlags(exec, flagsArg); ASSERT(!!scope.exception() == (flags == InvalidFlags)); if (flags == InvalidFlags) return nullptr; regExp = RegExp::create(vm, regExp->pattern(), flags); } return RegExpObject::create(vm, structure, regExp); } if (constructAsRegexp) { JSValue pattern = patternArg.get(exec, vm.propertyNames->source); RETURN_IF_EXCEPTION(scope, nullptr); if (flagsArg.isUndefined()) { flagsArg = patternArg.get(exec, vm.propertyNames->flags); RETURN_IF_EXCEPTION(scope, nullptr); } patternArg = pattern; } scope.release(); return regExpCreate(exec, globalObject, newTarget, patternArg, flagsArg); }
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; }
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)); }
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 CryptoKeyUsageBitmap cryptoKeyUsagesFromJSValue(ExecState& state, ThrowScope& scope, JSValue value) { if (!isJSArray(value)) { throwTypeError(&state, scope); return { }; } CryptoKeyUsageBitmap result = 0; JSArray* array = asArray(value); for (unsigned i = 0; i < array->length(); ++i) { auto usageString = array->getIndex(&state, i).toWTFString(&state); RETURN_IF_EXCEPTION(scope, { }); if (usageString == "encrypt") result |= CryptoKeyUsageEncrypt; else if (usageString == "decrypt") result |= CryptoKeyUsageDecrypt; else if (usageString == "sign") result |= CryptoKeyUsageSign; else if (usageString == "verify") result |= CryptoKeyUsageVerify; else if (usageString == "deriveKey") result |= CryptoKeyUsageDeriveKey; else if (usageString == "deriveBits") result |= CryptoKeyUsageDeriveBits; else if (usageString == "wrapKey") result |= CryptoKeyUsageWrapKey; else if (usageString == "unwrapKey") result |= CryptoKeyUsageUnwrapKey; } return result; }
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); }
void BytecodeSequence::addSequenceProperties(ExecState* exec, JSObject* result) const { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSArray* header = constructEmptyArray(exec, 0); RETURN_IF_EXCEPTION(scope, void()); for (unsigned i = 0; i < m_header.size(); ++i) header->putDirectIndex(exec, i, jsString(exec, String::fromUTF8(m_header[i]))); result->putDirect(vm, exec->propertyNames().header, header); JSArray* sequence = constructEmptyArray(exec, 0); RETURN_IF_EXCEPTION(scope, void()); for (unsigned i = 0; i < m_sequence.size(); ++i) sequence->putDirectIndex(exec, i, m_sequence[i].toJS(exec)); result->putDirect(vm, exec->propertyNames().bytecode, sequence); }
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; } }