Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
CONSOLE ERROR: line 16: Uncaught Exception in toString()
Tests that an exception is thrown when the value returned in the beforeunload callback cannot be converted to a String

On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".


PASS Exception was thrown
PASS testMessage is "Uncaught Exception in toString()"
PASS successfullyParsed is true

TEST COMPLETE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
var testMessage;
window.onerror = function(msg) {
testMessage = msg;
// FIXME: This test fails. See crbug.com/446147.
testPassed("Exception was thrown");
shouldBeEqualToString("testMessage", "Uncaught Exception in toString()");
setTimeout(finishJSTest, 0);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
PASS Event is correctly dispatched
PASS successfullyParsed is true

TEST COMPLETE

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!DOCTYPE html>
<head>
<script src="../../resources/js-test.js"></script>
</head>
<body>
<div id="frames"></div>
<script type="text/javascript">
function handleEvent(event) {
testPassed("Event is correctly dispatched");
}

var frame1 = document.createElement("iframe");
document.getElementById("frames").appendChild(frame1);
frame1.contentDocument.body.addEventListener("click", handleEvent);

var frame2 = document.createElement("iframe");
document.getElementById("frames").appendChild(frame2);
frame2.contentDocument.body.addEventListener("click", handleEvent);

document.getElementById("frames").removeChild(frame1);

frame2.contentDocument.body.click();
</script>
</body>
</html>
2 changes: 1 addition & 1 deletion Source/bindings/core/v8/ScriptState.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class ScriptState : public RefCounted<ScriptState> {
: m_handleScope(scriptState->isolate())
, m_context(scriptState->context())
{
ASSERT(!m_context.IsEmpty());
ASSERT(!scriptState->contextIsEmpty());
m_context->Enter();
}

Expand Down
67 changes: 32 additions & 35 deletions Source/bindings/core/v8/V8AbstractEventListener.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,10 @@

namespace blink {

V8AbstractEventListener::V8AbstractEventListener(bool isAttribute, ScriptState* scriptState)
V8AbstractEventListener::V8AbstractEventListener(bool isAttribute, DOMWrapperWorld& world, v8::Isolate* isolate)
: EventListener(JSEventListenerType)
, m_isAttribute(isAttribute)
, m_scriptState(scriptState)
, m_isolate(scriptState->isolate())
{
if (isMainThread())
InspectorCounters::incrementCounter(InspectorCounters::JSEventListenerCounter);
}

V8AbstractEventListener::V8AbstractEventListener(bool isAttribute, v8::Isolate* isolate)
: EventListener(JSEventListenerType)
, m_isAttribute(isAttribute)
, m_scriptState(nullptr)
, m_world(world)
, m_isolate(isolate)
{
if (isMainThread())
Expand All @@ -73,29 +63,41 @@ V8AbstractEventListener::~V8AbstractEventListener()
InspectorCounters::decrementCounter(InspectorCounters::JSEventListenerCounter);
}

void V8AbstractEventListener::handleEvent(ExecutionContext*, Event* event)
void V8AbstractEventListener::handleEvent(ExecutionContext* executionContext, Event* event)
{
if (scriptState()->contextIsEmpty())
return;
if (!scriptState()->executionContext())
if (!executionContext)
return;
// Don't reenter V8 if execution was terminated in this instance of V8.
if (scriptState()->executionContext()->isJSExecutionForbidden())
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->contextIsEmpty())
return;
handleEvent(scriptState, event);
}

void V8AbstractEventListener::handleEvent(ScriptState* scriptState, Event* event)
{
// The callback function on XMLHttpRequest can clear the event listener and destroys 'this' object. Keep a local reference to it.
// See issue 889829.
RefPtr<V8AbstractEventListener> protect(this);

ScriptState::Scope scope(scriptState());
ScriptState::Scope scope(scriptState);

// Get the V8 wrapper for the event object.
v8::Handle<v8::Value> jsEvent = toV8(event, scriptState()->context()->Global(), isolate());
v8::Handle<v8::Value> jsEvent = toV8(event, scriptState->context()->Global(), isolate());
if (jsEvent.IsEmpty())
return;
invokeEventHandler(event, v8::Local<v8::Value>::New(isolate(), jsEvent));
invokeEventHandler(scriptState, event, v8::Local<v8::Value>::New(isolate(), jsEvent));
}

void V8AbstractEventListener::setListenerObject(v8::Handle<v8::Object> listener)
Expand All @@ -104,43 +106,38 @@ void V8AbstractEventListener::setListenerObject(v8::Handle<v8::Object> listener)
m_listener.setWeak(this, &setWeakCallback);
}

void V8AbstractEventListener::invokeEventHandler(Event* event, v8::Local<v8::Value> jsEvent)
void V8AbstractEventListener::invokeEventHandler(ScriptState* scriptState, Event* event, v8::Local<v8::Value> jsEvent)
{
// If jsEvent is empty, attempt to set it as a hidden value would crash v8.
if (jsEvent.IsEmpty())
return;

ASSERT(!scriptState()->contextIsEmpty());
v8::Local<v8::Value> returnValue;
{
// Catch exceptions thrown in the event handler so they do not propagate to javascript code that caused the event to fire.
v8::TryCatch tryCatch;
tryCatch.SetVerbose(true);

// Save the old 'event' property so we can restore it later.
v8::Local<v8::Value> savedEvent = V8HiddenValue::getHiddenValue(isolate(), scriptState()->context()->Global(), V8HiddenValue::event(isolate()));
v8::Local<v8::Value> savedEvent = V8HiddenValue::getHiddenValue(isolate(), scriptState->context()->Global(), V8HiddenValue::event(isolate()));
tryCatch.Reset();

// Make the event available in the global object, so LocalDOMWindow can expose it.
V8HiddenValue::setHiddenValue(isolate(), scriptState()->context()->Global(), V8HiddenValue::event(isolate()), jsEvent);
V8HiddenValue::setHiddenValue(isolate(), scriptState->context()->Global(), V8HiddenValue::event(isolate()), jsEvent);
tryCatch.Reset();

returnValue = callListenerFunction(jsEvent, event);
returnValue = callListenerFunction(scriptState, jsEvent, event);
if (tryCatch.HasCaught())
event->target()->uncaughtExceptionInEventHandler();

if (!tryCatch.CanContinue()) { // Result of TerminateExecution().
if (scriptState()->executionContext()->isWorkerGlobalScope())
toWorkerGlobalScope(scriptState()->executionContext())->script()->forbidExecution();
if (scriptState->executionContext()->isWorkerGlobalScope())
toWorkerGlobalScope(scriptState->executionContext())->script()->forbidExecution();
return;
}
tryCatch.Reset();

// Restore the old event. This must be done for all exit paths through this method.
if (savedEvent.IsEmpty())
V8HiddenValue::setHiddenValue(isolate(), scriptState()->context()->Global(), V8HiddenValue::event(isolate()), v8::Undefined(isolate()));
V8HiddenValue::setHiddenValue(isolate(), scriptState->context()->Global(), V8HiddenValue::event(isolate()), v8::Undefined(isolate()));
else
V8HiddenValue::setHiddenValue(isolate(), scriptState()->context()->Global(), V8HiddenValue::event(isolate()), savedEvent);
V8HiddenValue::setHiddenValue(isolate(), scriptState->context()->Global(), V8HiddenValue::event(isolate()), savedEvent);
tryCatch.Reset();
}

Expand All @@ -163,14 +160,14 @@ bool V8AbstractEventListener::shouldPreventDefault(v8::Local<v8::Value> returnVa
return returnValue->IsBoolean() && !returnValue->BooleanValue();
}

v8::Local<v8::Object> V8AbstractEventListener::getReceiverObject(Event* event)
v8::Local<v8::Object> V8AbstractEventListener::getReceiverObject(ScriptState* scriptState, Event* event)
{
v8::Local<v8::Object> listener = m_listener.newLocal(isolate());
if (!m_listener.isEmpty() && !listener->IsFunction())
return listener;

EventTarget* target = event->currentTarget();
v8::Handle<v8::Value> value = toV8(target, scriptState()->context()->Global(), isolate());
v8::Handle<v8::Value> value = toV8(target, scriptState->context()->Global(), isolate());
if (value.IsEmpty())
return v8::Local<v8::Object>();
return v8::Local<v8::Object>::New(isolate(), v8::Handle<v8::Object>::Cast(value));
Expand Down
31 changes: 10 additions & 21 deletions Source/bindings/core/v8/V8AbstractEventListener.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,18 @@ class V8AbstractEventListener : public EventListener {

virtual bool operator==(const EventListener& other) OVERRIDE { return this == &other; }

virtual void handleEvent(ExecutionContext*, Event*) OVERRIDE;

virtual bool isLazy() const { return false; }
virtual void handleEvent(ExecutionContext*, Event*) override final;
virtual void handleEvent(ScriptState*, Event*);

// Returns the listener object, either a function or an object.
v8::Local<v8::Object> getListenerObject(ExecutionContext* context)
v8::Local<v8::Object> getListenerObject(ExecutionContext* executionContext)
{
// prepareListenerObject can potentially deref this event listener
// as it may attempt to compile a function (lazy event listener), get an error
// and invoke onerror callback which can execute arbitrary JS code.
// Protect this event listener to keep it alive.
RefPtr<V8AbstractEventListener> guard(this);
prepareListenerObject(context);
prepareListenerObject(executionContext);
return m_listener.newLocal(m_isolate);
}

Expand Down Expand Up @@ -110,32 +109,25 @@ class V8AbstractEventListener : public EventListener {

virtual bool belongsToTheCurrentWorld() const OVERRIDE FINAL;
v8::Isolate* isolate() const { return m_isolate; }
virtual DOMWrapperWorld& world() const { return scriptState()->world(); }
ScriptState* scriptState() const
{
ASSERT(m_scriptState);
return m_scriptState.get();
}
void setScriptState(ScriptState* scriptState) { m_scriptState = scriptState; }
DOMWrapperWorld& world() const { return *m_world; }

protected:
V8AbstractEventListener(bool isAttribute, ScriptState*);
V8AbstractEventListener(bool isAttribute, v8::Isolate*);
V8AbstractEventListener(bool isAttribute, DOMWrapperWorld&, v8::Isolate*);

virtual void prepareListenerObject(ExecutionContext*) { }

void setListenerObject(v8::Handle<v8::Object>);

void invokeEventHandler(Event*, v8::Local<v8::Value> jsEvent);
void invokeEventHandler(ScriptState*, Event*, v8::Local<v8::Value>);

// Get the receiver object to use for event listener call.
v8::Local<v8::Object> getReceiverObject(Event*);
v8::Local<v8::Object> getReceiverObject(ScriptState*, Event*);

private:
// Implementation of EventListener function.
virtual bool virtualisAttribute() const OVERRIDE { return m_isAttribute; }

virtual v8::Local<v8::Value> callListenerFunction(v8::Handle<v8::Value> jsevent, Event*) = 0;
virtual v8::Local<v8::Value> callListenerFunction(ScriptState*, v8::Handle<v8::Value> jsevent, Event*) = 0;

virtual bool shouldPreventDefault(v8::Local<v8::Value> returnValue);

Expand All @@ -146,10 +138,7 @@ class V8AbstractEventListener : public EventListener {
// Indicates if this is an HTML type listener.
bool m_isAttribute;

// For V8LazyEventListener, m_scriptState can be 0 until V8LazyEventListener is actually used.
// m_scriptState is set lazily because V8LazyEventListener doesn't know the associated frame
// until the listener is actually used.
RefPtr<ScriptState> m_scriptState;
RefPtr<DOMWrapperWorld> m_world;
v8::Isolate* m_isolate;
};

Expand Down
15 changes: 7 additions & 8 deletions Source/bindings/core/v8/V8ErrorHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,21 +47,20 @@ V8ErrorHandler::V8ErrorHandler(v8::Local<v8::Object> listener, bool isInline, Sc
{
}

v8::Local<v8::Value> V8ErrorHandler::callListenerFunction(v8::Handle<v8::Value> jsEvent, Event* event)
v8::Local<v8::Value> V8ErrorHandler::callListenerFunction(ScriptState* scriptState, v8::Handle<v8::Value> jsEvent, Event* event)
{
if (!event->hasInterface(EventNames::ErrorEvent))
return V8EventListener::callListenerFunction(jsEvent, event);
return V8EventListener::callListenerFunction(scriptState, jsEvent, event);

ErrorEvent* errorEvent = static_cast<ErrorEvent*>(event);

if (errorEvent->world() && errorEvent->world() != &world())
return v8::Null(isolate());

v8::Local<v8::Object> listener = getListenerObject(scriptState()->executionContext());
v8::Local<v8::Object> listener = getListenerObject(scriptState->executionContext());
v8::Local<v8::Value> returnValue;
if (!listener.IsEmpty() && listener->IsFunction()) {
v8::Local<v8::Function> callFunction = v8::Local<v8::Function>::Cast(listener);
v8::Local<v8::Object> thisValue = scriptState()->context()->Global();
v8::Local<v8::Object> thisValue = scriptState->context()->Global();

v8::Local<v8::Value> error = V8HiddenValue::getHiddenValue(isolate(), jsEvent->ToObject(), V8HiddenValue::error(isolate()));
if (error.IsEmpty())
Expand All @@ -70,10 +69,10 @@ v8::Local<v8::Value> V8ErrorHandler::callListenerFunction(v8::Handle<v8::Value>
v8::Handle<v8::Value> parameters[5] = { v8String(isolate(), errorEvent->message()), v8String(isolate(), errorEvent->filename()), v8::Integer::New(isolate(), errorEvent->lineno()), v8::Integer::New(isolate(), errorEvent->colno()), error };
v8::TryCatch tryCatch;
tryCatch.SetVerbose(true);
if (scriptState()->executionContext()->isWorkerGlobalScope())
returnValue = V8ScriptRunner::callFunction(callFunction, scriptState()->executionContext(), thisValue, WTF_ARRAY_LENGTH(parameters), parameters, isolate());
if (scriptState->executionContext()->isWorkerGlobalScope())
returnValue = V8ScriptRunner::callFunction(callFunction, scriptState->executionContext(), thisValue, WTF_ARRAY_LENGTH(parameters), parameters, isolate());
else
returnValue = ScriptController::callFunction(scriptState()->executionContext(), callFunction, thisValue, WTF_ARRAY_LENGTH(parameters), parameters, isolate());
returnValue = ScriptController::callFunction(scriptState->executionContext(), callFunction, thisValue, WTF_ARRAY_LENGTH(parameters), parameters, isolate());
}
return returnValue;
}
Expand Down
6 changes: 2 additions & 4 deletions Source/bindings/core/v8/V8ErrorHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,12 @@ class V8ErrorHandler FINAL : public V8EventListener {
{
return adoptRef(new V8ErrorHandler(listener, isInline, scriptState));
}

static void storeExceptionOnErrorEventWrapper(ErrorEvent*, v8::Handle<v8::Value>, v8::Handle<v8::Object> creationContext, v8::Isolate*);

private:
V8ErrorHandler(v8::Local<v8::Object> listener, bool isInline, ScriptState*);

virtual v8::Local<v8::Value> callListenerFunction(v8::Handle<v8::Value> jsEvent, Event*) OVERRIDE;
virtual bool shouldPreventDefault(v8::Local<v8::Value> returnValue) OVERRIDE;
virtual v8::Local<v8::Value> callListenerFunction(ScriptState*, v8::Handle<v8::Value>, Event*) override;
virtual bool shouldPreventDefault(v8::Local<v8::Value> returnValue) override;
};

} // namespace blink
Expand Down
16 changes: 8 additions & 8 deletions Source/bindings/core/v8/V8EventListener.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@
namespace blink {

V8EventListener::V8EventListener(v8::Local<v8::Object> listener, bool isAttribute, ScriptState* scriptState)
: V8AbstractEventListener(isAttribute, scriptState)
: V8AbstractEventListener(isAttribute, scriptState->world(), scriptState->isolate())
{
setListenerObject(listener);
}

v8::Local<v8::Function> V8EventListener::getListenerFunction(ExecutionContext*)
v8::Local<v8::Function> V8EventListener::getListenerFunction(ScriptState* scriptState)
{
v8::Local<v8::Object> listener = getListenerObject(scriptState()->executionContext());
v8::Local<v8::Object> listener = getListenerObject(scriptState->executionContext());

// Has the listener been disposed?
if (listener.IsEmpty())
Expand All @@ -67,17 +67,17 @@ v8::Local<v8::Function> V8EventListener::getListenerFunction(ExecutionContext*)
return v8::Local<v8::Function>();
}

v8::Local<v8::Value> V8EventListener::callListenerFunction(v8::Handle<v8::Value> jsEvent, Event* event)
v8::Local<v8::Value> V8EventListener::callListenerFunction(ScriptState* scriptState, v8::Handle<v8::Value> jsEvent, Event* event)
{
v8::Local<v8::Function> handlerFunction = getListenerFunction(scriptState()->executionContext());
v8::Local<v8::Object> receiver = getReceiverObject(event);
v8::Local<v8::Function> handlerFunction = getListenerFunction(scriptState);
v8::Local<v8::Object> receiver = getReceiverObject(scriptState, event);
if (handlerFunction.IsEmpty() || receiver.IsEmpty())
return v8::Local<v8::Value>();

if (!scriptState()->executionContext()->isDocument())
if (!scriptState->executionContext()->isDocument())
return v8::Local<v8::Value>();

LocalFrame* frame = toDocument(scriptState()->executionContext())->frame();
LocalFrame* frame = toDocument(scriptState->executionContext())->frame();
if (!frame)
return v8::Local<v8::Value>();

Expand Down
6 changes: 2 additions & 4 deletions Source/bindings/core/v8/V8EventListener.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,8 @@ class V8EventListener : public V8AbstractEventListener {

protected:
V8EventListener(v8::Local<v8::Object> listener, bool isAttribute, ScriptState*);

v8::Local<v8::Function> getListenerFunction(ExecutionContext*);

virtual v8::Local<v8::Value> callListenerFunction(v8::Handle<v8::Value> jsEvent, Event*) OVERRIDE;
v8::Local<v8::Function> getListenerFunction(ScriptState*);
virtual v8::Local<v8::Value> callListenerFunction(ScriptState*, v8::Handle<v8::Value>, Event*) override;
};

} // namespace blink
Expand Down
Loading