Index: third_party/WebKit/Source/bindings/core/v8/V8LazyEventListener.cpp |
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8LazyEventListener.cpp b/third_party/WebKit/Source/bindings/core/v8/V8LazyEventListener.cpp |
index 71812424a3520466226de05a5691538a00ba72fb..d714761b7df915c827f7a039c3a069fd8361cbcd 100644 |
--- a/third_party/WebKit/Source/bindings/core/v8/V8LazyEventListener.cpp |
+++ b/third_party/WebKit/Source/bindings/core/v8/V8LazyEventListener.cpp |
@@ -53,6 +53,7 @@ namespace blink { |
V8LazyEventListener::V8LazyEventListener(v8::Isolate* isolate, const AtomicString& functionName, const AtomicString& eventParameterName, const String& code, const String sourceURL, const TextPosition& position, Node* node) |
: V8AbstractEventListener(true, DOMWrapperWorld::mainWorld(), isolate) |
+ , m_wasCompilationFailed(false) |
, m_functionName(functionName) |
, m_eventParameterName(eventParameterName) |
, m_code(code) |
@@ -107,32 +108,42 @@ static void V8LazyEventListenerToString(const v8::FunctionCallbackInfo<v8::Value |
v8SetReturnValue(info, V8HiddenValue::getHiddenValue(ScriptState::current(info.GetIsolate()), info.Holder(), V8HiddenValue::toStringString(info.GetIsolate()))); |
} |
-void V8LazyEventListener::prepareListenerObject(ExecutionContext* executionContext) |
+v8::Local<v8::Object> V8LazyEventListener::getListenerObjectInternal(ExecutionContext* executionContext) |
{ |
if (!executionContext) |
- return; |
+ return v8::Local<v8::Object>(); |
// 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::EscapableHandleScope handleScope(toIsolate(executionContext)); |
v8::Local<v8::Context> v8Context = toV8Context(executionContext, world()); |
if (v8Context.IsEmpty()) |
- return; |
+ return v8::Local<v8::Object>(); |
ScriptState* scriptState = ScriptState::from(v8Context); |
if (!scriptState->contextIsValid()) |
- return; |
+ return v8::Local<v8::Object>(); |
if (!executionContext->isDocument()) |
- return; |
+ return v8::Local<v8::Object>(); |
- if (!toDocument(executionContext)->allowInlineEventHandler(m_node, this, m_sourceURL, m_position.m_line)) { |
- clearListenerObject(); |
- return; |
- } |
+ if (!toDocument(executionContext)->allowInlineEventHandler(m_node, this, m_sourceURL, m_position.m_line)) |
+ return v8::Local<v8::Object>(); |
- if (hasExistingListenerObject()) |
- return; |
+ // All checks passed and it's now okay to return the function object. |
+ |
+ // We may need to compile the same script twice or more because the compiled |
+ // function object may be garbage-collected, however, we should behave as if |
+ // we compile the code only once, i.e. we must not throw an error twice. |
+ if (!hasExistingListenerObject() && !m_wasCompilationFailed) |
+ compileScript(scriptState, executionContext); |
+ |
+ return handleScope.Escape(getExistingListenerObject()); |
+} |
+ |
+void V8LazyEventListener::compileScript(ScriptState* scriptState, ExecutionContext* executionContext) |
+{ |
+ DCHECK(!hasExistingListenerObject()); |
ScriptState::Scope scope(scriptState); |
@@ -142,12 +153,11 @@ void V8LazyEventListener::prepareListenerObject(ExecutionContext* executionConte |
// See fast/forms/form-action.html |
// fast/forms/selected-index-value.html |
// fast/overflow/onscroll-layer-self-destruct.html |
- HTMLFormElement* formElement = 0; |
+ HTMLFormElement* formElement = nullptr; |
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); |
@@ -168,9 +178,10 @@ void V8LazyEventListener::prepareListenerObject(ExecutionContext* executionConte |
// 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); |
+ wrappedFunction = v8::ScriptCompiler::CompileFunctionInContext(isolate(), &source, scriptState->context(), 1, ¶meterName, 3, scopes); |
if (block.HasCaught()) { |
- fireErrorEvent(v8Context, executionContext, block.Message()); |
+ m_wasCompilationFailed = true; // Do not compile the same code twice. |
+ fireErrorEvent(scriptState->context(), executionContext, block.Message()); |
return; |
} |
} |
@@ -192,16 +203,6 @@ void V8LazyEventListener::prepareListenerObject(ExecutionContext* executionConte |
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); |
} |