void WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, NakedPtr<JSC::Exception>& returnedException) { if (isExecutionForbidden()) return; initScriptIfNeeded(); ExecState* exec = m_workerGlobalScopeWrapper->globalExec(); JSLockHolder lock(exec); JSC::evaluate(exec, sourceCode.jsSourceCode(), m_workerGlobalScopeWrapper->globalThis(), returnedException); VM& vm = exec->vm(); if ((returnedException && isTerminatedExecutionException(returnedException)) || isTerminatingExecution()) { forbidExecution(); return; } if (returnedException) { String errorMessage; int lineNumber = 0; int columnNumber = 0; String sourceURL = sourceCode.url().string(); if (m_workerGlobalScope->sanitizeScriptError(errorMessage, lineNumber, columnNumber, sourceURL, sourceCode.cachedScript())) { vm.throwException(exec, createError(exec, errorMessage.impl())); returnedException = vm.exception(); vm.clearException(); } } }
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(); } } } }