static void messageHandlerInWorker(v8::Local<v8::Message> message, v8::Local<v8::Value> data) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); V8PerIsolateData* perIsolateData = V8PerIsolateData::from(isolate); // During the frame teardown, there may not be a valid context. ScriptState* scriptState = ScriptState::current(isolate); if (!scriptState->contextIsValid()) return; // Exceptions that occur in error handler should be ignored since in that case // WorkerGlobalScope::reportException will send the exception to the worker object. if (perIsolateData->isReportingException()) return; perIsolateData->setReportingException(true); ExecutionContext* context = scriptState->getExecutionContext(); std::unique_ptr<SourceLocation> location = SourceLocation::fromMessage(isolate, message, context); ErrorEvent* event = ErrorEvent::create(toCoreStringWithNullCheck(message->Get()), std::move(location), &scriptState->world()); AccessControlStatus corsStatus = message->IsSharedCrossOrigin() ? SharableCrossOrigin : NotSharableCrossOrigin; // If execution termination has been triggered as part of constructing // the error event from the v8::Message, quietly leave. if (!isolate->IsExecutionTerminating()) { V8ErrorHandler::storeExceptionOnErrorEventWrapper(scriptState, event, data, scriptState->context()->Global()); scriptState->getExecutionContext()->reportException(event, corsStatus); } perIsolateData->setReportingException(false); }
PassRefPtr<JSONValue> toJSONValue(const ScriptValue& value) { ScriptState* scriptState = value.scriptState(); ASSERT(scriptState->contextIsValid()); ScriptState::Scope scope(scriptState); NonThrowableExceptionState exceptionState; return ScriptValue::to<JSONValuePtr>(scriptState->isolate(), value, exceptionState); }
static void messageHandlerInMainThread(v8::Local<v8::Message> message, v8::Local<v8::Value> data) { ASSERT(isMainThread()); v8::Isolate* isolate = v8::Isolate::GetCurrent(); if (isolate->GetEnteredContext().IsEmpty()) return; // If called during context initialization, there will be no entered context. ScriptState* scriptState = ScriptState::current(isolate); if (!scriptState->contextIsValid()) return; ExecutionContext* context = scriptState->getExecutionContext(); std::unique_ptr<SourceLocation> location = SourceLocation::fromMessage(isolate, message, context); AccessControlStatus accessControlStatus = NotSharableCrossOrigin; if (message->IsOpaque()) accessControlStatus = OpaqueResource; else if (message->IsSharedCrossOrigin()) accessControlStatus = SharableCrossOrigin; ErrorEvent* event = ErrorEvent::create(toCoreStringWithNullCheck(message->Get()), std::move(location), &scriptState->world()); String messageForConsole = extractMessageForConsole(isolate, data); if (!messageForConsole.isEmpty()) event->setUnsanitizedMessage("Uncaught " + messageForConsole); // This method might be called while we're creating a new context. In this // case, we avoid storing the exception object, as we can't create a wrapper // during context creation. // FIXME: Can we even get here during initialization now that we bail out when // GetEntered returns an empty handle? if (context->isDocument()) { LocalFrame* frame = toDocument(context)->frame(); if (frame && frame->script().existingWindowProxy(scriptState->world())) { V8ErrorHandler::storeExceptionOnErrorEventWrapper( scriptState, event, data, scriptState->context()->Global()); } } if (scriptState->world().isPrivateScriptIsolatedWorld()) { // We allow a private script to dispatch error events even in a // EventDispatchForbiddenScope scope. Without having this ability, it's // hard to debug the private script because syntax errors in the private // script are not reported to console (the private script just crashes // silently). Allowing error events in private scripts is safe because // error events don't propagate to other isolated worlds (which means that // the error events won't fire any event listeners in user's scripts). EventDispatchForbiddenScope::AllowUserAgentEvents allowUserAgentEvents; context->dispatchErrorEvent(event, accessControlStatus); } else { context->dispatchErrorEvent(event, accessControlStatus); } }
ScriptState* ScriptState::forWorld(LocalFrame* frame, DOMWrapperWorld& world) { ASSERT(frame); v8::HandleScope handleScope(toIsolate(frame)); v8::Local<v8::Context> context = toV8Context(frame, world); if (context.IsEmpty()) return nullptr; ScriptState* scriptState = ScriptState::from(context); ASSERT(scriptState->contextIsValid()); return scriptState; }
// Create a V8 object with an interceptor of NPObjectPropertyGetter. bool ScriptController::bindToWindowObject(LocalFrame* frame, const String& key, NPObject* object) { ScriptState* scriptState = ScriptState::forMainWorld(frame); if (!scriptState->contextIsValid()) return false; ScriptState::Scope scope(scriptState); v8::Local<v8::Object> value = createV8ObjectForNPObject(isolate(), object, 0); // Attach to the global object. return v8CallBoolean(scriptState->context()->Global()->Set(scriptState->context(), v8String(isolate(), key), value)); }
// Create a V8 object with an interceptor of NPObjectPropertyGetter. void ScriptController::bindToWindowObject(LocalFrame* frame, const String& key, NPObject* object) { ScriptState* scriptState = ScriptState::forMainWorld(frame); if (!scriptState->contextIsValid()) return; ScriptState::Scope scope(scriptState); v8::Handle<v8::Object> value = createV8ObjectForNPObject(m_isolate, object, 0); // Attach to the global object. scriptState->context()->Global()->Set(v8String(m_isolate, key), value); }
static void promiseRejectHandlerInWorker(v8::PromiseRejectMessage data) { v8::Local<v8::Promise> promise = data.GetPromise(); // Bail out if called during context initialization. v8::Isolate* isolate = promise->GetIsolate(); ScriptState* scriptState = ScriptState::current(isolate); if (!scriptState->contextIsValid()) return; ExecutionContext* executionContext = scriptState->executionContext(); if (!executionContext) return; ASSERT(executionContext->isWorkerGlobalScope()); WorkerScriptController* scriptController = toWorkerGlobalScope(executionContext)->script(); ASSERT(scriptController); if (data.GetEvent() == v8::kPromiseHandlerAddedAfterReject) { scriptController->rejectedPromises()->handlerAdded(data); return; } ASSERT(data.GetEvent() == v8::kPromiseRejectWithNoHandler); int scriptId = 0; int lineNumber = 0; int columnNumber = 0; String resourceName; String errorMessage; v8::Local<v8::Message> message = v8::Exception::CreateMessage(data.GetValue()); if (!message.IsEmpty()) { TOSTRING_VOID(V8StringResource<>, resourceName, message->GetScriptOrigin().ResourceName()); scriptId = message->GetScriptOrigin().ScriptID()->Value(); if (v8Call(message->GetLineNumber(scriptState->context()), lineNumber) && v8Call(message->GetStartColumn(scriptState->context()), columnNumber)) ++columnNumber; // message->Get() can be empty here. https://crbug.com/450330 errorMessage = toCoreStringWithNullCheck(message->Get()); } scriptController->rejectedPromises()->rejectedWithNoHandler(scriptState, data, errorMessage, resourceName, scriptId, lineNumber, columnNumber, nullptr); }
void MainThreadDebugger::exceptionThrown(ExecutionContext* context, ErrorEvent* event) { LocalFrame* frame = nullptr; ScriptState* scriptState = nullptr; if (context->isDocument()) { frame = toDocument(context)->frame(); if (!frame) return; scriptState = event->world() ? ScriptState::forWorld(frame, *event->world()) : nullptr; } else if (context->isMainThreadWorkletGlobalScope()) { frame = toMainThreadWorkletGlobalScope(context)->frame(); if (!frame) return; scriptState = toMainThreadWorkletGlobalScope(context) ->scriptController() ->getScriptState(); } else { NOTREACHED(); } frame->console().reportMessageToClient(JSMessageSource, ErrorMessageLevel, event->messageForConsole(), event->location()); const String defaultMessage = "Uncaught"; if (scriptState && scriptState->contextIsValid()) { ScriptState::Scope scope(scriptState); v8::Local<v8::Value> exception = V8ErrorHandler::loadExceptionFromErrorEventWrapper( scriptState, event, scriptState->context()->Global()); SourceLocation* location = event->location(); String message = event->messageForConsole(); String url = location->url(); v8Inspector()->exceptionThrown( scriptState->context(), toV8InspectorStringView(defaultMessage), exception, toV8InspectorStringView(message), toV8InspectorStringView(url), location->lineNumber(), location->columnNumber(), location->takeStackTrace(), location->scriptId()); } }
static void promiseRejectHandlerInWorker(v8::PromiseRejectMessage data) { v8::Local<v8::Promise> promise = data.GetPromise(); // Bail out if called during context initialization. v8::Isolate* isolate = promise->GetIsolate(); ScriptState* scriptState = ScriptState::current(isolate); if (!scriptState->contextIsValid()) return; ExecutionContext* executionContext = scriptState->getExecutionContext(); if (!executionContext) return; ASSERT(executionContext->isWorkerGlobalScope()); WorkerOrWorkletScriptController* scriptController = toWorkerGlobalScope(executionContext)->scriptController(); ASSERT(scriptController); promiseRejectHandler(data, *scriptController->getRejectedPromises(), scriptState); }
static void promiseRejectHandlerInMainThread(v8::PromiseRejectMessage data) { ASSERT(isMainThread()); v8::Local<v8::Promise> promise = data.GetPromise(); v8::Isolate* isolate = promise->GetIsolate(); // TODO(ikilpatrick): Remove this check, extensions tests that use // extensions::ModuleSystemTest incorrectly don't have a valid script state. LocalDOMWindow* window = currentDOMWindow(isolate); if (!window || !window->isCurrentlyDisplayedInFrame()) return; // Bail out if called during context initialization. ScriptState* scriptState = ScriptState::current(isolate); if (!scriptState->contextIsValid()) return; promiseRejectHandler(data, rejectedPromisesOnMainThread(), scriptState); }
void V8AbstractEventListener::handleEvent(ExecutionContext* executionContext, Event* event) { if (!executionContext) return; // Don't reenter V8 if execution was terminated in this instance of V8. if (executionContext->isJSExecutionForbidden()) return; // A ScriptState used by the event listener needs to be calculated based on // the ExecutionContext that fired the the event listener and the world // that installed the event listener. ASSERT(event); v8::HandleScope handleScope(toIsolate(executionContext)); v8::Local<v8::Context> v8Context = toV8Context(executionContext, world()); if (v8Context.IsEmpty()) return; ScriptState* scriptState = ScriptState::from(v8Context); if (!scriptState->contextIsValid()) return; handleEvent(scriptState, event); }
// http://dev.w3.org/html5/spec/Overview.html#prepare-a-script bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, LegacyTypeSupport supportLegacyTypes) { if (m_alreadyStarted) return false; ScriptLoaderClient* client = this->client(); bool wasParserInserted; if (m_parserInserted) { wasParserInserted = true; m_parserInserted = false; } else { wasParserInserted = false; } if (wasParserInserted && !client->asyncAttributeValue()) m_forceAsync = true; // FIXME: HTML5 spec says we should check that all children are either comments or empty text nodes. if (!client->hasSourceAttribute() && !m_element->hasChildren()) return false; if (!m_element->inDocument()) return false; if (!isScriptTypeSupported(supportLegacyTypes)) return false; if (wasParserInserted) { m_parserInserted = true; m_forceAsync = false; } m_alreadyStarted = true; // FIXME: If script is parser inserted, verify it's still in the original document. Document& elementDocument = m_element->document(); Document* contextDocument = elementDocument.contextDocument().get(); if (!contextDocument || !contextDocument->allowExecutingScripts(m_element)) return false; if (!isScriptForEventSupported()) return false; if (!client->charsetAttributeValue().isEmpty()) m_characterEncoding = client->charsetAttributeValue(); else m_characterEncoding = elementDocument.characterSet(); if (client->hasSourceAttribute()) { FetchRequest::DeferOption defer = FetchRequest::NoDefer; if (!m_parserInserted || client->asyncAttributeValue() || client->deferAttributeValue()) defer = FetchRequest::LazyLoad; if (!fetchScript(client->sourceAttributeValue(), defer)) return false; } if (client->hasSourceAttribute() && client->deferAttributeValue() && m_parserInserted && !client->asyncAttributeValue()) { m_willExecuteWhenDocumentFinishedParsing = true; m_willBeParserExecuted = true; } else if (client->hasSourceAttribute() && m_parserInserted && !client->asyncAttributeValue()) { m_willBeParserExecuted = true; } else if (!client->hasSourceAttribute() && m_parserInserted && !elementDocument.isRenderingReady()) { m_willBeParserExecuted = true; m_readyToBeParserExecuted = true; } else if (client->hasSourceAttribute() && !client->asyncAttributeValue() && !m_forceAsync) { m_willExecuteInOrder = true; m_pendingScript = PendingScript(m_element, m_resource.get()); contextDocument->scriptRunner()->queueScriptForExecution(this, ScriptRunner::IN_ORDER_EXECUTION); // Note that watchForLoad can immediately call notifyFinished. m_pendingScript.watchForLoad(this); } else if (client->hasSourceAttribute()) { m_pendingScript = PendingScript(m_element, m_resource.get()); LocalFrame* frame = m_element->document().frame(); if (frame) { ScriptState* scriptState = ScriptState::forMainWorld(frame); if (scriptState->contextIsValid()) ScriptStreamer::startStreaming(m_pendingScript, PendingScript::Async, frame->settings(), scriptState, frame->frameScheduler()->loadingTaskRunner()); } contextDocument->scriptRunner()->queueScriptForExecution(this, ScriptRunner::ASYNC_EXECUTION); // Note that watchForLoad can immediately call notifyFinished. m_pendingScript.watchForLoad(this); } else { // Reset line numbering for nested writes. TextPosition position = elementDocument.isInDocumentWrite() ? TextPosition() : scriptStartPosition; KURL scriptURL = (!elementDocument.isInDocumentWrite() && m_parserInserted) ? elementDocument.url() : KURL(); if (!executeScript(ScriptSourceCode(scriptContent(), scriptURL, position))) { dispatchErrorEvent(); return false; } } return true; }
// https://html.spec.whatwg.org/multipage/dom.html#html-element-constructors void V8HTMLConstructor::htmlConstructor( const v8::FunctionCallbackInfo<v8::Value>& info, const WrapperTypeInfo& wrapperTypeInfo, const HTMLElementType elementInterfaceName) { TRACE_EVENT0("blink", "HTMLConstructor"); DCHECK(info.IsConstructCall()); v8::Isolate* isolate = info.GetIsolate(); ScriptState* scriptState = ScriptState::current(isolate); v8::Local<v8::Value> newTarget = info.NewTarget(); if (!scriptState->contextIsValid()) { V8ThrowException::throwError(isolate, "The context has been destroyed"); return; } if (!RuntimeEnabledFeatures::customElementsV1Enabled() || !scriptState->world().isMainWorld()) { V8ThrowException::throwTypeError(isolate, "Illegal constructor"); return; } // 2. If NewTarget is equal to the active function object, then // throw a TypeError and abort these steps. v8::Local<v8::Function> activeFunctionObject = scriptState->perContextData()->constructorForType( &V8HTMLElement::wrapperTypeInfo); if (newTarget == activeFunctionObject) { V8ThrowException::throwTypeError(isolate, "Illegal constructor"); return; } LocalDOMWindow* window = scriptState->domWindow(); CustomElementRegistry* registry = window->customElements(); // 3. Let definition be the entry in registry with constructor equal to // NewTarget. // If there is no such definition, then throw a TypeError and abort these // steps. ScriptCustomElementDefinition* definition = ScriptCustomElementDefinition::forConstructor(scriptState, registry, newTarget); if (!definition) { V8ThrowException::throwTypeError(isolate, "Illegal constructor"); return; } const AtomicString& localName = definition->descriptor().localName(); const AtomicString& name = definition->descriptor().name(); if (localName == name) { // Autonomous custom element // 4.1. If the active function object is not HTMLElement, then throw a // TypeError if (!V8HTMLElement::wrapperTypeInfo.equals(&wrapperTypeInfo)) { V8ThrowException::throwTypeError(isolate, "Illegal constructor: autonomous custom " "elements must extend HTMLElement"); return; } } else { // Customized built-in element // 5. If local name is not valid for interface, throw TypeError if (htmlElementTypeForTag(localName) != elementInterfaceName) { V8ThrowException::throwTypeError(isolate, "Illegal constructor: localName does " "not match the HTML element interface"); return; } } ExceptionState exceptionState(isolate, ExceptionState::ConstructionContext, "HTMLElement"); v8::TryCatch tryCatch(isolate); // 6. Let prototype be Get(NewTarget, "prototype"). Rethrow any exceptions. v8::Local<v8::Value> prototype; v8::Local<v8::String> prototypeString = v8AtomicString(isolate, "prototype"); if (!v8Call(newTarget.As<v8::Object>()->Get(scriptState->context(), prototypeString), prototype)) { return; } // 7. If Type(prototype) is not Object, then: ... if (!prototype->IsObject()) { if (V8PerContextData* perContextData = V8PerContextData::from( newTarget.As<v8::Object>()->CreationContext())) { prototype = perContextData->prototypeForType(&V8HTMLElement::wrapperTypeInfo); } else { V8ThrowException::throwError(isolate, "The context has been destroyed"); return; } } // 8. If definition's construction stack is empty... Element* element; if (definition->constructionStack().isEmpty()) { // This is an element being created with 'new' from script element = definition->createElementForConstructor(*window->document()); } else { element = definition->constructionStack().last(); if (element) { // This is an element being upgraded that has called super definition->constructionStack().last().clear(); } else { // During upgrade an element has invoked the same constructor // before calling 'super' and that invocation has poached the // element. exceptionState.throwDOMException(InvalidStateError, "this instance is already constructed"); return; } } const WrapperTypeInfo* wrapperType = element->wrapperTypeInfo(); v8::Local<v8::Object> wrapper = V8DOMWrapper::associateObjectWithWrapper( isolate, element, wrapperType, info.Holder()); // If the element had a wrapper, we now update and return that // instead. v8SetReturnValue(info, wrapper); // 11. Perform element.[[SetPrototypeOf]](prototype). Rethrow any exceptions. // Note: I don't think this prototype set *can* throw exceptions. wrapper->SetPrototype(scriptState->context(), prototype.As<v8::Object>()) .ToChecked(); }
void V8LazyEventListener::prepareListenerObject(ExecutionContext* executionContext) { if (!executionContext) return; // A ScriptState used by the event listener needs to be calculated based on // the ExecutionContext that fired the the event listener and the world // that installed the event listener. v8::HandleScope handleScope(toIsolate(executionContext)); v8::Local<v8::Context> v8Context = toV8Context(executionContext, world()); if (v8Context.IsEmpty()) return; ScriptState* scriptState = ScriptState::from(v8Context); if (!scriptState->contextIsValid()) return; if (!executionContext->isDocument()) return; if (!toDocument(executionContext)->allowInlineEventHandlers(m_node, this, m_sourceURL, m_position.m_line)) { clearListenerObject(); return; } if (hasExistingListenerObject()) return; ScriptState::Scope scope(scriptState); // FIXME: Remove the following 'with' hack. // // Nodes other than the document object, when executing inline event // handlers push document, form owner, and the target node on the scope chain. // We do this by using 'with' statement. // See chrome/fast/forms/form-action.html // chrome/fast/forms/selected-index-value.html // base/fast/overflow/onscroll-layer-self-destruct.html // // Don't use new lines so that lines in the modified handler // have the same numbers as in the original code. // FIXME: V8 does not allow us to programmatically create object environments so // we have to do this hack! What if m_code escapes to run arbitrary script? // // Call with 4 arguments instead of 3, pass additional null as the last parameter. // By calling the function with 4 arguments, we create a setter on arguments object // which would shadow property "3" on the prototype. String code = "(function() {" "with (this[2]) {" "with (this[1]) {" "with (this[0]) {" "return function(" + m_eventParameterName + ") {" + m_code + "\n" // Insert '\n' otherwise //-style comments could break the handler. "};" "}}}})"; v8::Local<v8::String> codeExternalString = v8String(isolate(), code); v8::Local<v8::Value> result; if (!V8ScriptRunner::compileAndRunInternalScript(codeExternalString, isolate(), m_sourceURL, m_position).ToLocal(&result)) return; // Call the outer function to get the inner function. if (!result->IsFunction()) return; v8::Local<v8::Function> intermediateFunction = result.As<v8::Function>(); HTMLFormElement* formElement = 0; if (m_node && m_node->isHTMLElement()) formElement = toHTMLElement(m_node)->formOwner(); v8::Local<v8::Object> nodeWrapper = toObjectWrapper<Node>(m_node, scriptState); v8::Local<v8::Object> formWrapper = toObjectWrapper<HTMLFormElement>(formElement, scriptState); v8::Local<v8::Object> documentWrapper = toObjectWrapper<Document>(m_node ? m_node->ownerDocument() : 0, scriptState); v8::Local<v8::Object> thisObject = v8::Object::New(isolate()); if (thisObject.IsEmpty()) return; if (!v8CallBoolean(thisObject->ForceSet(scriptState->context(), v8::Integer::New(isolate(), 0), nodeWrapper))) return; if (!v8CallBoolean(thisObject->ForceSet(scriptState->context(), v8::Integer::New(isolate(), 1), formWrapper))) return; if (!v8CallBoolean(thisObject->ForceSet(scriptState->context(), v8::Integer::New(isolate(), 2), documentWrapper))) return; // FIXME: Remove this code when we stop doing the 'with' hack above. v8::Local<v8::Value> innerValue; if (!V8ScriptRunner::callInternalFunction(intermediateFunction, thisObject, 0, 0, isolate()).ToLocal(&innerValue) || !innerValue->IsFunction()) return; v8::Local<v8::Function> wrappedFunction = innerValue.As<v8::Function>(); // Change the toString function on the wrapper function to avoid it // returning the source for the actual wrapper function. Instead it // returns source for a clean wrapper function with the event // argument wrapping the event source code. The reason for this is // that some web sites use toString on event functions and eval the // source returned (sometimes a RegExp is applied as well) for some // other use. That fails miserably if the actual wrapper source is // returned. v8::Local<v8::Function> toStringFunction = v8::Function::New(isolate(), V8LazyEventListenerToString); if (toStringFunction.IsEmpty()) return; String toStringString = "function " + m_functionName + "(" + m_eventParameterName + ") {\n " + m_code + "\n}"; V8HiddenValue::setHiddenValue(isolate(), wrappedFunction, V8HiddenValue::toStringString(isolate()), v8String(isolate(), toStringString)); if (!v8CallBoolean(wrappedFunction->Set(scriptState->context(), v8AtomicString(isolate(), "toString"), toStringFunction))) return; wrappedFunction->SetName(v8String(isolate(), m_functionName)); // FIXME: Remove the following comment-outs. // See https://bugs.webkit.org/show_bug.cgi?id=85152 for more details. // // For the time being, we comment out the following code since the // second parsing can happen. // // Since we only parse once, there's no need to keep data used for parsing around anymore. // m_functionName = String(); // m_code = String(); // m_eventParameterName = String(); // m_sourceURL = String(); setListenerObject(wrappedFunction); }
void V8LazyEventListener::prepareListenerObject(ExecutionContext* executionContext) { if (!executionContext) return; // A ScriptState used by the event listener needs to be calculated based on // the ExecutionContext that fired the the event listener and the world // that installed the event listener. v8::HandleScope handleScope(toIsolate(executionContext)); v8::Local<v8::Context> v8Context = toV8Context(executionContext, world()); if (v8Context.IsEmpty()) return; ScriptState* scriptState = ScriptState::from(v8Context); if (!scriptState->contextIsValid()) return; if (!executionContext->isDocument()) return; if (!toDocument(executionContext)->allowInlineEventHandlers(m_node, this, m_sourceURL, m_position.m_line)) { clearListenerObject(); return; } if (hasExistingListenerObject()) return; ScriptState::Scope scope(scriptState); // Nodes other than the document object, when executing inline event // handlers push document, form owner, and the target node on the scope chain. // We do this by using 'with' statement. // See fast/forms/form-action.html // fast/forms/selected-index-value.html // fast/overflow/onscroll-layer-self-destruct.html HTMLFormElement* formElement = 0; if (m_node && m_node->isHTMLElement()) formElement = toHTMLElement(m_node)->formOwner(); v8::Local<v8::Object> scopes[3]; scopes[2] = toObjectWrapper<Node>(m_node, scriptState); scopes[1] = toObjectWrapper<HTMLFormElement>(formElement, scriptState); scopes[0] = toObjectWrapper<Document>(m_node ? m_node->ownerDocument() : 0, scriptState); v8::Local<v8::String> parameterName = v8String(isolate(), m_eventParameterName); v8::ScriptOrigin origin( v8String(isolate(), m_sourceURL), v8::Integer::New(isolate(), m_position.m_line.zeroBasedInt()), v8::Integer::New(isolate(), m_position.m_column.zeroBasedInt()), v8::True(isolate()), v8::Local<v8::Integer>(), v8::True(isolate())); v8::ScriptCompiler::Source source(v8String(isolate(), m_code), origin); v8::Local<v8::Function> wrappedFunction; { // JavaScript compilation error shouldn't be reported as a runtime // exception because we're not running any program code. Instead, // it should be reported as an ErrorEvent. v8::TryCatch block(isolate()); wrappedFunction = v8::ScriptCompiler::CompileFunctionInContext(isolate(), &source, v8Context, 1, ¶meterName, 3, scopes); if (block.HasCaught()) { fireErrorEvent(v8Context, executionContext, block.Message()); return; } } // Change the toString function on the wrapper function to avoid it // returning the source for the actual wrapper function. Instead it // returns source for a clean wrapper function with the event // argument wrapping the event source code. The reason for this is // that some web sites use toString on event functions and eval the // source returned (sometimes a RegExp is applied as well) for some // other use. That fails miserably if the actual wrapper source is // returned. v8::Local<v8::Function> toStringFunction = v8::Function::New(isolate(), V8LazyEventListenerToString); if (toStringFunction.IsEmpty()) return; String toStringString = "function " + m_functionName + "(" + m_eventParameterName + ") {\n " + m_code + "\n}"; V8HiddenValue::setHiddenValue(scriptState, wrappedFunction, V8HiddenValue::toStringString(isolate()), v8String(isolate(), toStringString)); if (!v8CallBoolean(wrappedFunction->Set(scriptState->context(), v8AtomicString(isolate(), "toString"), toStringFunction))) return; wrappedFunction->SetName(v8String(isolate(), m_functionName)); // FIXME: Remove the following comment-outs. // See https://bugs.webkit.org/show_bug.cgi?id=85152 for more details. // // For the time being, we comment out the following code since the // second parsing can happen. // // Since we only parse once, there's no need to keep data used for parsing around anymore. // m_functionName = String(); // m_code = String(); // m_eventParameterName = String(); // m_sourceURL = String(); setListenerObject(wrappedFunction, scriptState); }