bool NPJSObject::hasMethod(NPIdentifier methodName) { IdentifierRep* identifierRep = static_cast<IdentifierRep*>(methodName); if (!identifierRep->isString()) return false; ExecState* exec = m_objectMap->globalExec(); if (!exec) return false; JSLockHolder lock(exec); JSValue value = m_jsObject->get(exec, identifierFromIdentifierRep(exec, identifierRep)); exec->clearException(); CallData callData; return getCallData(value, callData) != CallType::None; }
EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineSetter(ExecState* exec) { JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); JSValue set = exec->argument(1); CallData callData; if (getCallData(set, callData) == CallTypeNone) return throwVMError(exec, createTypeError(exec, ASCIILiteral("invalid setter usage"))); PropertyDescriptor descriptor; descriptor.setSetter(set); descriptor.setEnumerable(true); descriptor.setConfigurable(true); thisObject->methodTable(exec->vm())->defineOwnProperty(thisObject, exec, exec->argument(0).toString(exec)->toIdentifier(exec), descriptor, false); return JSValue::encode(jsUndefined()); }
// 15.2.4.3 Object.prototype.toLocaleString() EncodedJSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState* exec) { // 1. Let O be the result of calling ToObject passing the this value as the argument. JSObject* object = exec->thisValue().toThis(exec, StrictMode).toObject(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); // 2. Let toString be the result of calling the [[Get]] internal method of O passing "toString" as the argument. JSValue toString = object->get(exec, exec->propertyNames().toString); // 3. If IsCallable(toString) is false, throw a TypeError exception. CallData callData; CallType callType = getCallData(toString, callData); if (callType == CallTypeNone) return JSValue::encode(jsUndefined()); // 4. Return the result of calling the [[Call]] internal method of toString passing O as the this value and no arguments. return JSValue::encode(call(exec, toString, callType, callData, object, exec->emptyList())); }
EncodedJSValue JSC_HOST_CALL boundThisNoArgsFunctionCall(ExecState* exec) { JSBoundFunction* boundFunction = jsCast<JSBoundFunction*>(exec->jsCallee()); MarkedArgumentBuffer args; for (unsigned i = 0; i < exec->argumentCount(); ++i) args.append(exec->uncheckedArgument(i)); JSFunction* targetFunction = jsCast<JSFunction*>(boundFunction->targetFunction()); ExecutableBase* executable = targetFunction->executable(); if (executable->hasJITCodeForCall()) { // Force the executable to cache its arity entrypoint. executable->entrypointFor(CodeForCall, MustCheckArity); } CallData callData; CallType callType = getCallData(targetFunction, callData); ASSERT(callType != CallType::None); return JSValue::encode(call(exec, targetFunction, callType, callData, boundFunction->boundThis(), args)); }
ScriptValue ScriptCallback::call(bool& hadException) { JSLock lock(SilenceAssertionsOnly); CallData callData; CallType callType = getCallData(m_function.jsValue(), callData); if (callType == CallTypeNone) return ScriptValue(); JSValue result = JSC::call(m_exec, m_function.jsValue(), callType, callData, m_function.jsValue(), m_arguments); hadException = m_exec->hadException(); if (hadException) { reportException(m_exec, m_exec->exception()); return ScriptValue(); } return ScriptValue(result); }
void iteratorClose(ExecState* exec, JSValue iterator) { Exception* exception = nullptr; if (exec->hadException()) { exception = exec->exception(); exec->clearException(); } JSValue returnFunction = iterator.get(exec, exec->vm().propertyNames->returnKeyword); if (exec->hadException()) return; if (returnFunction.isUndefined()) { if (exception) exec->vm().throwException(exec, exception); return; } CallData returnFunctionCallData; CallType returnFunctionCallType = getCallData(returnFunction, returnFunctionCallData); if (returnFunctionCallType == CallTypeNone) { if (exception) exec->vm().throwException(exec, exception); else throwTypeError(exec); return; } MarkedArgumentBuffer returnFunctionArguments; JSValue innerResult = call(exec, returnFunction, returnFunctionCallType, returnFunctionCallData, iterator, returnFunctionArguments); if (exception) { exec->vm().throwException(exec, exception); return; } if (exec->hadException()) return; if (!innerResult.isObject()) { throwTypeError(exec, ASCIILiteral("Iterator result interface is not an object.")); return; } }
EncodedJSValue JSC_HOST_CALL boundFunctionCall(ExecState* exec) { JSBoundFunction* boundFunction = jsCast<JSBoundFunction*>(exec->callee()); ASSERT(isJSArray(boundFunction->boundArgs())); // Currently this is true! JSArray* boundArgs = asArray(boundFunction->boundArgs()); MarkedArgumentBuffer args; for (unsigned i = 0; i < boundArgs->length(); ++i) args.append(boundArgs->getIndexQuickly(i)); for (unsigned i = 0; i < exec->argumentCount(); ++i) args.append(exec->uncheckedArgument(i)); JSObject* targetFunction = boundFunction->targetFunction(); CallData callData; CallType callType = getCallData(targetFunction, callData); ASSERT(callType != CallTypeNone); return JSValue::encode(call(exec, targetFunction, callType, callData, boundFunction->boundThis(), args)); }
void JSMutationCallback::call(const Vector<RefPtr<MutationRecord> >& mutations, MutationObserver* observer) { if (!canInvokeCallback()) return; RefPtr<JSMutationCallback> protect(this); JSLockHolder lock(m_isolatedWorld->vm()); if (!m_callback) return; JSValue callback = m_callback.get(); CallData callData; CallType callType = getCallData(callback, callData); if (callType == CallTypeNone) { ASSERT_NOT_REACHED(); return; } ScriptExecutionContext* context = scriptExecutionContext(); if (!context) return; ASSERT(context->isDocument()); JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(context, m_isolatedWorld.get()); ExecState* exec = globalObject->globalExec(); JSValue jsObserver = toJS(exec, globalObject, observer); MarkedArgumentBuffer args; args.append(jsArray(exec, globalObject, mutations)); args.append(jsObserver); InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(context, callType, callData); JSMainThreadExecState::call(exec, callback, callType, callData, jsObserver, args); InspectorInstrumentation::didCallFunction(cookie); if (exec->hadException()) reportCurrentException(exec); }
// 15.3.4.5 Function.prototype.bind (thisArg [, arg1 [, arg2, ...]]) EncodedJSValue JSC_HOST_CALL functionProtoFuncBind(ExecState* exec) { JSGlobalObject* globalObject = exec->callee()->globalObject(); // Let Target be the this value. JSValue target = exec->hostThisValue(); // If IsCallable(Target) is false, throw a TypeError exception. CallData callData; CallType callType = getCallData(target, callData); if (callType == CallTypeNone) return throwVMTypeError(exec); // Primitive values are not callable. ASSERT(target.isObject()); JSObject* targetObject = asObject(target); // Let A be a new (possibly empty) internal list of all of the argument values provided after thisArg (arg1, arg2 etc), in order. size_t numBoundArgs = exec->argumentCount() > 1 ? exec->argumentCount() - 1 : 0; JSArray* boundArgs = JSArray::tryCreateUninitialized(exec->globalData(), globalObject->arrayStructure(), numBoundArgs); if (!boundArgs) return JSValue::encode(throwOutOfMemoryError(exec)); for (size_t i = 0; i < numBoundArgs; ++i) boundArgs->initializeIndex(exec->globalData(), i, exec->argument(i + 1)); boundArgs->completeInitialization(numBoundArgs); // If the [[Class]] internal property of Target is "Function", then ... // Else set the length own property of F to 0. unsigned length = 0; if (targetObject->inherits(&JSFunction::s_info)) { ASSERT(target.get(exec, exec->propertyNames().length).isNumber()); // a. Let L be the length property of Target minus the length of A. // b. Set the length own property of F to either 0 or L, whichever is larger. unsigned targetLength = (unsigned)target.get(exec, exec->propertyNames().length).asNumber(); if (targetLength > numBoundArgs) length = targetLength - numBoundArgs; } Identifier name(exec, target.get(exec, exec->propertyNames().name).toString(exec)->value(exec)); return JSValue::encode(JSBoundFunction::create(exec, globalObject, targetObject, exec->argument(0), boundArgs, length, name)); }
bool NPJSObject::invoke(ExecState* exec, JSGlobalObject* globalObject, JSValue function, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result) { CallData callData; CallType callType = getCallData(function, callData); if (callType == CallTypeNone) return false; // Convert the passed in arguments. MarkedArgumentBuffer argumentList; for (uint32_t i = 0; i < argumentCount; ++i) argumentList.append(m_objectMap->convertNPVariantToJSValue(exec, globalObject, arguments[i])); JSValue value = JSC::call(exec, function, callType, callData, m_jsObject->methodTable()->toThisObject(m_jsObject.get(), exec), argumentList); // Convert and return the result of the function call. m_objectMap->convertJSValueToNPVariant(exec, value, *result); exec->clearException(); return true; }
JSValue JSCallbackData::invokeCallback(MarkedArgumentBuffer& args, bool* raisedException) { ASSERT(callback()); ASSERT(globalObject()); ExecState* exec = globalObject()->globalExec(); JSValue function = callback()->get(exec, Identifier(exec, "handleEvent")); CallData callData; CallType callType = getCallData(function, callData); if (callType == CallTypeNone) { callType = callback()->methodTable()->getCallData(callback(), callData); if (callType == CallTypeNone) return JSValue(); function = callback(); } globalObject()->globalData().timeoutChecker.start(); ScriptExecutionContext* context = globalObject()->scriptExecutionContext(); // We will fail to get the context if the frame has been detached. if (!context) return JSValue(); bool contextIsDocument = context->isDocument(); JSValue result = contextIsDocument ? JSMainThreadExecState::call(exec, function, callType, callData, callback(), args) : JSC::call(exec, function, callType, callData, callback(), args); globalObject()->globalData().timeoutChecker.stop(); if (contextIsDocument) Document::updateStyleForAllDocuments(); if (exec->hadException()) { reportCurrentException(exec); if (raisedException) *raisedException = true; return result; } return result; }
static ALWAYS_INLINE JSValue callDefaultValueFunction(ExecState* exec, const JSObject* object, const Identifier& propertyName) { JSValue function = object->get(exec, propertyName); CallData callData; CallType callType = getCallData(function, callData); if (callType == CallTypeNone) return exec->exception(); // Prevent "toString" and "valueOf" from observing execution if an exception // is pending. if (exec->hadException()) return exec->exception(); JSValue result = call(exec, function, callType, callData, const_cast<JSObject*>(object), exec->emptyList()); ASSERT(!result.isGetterSetter()); if (exec->hadException()) return exec->exception(); if (result.isObject()) return JSValue(); return result; }
EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec) { JSValue thisValue = exec->thisValue(); JSObject* object = jsCast<JSObject*>(thisValue.toThis(exec, NotStrictMode)); if (exec->hadException()) return JSValue::encode(jsNull()); JSValue toISOValue = object->get(exec, exec->vm().propertyNames->toISOString); if (exec->hadException()) return JSValue::encode(jsNull()); CallData callData; CallType callType = getCallData(toISOValue, callData); if (callType == CallTypeNone) return throwVMError(exec, createTypeError(exec, ASCIILiteral("toISOString is not a function"))); JSValue result = call(exec, asObject(toISOValue), callType, callData, object, exec->emptyList()); if (exec->hadException()) return JSValue::encode(jsNull()); if (result.isObject()) return throwVMError(exec, createTypeError(exec, ASCIILiteral("toISOString did not return a primitive value"))); return JSValue::encode(result); }
JSValue iteratorNext(ExecState* exec, JSValue iterator, JSValue value) { JSValue nextFunction = iterator.get(exec, exec->vm().propertyNames->next); if (exec->hadException()) return jsUndefined(); CallData nextFunctionCallData; CallType nextFunctionCallType = getCallData(nextFunction, nextFunctionCallData); if (nextFunctionCallType == CallType::None) return throwTypeError(exec); MarkedArgumentBuffer nextFunctionArguments; if (!value.isEmpty()) nextFunctionArguments.append(value); JSValue result = call(exec, nextFunction, nextFunctionCallType, nextFunctionCallData, iterator, nextFunctionArguments); if (exec->hadException()) return jsUndefined(); if (!result.isObject()) return throwTypeError(exec, ASCIILiteral("Iterator result interface is not an object.")); return result; }
bool NPJSObject::invoke(ExecState* exec, JSGlobalObject* globalObject, JSValue function, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result) { VM& vm = exec->vm(); auto scope = DECLARE_CATCH_SCOPE(vm); CallData callData; CallType callType = getCallData(function, callData); if (callType == CallType::None) return false; // Convert the passed in arguments. MarkedArgumentBuffer argumentList; for (uint32_t i = 0; i < argumentCount; ++i) argumentList.append(m_objectMap->convertNPVariantToJSValue(exec, globalObject, arguments[i])); JSValue value = JSC::call(exec, function, callType, callData, m_jsObject.get(), argumentList); // Convert and return the result of the function call. m_objectMap->convertJSValueToNPVariant(exec, value, *result); scope.clearException(); return true; }
static EncodedJSValue JSC_HOST_CALL constructPromise(ExecState* exec) { if (!exec->argumentCount()) return throwVMError(exec, createTypeError(exec, "Expected at least one argument")); JSValue function = exec->argument(0); CallData callData; CallType callType = getCallData(function, callData); if (callType == CallTypeNone) return throwVMError(exec, createTypeError(exec, "Expected function as as first argument")); JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject(); // 1. Let promise be a new promise. JSPromise* promise = JSPromise::createWithResolver(exec->vm(), globalObject); // 2. Let resolver be promise's associated resolver. JSPromiseResolver* resolver = promise->resolver(); // 3. Set init's callback this value to promise. // 4. Invoke init with resolver passed as parameter. MarkedArgumentBuffer initArguments; initArguments.append(resolver); call(exec, function, callType, callData, promise, initArguments); // 5. If init threw an exception, catch it, and then, if resolver's resolved flag // is unset, run resolver's reject with the thrown exception as argument. if (exec->hadException()) { JSValue exception = exec->exception(); exec->clearException(); resolver->rejectIfNotResolved(exec, exception); } return JSValue::encode(promise); }
EncodedJSValue JSC_HOST_CALL mapProtoFuncForEach(CallFrame* callFrame) { JSMap* map = getMap(callFrame, callFrame->thisValue()); if (!map) return JSValue::encode(jsUndefined()); JSValue callBack = callFrame->argument(0); CallData callData; CallType callType = getCallData(callBack, callData); if (callType == CallTypeNone) return JSValue::encode(throwTypeError(callFrame, WTF::ASCIILiteral("Map.prototype.forEach called without callback"))); JSValue thisValue = callFrame->argument(1); VM* vm = &callFrame->vm(); JSMapIterator* iterator = JSMapIterator::create(*vm, callFrame->callee()->globalObject()->mapIteratorStructure(), map, MapIterateKeyValue); JSValue key, value; if (callType == CallTypeJS) { JSFunction* function = jsCast<JSFunction*>(callBack); CachedCall cachedCall(callFrame, function, 3); while (iterator->nextKeyValue(key, value) && !vm->exception()) { cachedCall.setThis(thisValue); cachedCall.setArgument(0, value); cachedCall.setArgument(1, key); cachedCall.setArgument(2, map); cachedCall.call(); } iterator->finish(); } else { while (iterator->nextKeyValue(key, value) && !vm->exception()) { MarkedArgumentBuffer args; args.append(value); args.append(key); args.append(map); JSC::call(callFrame, callBack, callType, callData, thisValue, args); } iterator->finish(); } return JSValue::encode(jsUndefined()); }
EncodedJSValue JSC_HOST_CALL JSPromisePrototypeFuncCatch(ExecState* exec) { JSPromise* thisObject = jsDynamicCast<JSPromise*>(exec->thisValue()); if (!thisObject) return throwVMError(exec, createTypeError(exec, "Receiver of catch must be a Promise")); JSValue rejectCallback = exec->argument(0); if (!rejectCallback.isUndefined()) { CallData callData; CallType callType = getCallData(rejectCallback, callData); if (callType == CallTypeNone) return throwVMError(exec, createTypeError(exec, "Expected function or undefined as as first argument")); } JSFunction* callee = jsCast<JSFunction*>(exec->callee()); JSGlobalObject* globalObject = callee->globalObject(); // 1. Let promise be a new promise. JSPromise* promise = JSPromise::createWithResolver(exec->vm(), globalObject); // 2. Let resolver be promise's associated resolver. JSPromiseResolver* resolver = promise->resolver(); // 3. Let fulfillCallback be a new promise callback for resolver and its fulfill algorithm. InternalFunction* fulfillWrapper = JSPromiseCallback::create(exec, globalObject, globalObject->promiseCallbackStructure(), resolver, JSPromiseCallback::Fulfill); // 4. Let rejectWrapper be a promise wrapper callback for resolver and rejectCallback if rejectCallback is // not omitted and a promise callback for resolver and its reject algorithm otherwise. InternalFunction* rejectWrapper = wrapCallback(exec, globalObject, rejectCallback, resolver, JSPromiseCallback::Reject); // 5. Append fulfillWrapper and rejectWrapper to the context object. thisObject->appendCallbacks(exec, fulfillWrapper, rejectWrapper); // 6. Return promise. return JSValue::encode(promise); }
ScriptObject InjectedScriptHost::createInjectedScript(const String& source, ScriptState* scriptState, long id) { SourceCode sourceCode = makeSource(stringToUString(source)); JSLock lock(SilenceAssertionsOnly); JSDOMGlobalObject* globalObject = static_cast<JSDOMGlobalObject*>(scriptState->lexicalGlobalObject()); JSValue globalThisValue = scriptState->globalThisValue(); Completion comp = JSMainThreadExecState::evaluate(scriptState, globalObject->globalScopeChain(), sourceCode, globalThisValue); if (comp.complType() != JSC::Normal && comp.complType() != JSC::ReturnValue) return ScriptObject(); JSValue functionValue = comp.value(); CallData callData; CallType callType = getCallData(functionValue, callData); if (callType == CallTypeNone) return ScriptObject(); MarkedArgumentBuffer args; args.append(toJS(scriptState, globalObject, this)); args.append(globalThisValue); args.append(jsNumber(id)); JSValue result = JSC::call(scriptState, functionValue, callType, callData, globalThisValue, args); if (result.isObject()) return ScriptObject(scriptState, result.getObject()); return ScriptObject(); }
JSValue iteratorNext(ExecState* exec, JSValue iterator, JSValue value) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSValue nextFunction = iterator.get(exec, vm.propertyNames->next); RETURN_IF_EXCEPTION(scope, JSValue()); CallData nextFunctionCallData; CallType nextFunctionCallType = getCallData(nextFunction, nextFunctionCallData); if (nextFunctionCallType == CallType::None) return throwTypeError(exec, scope); MarkedArgumentBuffer nextFunctionArguments; if (!value.isEmpty()) nextFunctionArguments.append(value); JSValue result = call(exec, nextFunction, nextFunctionCallType, nextFunctionCallData, iterator, nextFunctionArguments); RETURN_IF_EXCEPTION(scope, JSValue()); if (!result.isObject()) return throwTypeError(exec, scope, ASCIILiteral("Iterator result interface is not an object.")); return result; }
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(); }
// ES5 8.10.5 ToPropertyDescriptor static bool toPropertyDescriptor(ExecState* exec, JSValue in, PropertyDescriptor& desc) { if (!in.isObject()) { throwError(exec, createTypeError(exec, ASCIILiteral("Property description must be an object."))); return false; } JSObject* description = asObject(in); PropertySlot enumerableSlot(description); if (description->getPropertySlot(exec, exec->propertyNames().enumerable, enumerableSlot)) { desc.setEnumerable(enumerableSlot.getValue(exec, exec->propertyNames().enumerable).toBoolean(exec)); if (exec->hadException()) return false; } PropertySlot configurableSlot(description); if (description->getPropertySlot(exec, exec->propertyNames().configurable, configurableSlot)) { desc.setConfigurable(configurableSlot.getValue(exec, exec->propertyNames().configurable).toBoolean(exec)); if (exec->hadException()) return false; } JSValue value; PropertySlot valueSlot(description); if (description->getPropertySlot(exec, exec->propertyNames().value, valueSlot)) { desc.setValue(valueSlot.getValue(exec, exec->propertyNames().value)); if (exec->hadException()) return false; } PropertySlot writableSlot(description); if (description->getPropertySlot(exec, exec->propertyNames().writable, writableSlot)) { desc.setWritable(writableSlot.getValue(exec, exec->propertyNames().writable).toBoolean(exec)); if (exec->hadException()) return false; } PropertySlot getSlot(description); if (description->getPropertySlot(exec, exec->propertyNames().get, getSlot)) { JSValue get = getSlot.getValue(exec, exec->propertyNames().get); if (exec->hadException()) return false; if (!get.isUndefined()) { CallData callData; if (getCallData(get, callData) == CallTypeNone) { throwError(exec, createTypeError(exec, ASCIILiteral("Getter must be a function."))); return false; } } desc.setGetter(get); } PropertySlot setSlot(description); if (description->getPropertySlot(exec, exec->propertyNames().set, setSlot)) { JSValue set = setSlot.getValue(exec, exec->propertyNames().set); if (exec->hadException()) return false; if (!set.isUndefined()) { CallData callData; if (getCallData(set, callData) == CallTypeNone) { throwError(exec, createTypeError(exec, ASCIILiteral("Setter must be a function."))); return false; } } desc.setSetter(set); } if (!desc.isAccessorDescriptor()) return true; if (desc.value()) { throwError(exec, createTypeError(exec, ASCIILiteral("Invalid property. 'value' present on property with getter or setter."))); return false; } if (desc.writablePresent()) { throwError(exec, createTypeError(exec, ASCIILiteral("Invalid property. 'writable' present on property with getter or setter."))); return false; } return true; }
static inline JSValue callFunction(ExecState& exec, JSValue jsFunction, JSValue thisValue, const ArgList& arguments) { CallData callData; CallType callType = getCallData(jsFunction, callData); return call(&exec, jsFunction, callType, callData, thisValue, arguments); }
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); }
bool ScriptValue::isFunction() const { CallData callData; return getCallData(m_value.get(), callData) != CallTypeNone; }
static EncodedJSValue JSC_HOST_CALL promiseResolutionHandlerFunction(ExecState* exec) { JSValue x = exec->argument(0); VM& vm = exec->vm(); JSObject* F = exec->callee(); // 1. Let 'promise' be the value of F's [[Promise]] internal slot JSPromise* promise = jsCast<JSPromise*>(F->get(exec, vm.propertyNames->promisePrivateName)); // 2. Let 'fulfillmentHandler' be the value of F's [[FulfillmentHandler]] internal slot. JSValue fulfillmentHandler = F->get(exec, vm.propertyNames->fulfillmentHandlerPrivateName); // 3. Let 'rejectionHandler' be the value of F's [[RejectionHandler]] internal slot. JSValue rejectionHandler = F->get(exec, vm.propertyNames->rejectionHandlerPrivateName); // 4. If SameValue(x, promise) is true, if (sameValue(exec, x, promise)) { // i. Let 'selfResolutionError' be a newly-created TypeError object. JSObject* selfResolutionError = createTypeError(exec, ASCIILiteral("Resolve a promise with itself")); // ii. Return the result of calling the [[Call]] internal method of rejectionHandler with // undefined as thisArgument and a List containing selfResolutionError as argumentsList. CallData rejectCallData; CallType rejectCallType = getCallData(rejectionHandler, rejectCallData); ASSERT(rejectCallType != CallTypeNone); MarkedArgumentBuffer rejectArguments; rejectArguments.append(selfResolutionError); return JSValue::encode(call(exec, rejectionHandler, rejectCallType, rejectCallData, jsUndefined(), rejectArguments)); } // 5. Let 'C' be the value of promise's [[PromiseConstructor]] internal slot. JSValue C = promise->constructor(); // 6. Let 'deferred' be the result of calling GetDeferred(C) JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C); // 7. ReturnIfAbrupt(deferred). if (exec->hadException()) return JSValue::encode(jsUndefined()); JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue); // 8. Let 'updateResult' be the result of calling UpdateDeferredFromPotentialThenable(x, deferred). ThenableStatus updateResult = updateDeferredFromPotentialThenable(exec, x, deferred); // 9. ReturnIfAbrupt(updateResult). if (exec->hadException()) return JSValue::encode(jsUndefined()); // 10. If 'updateResult' is not "not a thenable", return the result of calling // Invoke(deferred.[[Promise]], "then", (fulfillmentHandler, rejectionHandler)). // NOTE: Invoke does not seem to be defined anywhere, so I am guessing here. if (updateResult != NotAThenable) { JSObject* deferredPromise = deferred->promise(); JSValue thenValue = deferredPromise->get(exec, exec->vm().propertyNames->then); if (exec->hadException()) return JSValue::encode(jsUndefined()); CallData thenCallData; CallType thenCallType = getCallData(thenValue, thenCallData); if (thenCallType == CallTypeNone) return JSValue::encode(throwTypeError(exec)); MarkedArgumentBuffer arguments; arguments.append(fulfillmentHandler); arguments.append(rejectionHandler); return JSValue::encode(call(exec, thenValue, thenCallType, thenCallData, deferredPromise, arguments)); } // 11. Return the result of calling the [[Call]] internal method of fulfillmentHandler // with undefined as thisArgument and a List containing x as argumentsList. CallData fulfillmentHandlerCallData; CallType fulfillmentHandlerCallType = getCallData(fulfillmentHandler, fulfillmentHandlerCallData); ASSERT(fulfillmentHandlerCallType != CallTypeNone); MarkedArgumentBuffer fulfillmentHandlerArguments; fulfillmentHandlerArguments.append(x); return JSValue::encode(call(exec, fulfillmentHandler, fulfillmentHandlerCallType, fulfillmentHandlerCallData, jsUndefined(), fulfillmentHandlerArguments)); }
void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event) { ASSERT(scriptExecutionContext); if (!scriptExecutionContext || scriptExecutionContext->isJSExecutionForbidden()) return; JSLock lock(SilenceAssertionsOnly); JSObject* jsFunction = this->jsFunction(scriptExecutionContext); if (!jsFunction) return; JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, m_isolatedWorld.get()); if (!globalObject) return; if (scriptExecutionContext->isDocument()) { JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject); Frame* frame = window->impl()->frame(); if (!frame) return; // The window must still be active in its frame. See <https://bugs.webkit.org/show_bug.cgi?id=21921>. // FIXME: A better fix for this may be to change DOMWindow::frame() to not return a frame the detached window used to be in. if (frame->domWindow() != window->impl()) return; // FIXME: Is this check needed for other contexts? ScriptController* script = frame->script(); if (!script->canExecuteScripts(AboutToExecuteScript) || script->isPaused()) return; } ExecState* exec = globalObject->globalExec(); JSValue handleEventFunction = jsFunction; CallData callData; CallType callType = getCallData(handleEventFunction, callData); // If jsFunction is not actually a function, see if it implements the EventListener interface and use that if (callType == CallTypeNone) { handleEventFunction = jsFunction->get(exec, Identifier(exec, "handleEvent")); callType = getCallData(handleEventFunction, callData); } if (callType != CallTypeNone) { RefPtr<JSEventListener> protect(this); MarkedArgumentBuffer args; args.append(toJS(exec, globalObject, event)); Event* savedEvent = globalObject->currentEvent(); globalObject->setCurrentEvent(event); JSGlobalData& globalData = globalObject->globalData(); DynamicGlobalObjectScope globalObjectScope(globalData, globalData.dynamicGlobalObject ? globalData.dynamicGlobalObject : globalObject); globalData.timeoutChecker.start(); JSValue thisValue = handleEventFunction == jsFunction ? toJS(exec, globalObject, event->currentTarget()) : jsFunction; JSValue retval = scriptExecutionContext->isDocument() ? JSMainThreadExecState::call(exec, handleEventFunction, callType, callData, thisValue, args) : JSC::call(exec, handleEventFunction, callType, callData, thisValue, args); globalData.timeoutChecker.stop(); globalObject->setCurrentEvent(savedEvent); #if ENABLE(WORKERS) if (scriptExecutionContext->isWorkerContext()) { bool terminatorCausedException = (exec->hadException() && isTerminatedExecutionException(exec->exception())); if (terminatorCausedException || globalData.terminator.shouldTerminate()) static_cast<WorkerContext*>(scriptExecutionContext)->script()->forbidExecution(); } #endif if (exec->hadException()) { event->target()->uncaughtExceptionInEventHandler(); reportCurrentException(exec); } else { if (!retval.isUndefinedOrNull() && event->storesResultAsString()) event->storeResult(ustringToString(retval.toString(exec)->value(exec))); if (m_isAttribute) { if (retval.isFalse()) event->preventDefault(); } } } }
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); }
void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event) { ASSERT(scriptExecutionContext); if (!scriptExecutionContext || scriptExecutionContext->isJSExecutionForbidden()) return; JSLockHolder lock(scriptExecutionContext->vm()); JSObject* jsFunction = this->jsFunction(scriptExecutionContext); if (!jsFunction) return; JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, *m_isolatedWorld); if (!globalObject) return; if (scriptExecutionContext->isDocument()) { JSDOMWindow* window = jsCast<JSDOMWindow*>(globalObject); if (!window->impl().isCurrentlyDisplayedInFrame()) return; // FIXME: Is this check needed for other contexts? ScriptController& script = window->impl().frame()->script(); if (!script.canExecuteScripts(AboutToExecuteScript) || script.isPaused()) return; } ExecState* exec = globalObject->globalExec(); JSValue handleEventFunction = jsFunction; CallData callData; CallType callType = getCallData(handleEventFunction, callData); // If jsFunction is not actually a function, see if it implements the EventListener interface and use that if (callType == CallTypeNone) { handleEventFunction = jsFunction->get(exec, Identifier::fromString(exec, "handleEvent")); callType = getCallData(handleEventFunction, callData); } if (callType != CallTypeNone) { Ref<JSEventListener> protect(*this); MarkedArgumentBuffer args; args.append(toJS(exec, globalObject, event)); Event* savedEvent = globalObject->currentEvent(); globalObject->setCurrentEvent(event); VM& vm = globalObject->vm(); VMEntryScope entryScope(vm, vm.entryScope ? vm.entryScope->globalObject() : globalObject); InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(scriptExecutionContext, callType, callData); JSValue thisValue = handleEventFunction == jsFunction ? toJS(exec, globalObject, event->currentTarget()) : jsFunction; NakedPtr<Exception> exception; JSValue retval = scriptExecutionContext->isDocument() ? JSMainThreadExecState::call(exec, handleEventFunction, callType, callData, thisValue, args, exception) : JSC::call(exec, handleEventFunction, callType, callData, thisValue, args, exception); InspectorInstrumentation::didCallFunction(cookie, scriptExecutionContext); globalObject->setCurrentEvent(savedEvent); if (is<WorkerGlobalScope>(*scriptExecutionContext)) { bool terminatorCausedException = (exec->hadException() && isTerminatedExecutionException(exec->exception())); if (terminatorCausedException || (vm.watchdog && vm.watchdog->didFire())) downcast<WorkerGlobalScope>(*scriptExecutionContext).script()->forbidExecution(); } if (exception) { event->target()->uncaughtExceptionInEventHandler(); reportException(exec, exception); } else { if (!retval.isUndefinedOrNull() && is<BeforeUnloadEvent>(*event)) downcast<BeforeUnloadEvent>(*event).setReturnValue(retval.toString(exec)->value(exec)); if (m_isAttribute) { if (retval.isFalse()) event->preventDefault(); } } } }
void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event) { ASSERT(scriptExecutionContext); if (!scriptExecutionContext || scriptExecutionContext->isJSExecutionForbidden()) return; VM& vm = scriptExecutionContext->vm(); JSLockHolder lock(vm); auto scope = DECLARE_CATCH_SCOPE(vm); // See https://dom.spec.whatwg.org/#dispatching-events spec on calling handleEvent. // "If this throws an exception, report the exception." It should not propagate the // exception. JSObject* jsFunction = this->jsFunction(scriptExecutionContext); if (!jsFunction) return; JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, *m_isolatedWorld); if (!globalObject) return; if (scriptExecutionContext->isDocument()) { JSDOMWindow* window = jsCast<JSDOMWindow*>(globalObject); if (!window->wrapped().isCurrentlyDisplayedInFrame()) return; if (wasCreatedFromMarkup() && !scriptExecutionContext->contentSecurityPolicy()->allowInlineEventHandlers(sourceURL(), sourcePosition().m_line)) return; // FIXME: Is this check needed for other contexts? ScriptController& script = window->wrapped().frame()->script(); if (!script.canExecuteScripts(AboutToExecuteScript) || script.isPaused()) return; } ExecState* exec = globalObject->globalExec(); JSValue handleEventFunction = jsFunction; CallData callData; CallType callType = getCallData(handleEventFunction, callData); // If jsFunction is not actually a function, see if it implements the EventListener interface and use that if (callType == CallType::None) { handleEventFunction = jsFunction->get(exec, Identifier::fromString(exec, "handleEvent")); if (UNLIKELY(scope.exception())) { auto* exception = scope.exception(); scope.clearException(); event->target()->uncaughtExceptionInEventHandler(); reportException(exec, exception); return; } callType = getCallData(handleEventFunction, callData); } if (callType != CallType::None) { Ref<JSEventListener> protectedThis(*this); MarkedArgumentBuffer args; args.append(toJS(exec, globalObject, event)); Event* savedEvent = globalObject->currentEvent(); globalObject->setCurrentEvent(event); VMEntryScope entryScope(vm, vm.entryScope ? vm.entryScope->globalObject() : globalObject); InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(scriptExecutionContext, callType, callData); JSValue thisValue = handleEventFunction == jsFunction ? toJS(exec, globalObject, event->currentTarget()) : jsFunction; NakedPtr<JSC::Exception> exception; JSValue retval = scriptExecutionContext->isDocument() ? JSMainThreadExecState::profiledCall(exec, JSC::ProfilingReason::Other, handleEventFunction, callType, callData, thisValue, args, exception) : JSC::profiledCall(exec, JSC::ProfilingReason::Other, handleEventFunction, callType, callData, thisValue, args, exception); InspectorInstrumentation::didCallFunction(cookie, scriptExecutionContext); globalObject->setCurrentEvent(savedEvent); if (is<WorkerGlobalScope>(*scriptExecutionContext)) { auto scriptController = downcast<WorkerGlobalScope>(*scriptExecutionContext).script(); bool terminatorCausedException = (scope.exception() && isTerminatedExecutionException(scope.exception())); if (terminatorCausedException || scriptController->isTerminatingExecution()) scriptController->forbidExecution(); } if (exception) { event->target()->uncaughtExceptionInEventHandler(); reportException(exec, exception); } else { if (!retval.isUndefinedOrNull() && is<BeforeUnloadEvent>(*event)) downcast<BeforeUnloadEvent>(*event).setReturnValue(retval.toWTFString(exec)); if (m_isAttribute) { if (retval.isFalse()) event->preventDefault(); } } } }