diff options
Diffstat (limited to 'Source/WebCore/bindings/v8')
28 files changed, 1121 insertions, 527 deletions
diff --git a/Source/WebCore/bindings/v8/DebuggerScript.js b/Source/WebCore/bindings/v8/DebuggerScript.js index 0bed33d..fe6e8ab 100644 --- a/Source/WebCore/bindings/v8/DebuggerScript.js +++ b/Source/WebCore/bindings/v8/DebuggerScript.js @@ -262,5 +262,4 @@ DebuggerScript._frameMirrorToJSCallFrame = function(frameMirror, callerFrame) } return DebuggerScript; - })(); diff --git a/Source/WebCore/bindings/v8/PageScriptDebugServer.cpp b/Source/WebCore/bindings/v8/PageScriptDebugServer.cpp new file mode 100755 index 0000000..f149d8f --- /dev/null +++ b/Source/WebCore/bindings/v8/PageScriptDebugServer.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PageScriptDebugServer.h" + +#if ENABLE(JAVASCRIPT_DEBUGGER) + +#include "Frame.h" +#include "Page.h" +#include "ScriptDebugListener.h" +#include "V8Binding.h" +#include "V8DOMWindow.h" +#include "V8Proxy.h" +#include <wtf/OwnPtr.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/StdLibExtras.h> + +namespace WebCore { + +static Frame* retrieveFrame(v8::Handle<v8::Context> context) +{ + if (context.IsEmpty()) + return 0; + + // Test that context has associated global dom window object. + v8::Handle<v8::Object> global = context->Global(); + if (global.IsEmpty()) + return 0; + + global = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), global); + if (global.IsEmpty()) + return 0; + + return V8Proxy::retrieveFrame(context); +} + +PageScriptDebugServer& PageScriptDebugServer::shared() +{ + DEFINE_STATIC_LOCAL(PageScriptDebugServer, server, ()); + return server; +} + +PageScriptDebugServer::PageScriptDebugServer() + : ScriptDebugServer() + , m_pausedPage(0) + , m_enabled(true) +{ +} + +void PageScriptDebugServer::addListener(ScriptDebugListener* listener, Page* page) +{ + if (!m_enabled) + return; + + V8Proxy* proxy = V8Proxy::retrieve(page->mainFrame()); + if (!proxy) + return; + + v8::HandleScope scope; + v8::Local<v8::Context> debuggerContext = v8::Debug::GetDebugContext(); + v8::Context::Scope contextScope(debuggerContext); + + if (!m_listenersMap.size()) { + ensureDebuggerScriptCompiled(); + ASSERT(!m_debuggerScript.get()->IsUndefined()); + v8::Debug::SetDebugEventListener2(&PageScriptDebugServer::v8DebugEventCallback, v8::External::New(this)); + } + m_listenersMap.set(page, listener); + + V8DOMWindowShell* shell = proxy->windowShell(); + if (!shell->isContextInitialized()) + return; + v8::Handle<v8::Context> context = shell->context(); + v8::Handle<v8::Function> getScriptsFunction = v8::Local<v8::Function>::Cast(m_debuggerScript.get()->Get(v8::String::New("getScripts"))); + v8::Handle<v8::Value> argv[] = { context->GetData() }; + v8::Handle<v8::Value> value = getScriptsFunction->Call(m_debuggerScript.get(), 1, argv); + if (value.IsEmpty()) + return; + ASSERT(!value->IsUndefined() && value->IsArray()); + v8::Handle<v8::Array> scriptsArray = v8::Handle<v8::Array>::Cast(value); + for (unsigned i = 0; i < scriptsArray->Length(); ++i) + dispatchDidParseSource(listener, v8::Handle<v8::Object>::Cast(scriptsArray->Get(v8::Integer::New(i)))); +} + +void PageScriptDebugServer::removeListener(ScriptDebugListener* listener, Page* page) +{ + if (!m_listenersMap.contains(page)) + return; + + if (m_pausedPage == page) + continueProgram(); + + m_listenersMap.remove(page); + + if (m_listenersMap.isEmpty()) + v8::Debug::SetDebugEventListener(0); + // FIXME: Remove all breakpoints set by the agent. +} + +void PageScriptDebugServer::setClientMessageLoop(PassOwnPtr<ClientMessageLoop> clientMessageLoop) +{ + m_clientMessageLoop = clientMessageLoop; +} + +ScriptDebugListener* PageScriptDebugServer::getDebugListenerForContext(v8::Handle<v8::Context> context) +{ + v8::HandleScope scope; + Frame* frame = retrieveFrame(context); + if (!frame) + return 0; + return m_listenersMap.get(frame->page()); +} + +void PageScriptDebugServer::runMessageLoopOnPause(v8::Handle<v8::Context> context) +{ + v8::HandleScope scope; + Frame* frame = retrieveFrame(context); + m_pausedPage = frame->page(); + + // Wait for continue or step command. + m_clientMessageLoop->run(m_pausedPage); + + // The listener may have been removed in the nested loop. + if (ScriptDebugListener* listener = m_listenersMap.get(m_pausedPage)) + listener->didContinue(); + + m_pausedPage = 0; +} + +void PageScriptDebugServer::quitMessageLoopOnPause() +{ + m_clientMessageLoop->quitNow(); +} + +} // namespace WebCore + +#endif // ENABLE(JAVASCRIPT_DEBUGGER) diff --git a/Source/WebCore/bindings/v8/PageScriptDebugServer.h b/Source/WebCore/bindings/v8/PageScriptDebugServer.h new file mode 100755 index 0000000..4b134c1 --- /dev/null +++ b/Source/WebCore/bindings/v8/PageScriptDebugServer.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PageScriptDebugServer_h +#define PageScriptDebugServer_h + +#if ENABLE(JAVASCRIPT_DEBUGGER) + +#include "ScriptDebugServer.h" +#include <wtf/Forward.h> + +namespace WebCore { + +class Page; + +class PageScriptDebugServer : public ScriptDebugServer { + WTF_MAKE_NONCOPYABLE(PageScriptDebugServer); +public: + static PageScriptDebugServer& shared(); + + void addListener(ScriptDebugListener*, Page*); + void removeListener(ScriptDebugListener*, Page*); + + // v8-specific methods. + void setEnabled(bool value) { m_enabled = value; } + + class ClientMessageLoop { + public: + virtual ~ClientMessageLoop() { } + virtual void run(Page*) = 0; + virtual void quitNow() = 0; + }; + void setClientMessageLoop(PassOwnPtr<ClientMessageLoop>); + +private: + PageScriptDebugServer(); + virtual ~PageScriptDebugServer() { } + + virtual ScriptDebugListener* getDebugListenerForContext(v8::Handle<v8::Context>); + virtual void runMessageLoopOnPause(v8::Handle<v8::Context>); + virtual void quitMessageLoopOnPause(); + + typedef HashMap<Page*, ScriptDebugListener*> ListenersMap; + ListenersMap m_listenersMap; + OwnPtr<ClientMessageLoop> m_clientMessageLoop; + Page* m_pausedPage; + bool m_enabled; +}; + +} // namespace WebCore + +#endif // ENABLE(JAVASCRIPT_DEBUGGER) + +#endif // PageScriptDebugServer_h diff --git a/Source/WebCore/bindings/v8/RetainedDOMInfo.cpp b/Source/WebCore/bindings/v8/RetainedDOMInfo.cpp new file mode 100644 index 0000000..ba64263 --- /dev/null +++ b/Source/WebCore/bindings/v8/RetainedDOMInfo.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RetainedDOMInfo.h" + +#include "Node.h" + +namespace WebCore { + +RetainedDOMInfo::RetainedDOMInfo(Node* root) + : m_root(root) +{ + ASSERT(m_root); +} + +RetainedDOMInfo::~RetainedDOMInfo() +{ +} + +void RetainedDOMInfo::Dispose() +{ + delete this; +} + +bool RetainedDOMInfo::IsEquivalent(v8::RetainedObjectInfo* other) +{ + ASSERT(other); + return other == this || static_cast<WebCore::RetainedObjectInfo*>(other)->GetEquivalenceClass() == this->GetEquivalenceClass(); +} + +intptr_t RetainedDOMInfo::GetHash() +{ + return reinterpret_cast<intptr_t>(m_root); +} + +const char* RetainedDOMInfo::GetLabel() +{ + return m_root->inDocument() ? "Document DOM tree" : "Detached DOM tree"; +} + +intptr_t RetainedDOMInfo::GetElementCount() +{ + intptr_t count = 1; + Node* current = m_root; + while (current) { + current = current->traverseNextNode(m_root); + ++count; + } + return count; +} + +intptr_t RetainedDOMInfo::GetEquivalenceClass() +{ + return reinterpret_cast<intptr_t>(m_root); +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/v8/RetainedDOMInfo.h b/Source/WebCore/bindings/v8/RetainedDOMInfo.h new file mode 100644 index 0000000..6767f75 --- /dev/null +++ b/Source/WebCore/bindings/v8/RetainedDOMInfo.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RetainedDOMInfo_h +#define RetainedDOMInfo_h + +#include "RetainedObjectInfo.h" + +namespace WebCore { + +class Node; + +// Implements v8::RetainedObjectInfo. +class RetainedDOMInfo : public RetainedObjectInfo { +public: + explicit RetainedDOMInfo(Node* root); + virtual ~RetainedDOMInfo(); + virtual void Dispose(); + virtual bool IsEquivalent(v8::RetainedObjectInfo* other); + virtual intptr_t GetHash(); + virtual const char* GetLabel(); + virtual intptr_t GetElementCount(); + virtual intptr_t GetEquivalenceClass(); + +private: + // V8 guarantees to keep RetainedObjectInfos alive only during a GC or heap snapshotting round, when renderer + // doesn't get control. This allows us to use raw pointers. + Node* m_root; +}; + +} // namespace WebCore + +#endif // RetainedDOMInfo_h diff --git a/Source/WebCore/bindings/v8/RetainedObjectInfo.h b/Source/WebCore/bindings/v8/RetainedObjectInfo.h new file mode 100644 index 0000000..0368fb1 --- /dev/null +++ b/Source/WebCore/bindings/v8/RetainedObjectInfo.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RetainedObjectInfo_h +#define RetainedObjectInfo_h + +#include <v8-profiler.h> + +namespace WebCore { + +class RetainedObjectInfo : public v8::RetainedObjectInfo { +public: + virtual intptr_t GetEquivalenceClass() = 0; +}; + +} // namespace WebCore + +#endif // RetainedObjectInfo_h diff --git a/Source/WebCore/bindings/v8/ScriptCachedFrameData.cpp b/Source/WebCore/bindings/v8/ScriptCachedFrameData.cpp index dc28f32..9e15d1c 100644 --- a/Source/WebCore/bindings/v8/ScriptCachedFrameData.cpp +++ b/Source/WebCore/bindings/v8/ScriptCachedFrameData.cpp @@ -26,6 +26,10 @@ #include "config.h" #include "ScriptCachedFrameData.h" +#if PLATFORM(ANDROID) || PLATFORM(QT) +// FIXME: the right guard should be ENABLE(PAGE_CACHE). Replace with the right guard, once +// https://bugs.webkit.org/show_bug.cgi?id=35061 is fixed. + #include "Frame.h" #include "ScriptController.h" #include "V8DOMWindow.h" @@ -72,3 +76,5 @@ void ScriptCachedFrameData::clear() } } // namespace WebCore + +#endif // PLATFORM(ANDROID) || PLATFORM(QT) diff --git a/Source/WebCore/bindings/v8/ScriptDebugServer.cpp b/Source/WebCore/bindings/v8/ScriptDebugServer.cpp index cc7fba8..5758639 100644 --- a/Source/WebCore/bindings/v8/ScriptDebugServer.cpp +++ b/Source/WebCore/bindings/v8/ScriptDebugServer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Google Inc. All rights reserved. + * Copyright (c) 2010-2011 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -33,13 +33,10 @@ #if ENABLE(JAVASCRIPT_DEBUGGER) -#include "Frame.h" +#include "DebuggerScriptSource.h" #include "JavaScriptCallFrame.h" -#include "Page.h" #include "ScriptDebugListener.h" #include "V8Binding.h" -#include "V8DOMWindow.h" -#include "V8Proxy.h" #include <wtf/StdLibExtras.h> namespace WebCore { @@ -57,92 +54,12 @@ private: } -static Frame* retrieveFrame(v8::Handle<v8::Context> context) -{ - if (context.IsEmpty()) - return 0; - - // Test that context has associated global dom window object. - v8::Handle<v8::Object> global = context->Global(); - if (global.IsEmpty()) - return 0; - - global = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), global); - if (global.IsEmpty()) - return 0; - - return V8Proxy::retrieveFrame(context); -} - -ScriptDebugServer& ScriptDebugServer::shared() -{ - DEFINE_STATIC_LOCAL(ScriptDebugServer, server, ()); - return server; -} - ScriptDebugServer::ScriptDebugServer() : m_pauseOnExceptionsState(DontPauseOnExceptions) - , m_pausedPage(0) - , m_enabled(true) , m_breakpointsActivated(true) { } -void ScriptDebugServer::setDebuggerScriptSource(const String& scriptSource) -{ - m_debuggerScriptSource = scriptSource; -} - -void ScriptDebugServer::addListener(ScriptDebugListener* listener, Page* page) -{ - if (!m_enabled) - return; - - V8Proxy* proxy = V8Proxy::retrieve(page->mainFrame()); - if (!proxy) - return; - - v8::HandleScope scope; - v8::Local<v8::Context> debuggerContext = v8::Debug::GetDebugContext(); - v8::Context::Scope contextScope(debuggerContext); - - if (!m_listenersMap.size()) { - ensureDebuggerScriptCompiled(); - ASSERT(!m_debuggerScript.get()->IsUndefined()); - v8::Debug::SetDebugEventListener2(&ScriptDebugServer::v8DebugEventCallback); - } - m_listenersMap.set(page, listener); - - V8DOMWindowShell* shell = proxy->windowShell(); - if (!shell->isContextInitialized()) - return; - v8::Handle<v8::Context> context = shell->context(); - v8::Handle<v8::Function> getScriptsFunction = v8::Local<v8::Function>::Cast(m_debuggerScript.get()->Get(v8::String::New("getScripts"))); - v8::Handle<v8::Value> argv[] = { context->GetData() }; - v8::Handle<v8::Value> value = getScriptsFunction->Call(m_debuggerScript.get(), 1, argv); - if (value.IsEmpty()) - return; - ASSERT(!value->IsUndefined() && value->IsArray()); - v8::Handle<v8::Array> scriptsArray = v8::Handle<v8::Array>::Cast(value); - for (unsigned i = 0; i < scriptsArray->Length(); ++i) - dispatchDidParseSource(listener, v8::Handle<v8::Object>::Cast(scriptsArray->Get(v8::Integer::New(i)))); -} - -void ScriptDebugServer::removeListener(ScriptDebugListener* listener, Page* page) -{ - if (!m_listenersMap.contains(page)) - return; - - if (m_pausedPage == page) - continueProgram(); - - m_listenersMap.remove(page); - - if (m_listenersMap.isEmpty()) - v8::Debug::SetDebugEventListener(0); - // FIXME: Remove all breakpoints set by the agent. -} - String ScriptDebugServer::setBreakpoint(const String& sourceID, const ScriptBreakpoint& scriptBreakpoint, int* actualLineNumber, int* actualColumnNumber) { v8::HandleScope scope; @@ -229,7 +146,7 @@ void ScriptDebugServer::setPauseOnExceptionsState(PauseOnExceptionsState pauseOn void ScriptDebugServer::setPauseOnNextStatement(bool pause) { - if (m_pausedPage) + if (isPaused()) return; if (pause) v8::Debug::DebugBreak(); @@ -239,17 +156,15 @@ void ScriptDebugServer::setPauseOnNextStatement(bool pause) void ScriptDebugServer::breakProgram() { - DEFINE_STATIC_LOCAL(v8::Persistent<v8::FunctionTemplate>, callbackTemplate, ()); - if (!m_breakpointsActivated) return; if (!v8::Context::InContext()) return; - if (callbackTemplate.IsEmpty()) { - callbackTemplate = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New()); - callbackTemplate->SetCallHandler(&ScriptDebugServer::breakProgramCallback); + if (m_breakProgramCallbackTemplate.get().IsEmpty()) { + m_breakProgramCallbackTemplate.set(v8::FunctionTemplate::New()); + m_breakProgramCallbackTemplate.get()->SetCallHandler(&ScriptDebugServer::breakProgramCallback, v8::External::New(this)); } v8::Handle<v8::Context> context = v8::Context::GetCurrent(); @@ -257,21 +172,22 @@ void ScriptDebugServer::breakProgram() return; m_pausedPageContext = *context; - v8::Handle<v8::Function> breakProgramFunction = callbackTemplate->GetFunction(); + v8::Handle<v8::Function> breakProgramFunction = m_breakProgramCallbackTemplate.get()->GetFunction(); v8::Debug::Call(breakProgramFunction); m_pausedPageContext.Clear(); } void ScriptDebugServer::continueProgram() { - if (m_pausedPage) - m_clientMessageLoop->quitNow(); - didResume(); + if (isPaused()) + quitMessageLoopOnPause(); + m_currentCallFrame.clear(); + m_executionState.clear(); } void ScriptDebugServer::stepIntoStatement() { - ASSERT(m_pausedPage); + ASSERT(isPaused()); v8::Handle<v8::Function> function = v8::Local<v8::Function>::Cast(m_debuggerScript.get()->Get(v8::String::New("stepIntoStatement"))); v8::Handle<v8::Value> argv[] = { m_executionState.get() }; function->Call(m_debuggerScript.get(), 1, argv); @@ -280,7 +196,7 @@ void ScriptDebugServer::stepIntoStatement() void ScriptDebugServer::stepOverStatement() { - ASSERT(m_pausedPage); + ASSERT(isPaused()); v8::Handle<v8::Function> function = v8::Local<v8::Function>::Cast(m_debuggerScript.get()->Get(v8::String::New("stepOverStatement"))); v8::Handle<v8::Value> argv[] = { m_executionState.get() }; function->Call(m_debuggerScript.get(), 1, argv); @@ -289,7 +205,7 @@ void ScriptDebugServer::stepOverStatement() void ScriptDebugServer::stepOutOfFunction() { - ASSERT(m_pausedPage); + ASSERT(isPaused()); v8::Handle<v8::Function> function = v8::Local<v8::Function>::Cast(m_debuggerScript.get()->Get(v8::String::New("stepOutOfFunction"))); v8::Handle<v8::Value> argv[] = { m_executionState.get() }; function->Call(m_debuggerScript.get(), 1, argv); @@ -302,7 +218,7 @@ bool ScriptDebugServer::editScriptSource(const String& sourceID, const String& n v8::HandleScope scope; OwnPtr<v8::Context::Scope> contextScope; - if (!m_pausedPage) + if (!isPaused()) contextScope.set(new v8::Context::Scope(v8::Debug::GetDebugContext())); v8::Handle<v8::Function> function = v8::Local<v8::Function>::Cast(m_debuggerScript.get()->Get(v8::String::New("editScriptSource"))); @@ -337,11 +253,6 @@ PassRefPtr<JavaScriptCallFrame> ScriptDebugServer::currentCallFrame() return m_currentCallFrame; } -void ScriptDebugServer::setEnabled(bool value) -{ - m_enabled = value; -} - void ScriptDebugServer::interruptAndRun(PassOwnPtr<Task> task) { v8::Debug::DebugBreakForCommand(new ClientDataImpl(task)); @@ -352,44 +263,42 @@ void ScriptDebugServer::runPendingTasks() v8::Debug::ProcessDebugMessages(); } +static ScriptDebugServer* toScriptDebugServer(v8::Handle<v8::Value> data) +{ + void* p = v8::Handle<v8::External>::Cast(data)->Value(); + return static_cast<ScriptDebugServer*>(p); +} + v8::Handle<v8::Value> ScriptDebugServer::breakProgramCallback(const v8::Arguments& args) { ASSERT(2 == args.Length()); - ScriptDebugServer::shared().breakProgram(v8::Handle<v8::Object>::Cast(args[0])); + + ScriptDebugServer* thisPtr = toScriptDebugServer(args.Data()); + thisPtr->breakProgram(v8::Handle<v8::Object>::Cast(args[0])); return v8::Undefined(); } void ScriptDebugServer::breakProgram(v8::Handle<v8::Object> executionState) { // Don't allow nested breaks. - if (m_pausedPage) - return; - - Frame* frame = retrieveFrame(m_pausedPageContext); - if (!frame) + if (isPaused()) return; - ScriptDebugListener* listener = m_listenersMap.get(frame->page()); + ScriptDebugListener* listener = getDebugListenerForContext(m_pausedPageContext); if (!listener) return; m_executionState.set(executionState); - m_pausedPage = frame->page(); ScriptState* currentCallFrameState = ScriptState::forContext(m_pausedPageContext); listener->didPause(currentCallFrameState); - // Wait for continue or step command. - m_clientMessageLoop->run(m_pausedPage); - ASSERT(!m_pausedPage); - - // The listener may have been removed in the nested loop. - if (ScriptDebugListener* listener = m_listenersMap.get(frame->page())) - listener->didContinue(); + runMessageLoopOnPause(m_pausedPageContext); } void ScriptDebugServer::v8DebugEventCallback(const v8::Debug::EventDetails& eventDetails) { - ScriptDebugServer::shared().handleV8DebugEvent(eventDetails); + ScriptDebugServer* thisPtr = toScriptDebugServer(eventDetails.GetCallbackData()); + thisPtr->handleV8DebugEvent(eventDetails); } void ScriptDebugServer::handleV8DebugEvent(const v8::Debug::EventDetails& eventDetails) @@ -408,31 +317,28 @@ void ScriptDebugServer::handleV8DebugEvent(const v8::Debug::EventDetails& eventD v8::Handle<v8::Context> eventContext = eventDetails.GetEventContext(); ASSERT(!eventContext.IsEmpty()); - Frame* frame = retrieveFrame(eventContext); - if (frame) { - ScriptDebugListener* listener = m_listenersMap.get(frame->page()); - if (listener) { - v8::HandleScope scope; - if (event == v8::AfterCompile) { - v8::Context::Scope contextScope(v8::Debug::GetDebugContext()); - v8::Handle<v8::Function> onAfterCompileFunction = v8::Local<v8::Function>::Cast(m_debuggerScript.get()->Get(v8::String::New("getAfterCompileScript"))); - v8::Handle<v8::Value> argv[] = { eventDetails.GetEventData() }; - v8::Handle<v8::Value> value = onAfterCompileFunction->Call(m_debuggerScript.get(), 1, argv); - ASSERT(value->IsObject()); - v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value); - dispatchDidParseSource(listener, object); - } else if (event == v8::Break || event == v8::Exception) { - if (event == v8::Exception) { - v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(1); - // Stack trace is empty in case of syntax error. Silently continue execution in such cases. - if (!stackTrace->GetFrameCount()) - return; - } - - m_pausedPageContext = *eventContext; - breakProgram(eventDetails.GetExecutionState()); - m_pausedPageContext.Clear(); + ScriptDebugListener* listener = getDebugListenerForContext(eventContext); + if (listener) { + v8::HandleScope scope; + if (event == v8::AfterCompile) { + v8::Context::Scope contextScope(v8::Debug::GetDebugContext()); + v8::Handle<v8::Function> onAfterCompileFunction = v8::Local<v8::Function>::Cast(m_debuggerScript.get()->Get(v8::String::New("getAfterCompileScript"))); + v8::Handle<v8::Value> argv[] = { eventDetails.GetEventData() }; + v8::Handle<v8::Value> value = onAfterCompileFunction->Call(m_debuggerScript.get(), 1, argv); + ASSERT(value->IsObject()); + v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value); + dispatchDidParseSource(listener, object); + } else if (event == v8::Break || event == v8::Exception) { + if (event == v8::Exception) { + v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(1); + // Stack trace is empty in case of syntax error. Silently continue execution in such cases. + if (!stackTrace->GetFrameCount()) + return; } + + m_pausedPageContext = *eventContext; + breakProgram(eventDetails.GetExecutionState()); + m_pausedPageContext.Clear(); } } } @@ -454,15 +360,14 @@ void ScriptDebugServer::ensureDebuggerScriptCompiled() v8::HandleScope scope; v8::Local<v8::Context> debuggerContext = v8::Debug::GetDebugContext(); v8::Context::Scope contextScope(debuggerContext); - m_debuggerScript.set(v8::Handle<v8::Object>::Cast(v8::Script::Compile(v8String(m_debuggerScriptSource))->Run())); + String debuggerScriptSource(reinterpret_cast<const char*>(DebuggerScriptSource_js), sizeof(DebuggerScriptSource_js)); + m_debuggerScript.set(v8::Handle<v8::Object>::Cast(v8::Script::Compile(v8String(debuggerScriptSource))->Run())); } } -void ScriptDebugServer::didResume() +bool ScriptDebugServer::isPaused() { - m_currentCallFrame.clear(); - m_executionState.clear(); - m_pausedPage = 0; + return !m_executionState.get().IsEmpty(); } } // namespace WebCore diff --git a/Source/WebCore/bindings/v8/ScriptDebugServer.h b/Source/WebCore/bindings/v8/ScriptDebugServer.h index af3d2ab..15004ea 100644 --- a/Source/WebCore/bindings/v8/ScriptDebugServer.h +++ b/Source/WebCore/bindings/v8/ScriptDebugServer.h @@ -45,17 +45,11 @@ namespace WebCore { -class Page; class ScriptDebugListener; class ScriptDebugServer { WTF_MAKE_NONCOPYABLE(ScriptDebugServer); public: - static ScriptDebugServer& shared(); - - void addListener(ScriptDebugListener*, Page*); - void removeListener(ScriptDebugListener*, Page*); - String setBreakpoint(const String& sourceID, const ScriptBreakpoint&, int* actualLineNumber, int* actualColumnNumber); void removeBreakpoint(const String& breakpointId); void clearBreakpoints(); @@ -83,23 +77,8 @@ public: void recompileAllJSFunctionsSoon() { } void recompileAllJSFunctions(Timer<ScriptDebugServer>* = 0) { } - void pageCreated(Page*) { } - - // v8-specific methods. - void setDebuggerScriptSource(const String& scriptSource); - - class ClientMessageLoop { - public: - virtual ~ClientMessageLoop() { } - virtual void run(Page*) = 0; - virtual void quitNow() = 0; - }; - void setClientMessageLoop(PassOwnPtr<ClientMessageLoop> clientMessageLoop) { m_clientMessageLoop = clientMessageLoop; } - PassRefPtr<JavaScriptCallFrame> currentCallFrame(); - void setEnabled(bool); - class Task { public: virtual ~Task() { } @@ -108,9 +87,13 @@ public: static void interruptAndRun(PassOwnPtr<Task>); void runPendingTasks(); -private: +protected: ScriptDebugServer(); ~ScriptDebugServer() { } + + virtual ScriptDebugListener* getDebugListenerForContext(v8::Handle<v8::Context>) = 0; + virtual void runMessageLoopOnPause(v8::Handle<v8::Context>) = 0; + virtual void quitMessageLoopOnPause() = 0; static v8::Handle<v8::Value> breakProgramCallback(const v8::Arguments& args); void breakProgram(v8::Handle<v8::Object> executionState); @@ -121,21 +104,17 @@ private: void dispatchDidParseSource(ScriptDebugListener* listener, v8::Handle<v8::Object> sourceObject); void ensureDebuggerScriptCompiled(); - void didResume(); + + bool isPaused(); - typedef HashMap<Page*, ScriptDebugListener*> ListenersMap; - ListenersMap m_listenersMap; - String m_debuggerScriptSource; PauseOnExceptionsState m_pauseOnExceptionsState; OwnHandle<v8::Object> m_debuggerScript; RefPtr<JavaScriptCallFrame> m_currentCallFrame; OwnHandle<v8::Object> m_executionState; - OwnPtr<ClientMessageLoop> m_clientMessageLoop; - Page* m_pausedPage; v8::Local<v8::Context> m_pausedPageContext; - bool m_enabled; bool m_breakpointsActivated; + OwnHandle<v8::FunctionTemplate> m_breakProgramCallbackTemplate; }; } // namespace WebCore diff --git a/Source/WebCore/bindings/v8/ScriptHeapSnapshot.cpp b/Source/WebCore/bindings/v8/ScriptHeapSnapshot.cpp index 09e1e54..68ed8da 100644 --- a/Source/WebCore/bindings/v8/ScriptHeapSnapshot.cpp +++ b/Source/WebCore/bindings/v8/ScriptHeapSnapshot.cpp @@ -40,6 +40,11 @@ namespace WebCore { +ScriptHeapSnapshot::~ScriptHeapSnapshot() +{ + const_cast<v8::HeapSnapshot*>(m_snapshot)->Delete(); +} + String ScriptHeapSnapshot::title() const { v8::HandleScope scope; @@ -76,10 +81,4 @@ void ScriptHeapSnapshot::writeJSON(ScriptHeapSnapshot::OutputStream* stream) m_snapshot->Serialize(&outputStream, v8::HeapSnapshot::kJSON); } -int ScriptHeapSnapshot::exactRetainedSize(uint64_t nodeId) -{ - const v8::HeapGraphNode* node = m_snapshot->GetNodeById(nodeId); - return node ? node->GetRetainedSize(true) : -1; -} - } // namespace WebCore diff --git a/Source/WebCore/bindings/v8/ScriptHeapSnapshot.h b/Source/WebCore/bindings/v8/ScriptHeapSnapshot.h index 6cfd76d..4093fa7 100644 --- a/Source/WebCore/bindings/v8/ScriptHeapSnapshot.h +++ b/Source/WebCore/bindings/v8/ScriptHeapSnapshot.h @@ -54,12 +54,11 @@ public: { return adoptRef(new ScriptHeapSnapshot(snapshot)); } - virtual ~ScriptHeapSnapshot() {} + virtual ~ScriptHeapSnapshot(); String title() const; unsigned int uid() const; void writeJSON(OutputStream* stream); - int exactRetainedSize(uint64_t nodeId); private: ScriptHeapSnapshot(const v8::HeapSnapshot* snapshot) diff --git a/Source/WebCore/bindings/v8/ScriptProfile.cpp b/Source/WebCore/bindings/v8/ScriptProfile.cpp index c5a6dbf..2c9f0f5 100644 --- a/Source/WebCore/bindings/v8/ScriptProfile.cpp +++ b/Source/WebCore/bindings/v8/ScriptProfile.cpp @@ -39,6 +39,11 @@ namespace WebCore { +ScriptProfile::~ScriptProfile() +{ + const_cast<v8::CpuProfile*>(m_profile)->Delete(); +} + String ScriptProfile::title() const { v8::HandleScope scope; diff --git a/Source/WebCore/bindings/v8/ScriptProfile.h b/Source/WebCore/bindings/v8/ScriptProfile.h index 0182669..d8196a4 100644 --- a/Source/WebCore/bindings/v8/ScriptProfile.h +++ b/Source/WebCore/bindings/v8/ScriptProfile.h @@ -48,7 +48,7 @@ public: { return adoptRef(new ScriptProfile(profile)); } - virtual ~ScriptProfile() {} + virtual ~ScriptProfile(); String title() const; unsigned int uid() const; diff --git a/Source/WebCore/bindings/v8/ScriptProfiler.cpp b/Source/WebCore/bindings/v8/ScriptProfiler.cpp index 615dcfc..21537f4 100644 --- a/Source/WebCore/bindings/v8/ScriptProfiler.cpp +++ b/Source/WebCore/bindings/v8/ScriptProfiler.cpp @@ -32,12 +32,15 @@ #include "ScriptProfiler.h" #include "InspectorValues.h" +#include "RetainedDOMInfo.h" +#include "V8Binding.h" +#include "V8Node.h" #include <v8-profiler.h> -#include <V8Binding.h> namespace WebCore { +#if ENABLE(INSPECTOR) void ScriptProfiler::start(ScriptState* state, const String& title) { v8::HandleScope hs; @@ -53,6 +56,14 @@ PassRefPtr<ScriptProfile> ScriptProfiler::stop(ScriptState* state, const String& return profile ? ScriptProfile::create(profile) : 0; } +void ScriptProfiler::collectGarbage() +{ + // NOTE : There is currently no direct way to collect memory from the v8 C++ API + // but notifying low-memory forces a mark-compact, which is exactly what we want + // in this case. + v8::V8::LowMemoryNotification(); +} + namespace { class ActivityControlAdapter : public v8::ActivityControl { @@ -90,4 +101,22 @@ PassRefPtr<ScriptHeapSnapshot> ScriptProfiler::takeHeapSnapshot(const String& ti return snapshot ? ScriptHeapSnapshot::create(snapshot) : 0; } +static v8::RetainedObjectInfo* retainedDOMInfo(uint16_t classId, v8::Handle<v8::Value> wrapper) +{ + ASSERT(classId == v8DOMSubtreeClassId); + if (!wrapper->IsObject()) + return 0; + Node* node = V8Node::toNative(wrapper.As<v8::Object>()); + return node ? new RetainedDOMInfo(node) : 0; +} +#endif // ENABLE(INSPECTOR) + +void ScriptProfiler::initialize() +{ +#if ENABLE(INSPECTOR) + v8::HeapProfiler::DefineWrapperClass(v8DOMSubtreeClassId, &retainedDOMInfo); +#endif // ENABLE(INSPECTOR) +} + + } // namespace WebCore diff --git a/Source/WebCore/bindings/v8/ScriptProfiler.h b/Source/WebCore/bindings/v8/ScriptProfiler.h index 9016668..92a980b 100644 --- a/Source/WebCore/bindings/v8/ScriptProfiler.h +++ b/Source/WebCore/bindings/v8/ScriptProfiler.h @@ -53,9 +53,11 @@ public: virtual bool isCanceled() = 0; }; + static void collectGarbage(); static void start(ScriptState* state, const String& title); static PassRefPtr<ScriptProfile> stop(ScriptState* state, const String& title); static PassRefPtr<ScriptHeapSnapshot> takeHeapSnapshot(const String& title, HeapSnapshotProgress*); + static void initialize(); }; } // namespace WebCore diff --git a/Source/WebCore/bindings/v8/SerializedScriptValue.h b/Source/WebCore/bindings/v8/SerializedScriptValue.h index c0e9109..212be66 100644 --- a/Source/WebCore/bindings/v8/SerializedScriptValue.h +++ b/Source/WebCore/bindings/v8/SerializedScriptValue.h @@ -37,7 +37,7 @@ namespace WebCore { -class SerializedScriptValue : public ThreadSafeShared<SerializedScriptValue> { +class SerializedScriptValue : public ThreadSafeRefCounted<SerializedScriptValue> { public: static void deserializeAndSetProperty(v8::Handle<v8::Object>, const char* propertyName, v8::PropertyAttribute, SerializedScriptValue*); diff --git a/Source/WebCore/bindings/v8/V8DOMWindowShell.cpp b/Source/WebCore/bindings/v8/V8DOMWindowShell.cpp index d88d8a6..e025008 100644 --- a/Source/WebCore/bindings/v8/V8DOMWindowShell.cpp +++ b/Source/WebCore/bindings/v8/V8DOMWindowShell.cpp @@ -43,6 +43,7 @@ #include "ScriptCallStack.h" #include "ScriptCallStackFactory.h" #include "ScriptController.h" +#include "ScriptProfiler.h" #include "StorageNamespace.h" #include "V8Binding.h" #include "V8BindingState.h" @@ -305,6 +306,8 @@ bool V8DOMWindowShell::initContextIfNeeded() v8::V8::SetFailedAccessCheckCallbackFunction(reportUnsafeJavaScriptAccess); + ScriptProfiler::initialize(); + isV8Initialized = true; } diff --git a/Source/WebCore/bindings/v8/V8GCController.cpp b/Source/WebCore/bindings/v8/V8GCController.cpp index cda9f3d..82c9ca4 100644 --- a/Source/WebCore/bindings/v8/V8GCController.cpp +++ b/Source/WebCore/bindings/v8/V8GCController.cpp @@ -34,27 +34,20 @@ #include "ActiveDOMObject.h" #include "Attr.h" #include "DOMDataStore.h" -#include "Frame.h" +#include "DOMImplementation.h" #include "HTMLImageElement.h" #include "HTMLNames.h" #include "MessagePort.h" #include "PlatformBridge.h" -#include "SVGElement.h" +#include "RetainedDOMInfo.h" +#include "RetainedObjectInfo.h" #include "V8Binding.h" -#include "V8CSSCharsetRule.h" -#include "V8CSSFontFaceRule.h" -#include "V8CSSImportRule.h" -#include "V8CSSMediaRule.h" +#include "V8CSSRule.h" #include "V8CSSRuleList.h" #include "V8CSSStyleDeclaration.h" -#include "V8CSSStyleRule.h" -#include "V8CSSStyleSheet.h" -#include "V8DOMMap.h" -#include "V8HTMLLinkElement.h" -#include "V8HTMLStyleElement.h" +#include "V8DOMImplementation.h" #include "V8MessagePort.h" -#include "V8ProcessingInstruction.h" -#include "V8Proxy.h" +#include "V8StyleSheet.h" #include "V8StyleSheetList.h" #include "WrapperTypeInfo.h" @@ -175,19 +168,86 @@ public: } }; -class GrouperItem { +// Implements v8::RetainedObjectInfo. +class UnspecifiedGroup : public RetainedObjectInfo { public: - GrouperItem(uintptr_t groupId, v8::Persistent<v8::Object> wrapper) - : m_groupId(groupId) - , m_wrapper(wrapper) - { - } + explicit UnspecifiedGroup(void* object) + : m_object(object) + { + ASSERT(m_object); + } + + virtual void Dispose() { delete this; } + + virtual bool IsEquivalent(v8::RetainedObjectInfo* other) + { + ASSERT(other); + return other == this || static_cast<WebCore::RetainedObjectInfo*>(other)->GetEquivalenceClass() == this->GetEquivalenceClass(); + } + virtual intptr_t GetHash() + { + return reinterpret_cast<intptr_t>(m_object); + } + + virtual const char* GetLabel() + { + return "Object group"; + } + + virtual intptr_t GetEquivalenceClass() + { + return reinterpret_cast<intptr_t>(m_object); + } + +private: + void* m_object; +}; + +class GroupId { +public: + GroupId() : m_type(NullType), m_groupId(0) {} + GroupId(Node* node) : m_type(NodeType), m_node(node) {} + GroupId(void* other) : m_type(OtherType), m_other(other) {} + bool operator!() const { return m_type == NullType; } uintptr_t groupId() const { return m_groupId; } + RetainedObjectInfo* createRetainedObjectInfo() const + { + switch (m_type) { + case NullType: + return 0; + case NodeType: + return new RetainedDOMInfo(m_node); + case OtherType: + return new UnspecifiedGroup(m_other); + default: + return 0; + } + } + +private: + enum Type { + NullType, + NodeType, + OtherType + }; + Type m_type; + union { + uintptr_t m_groupId; + Node* m_node; + void* m_other; + }; +}; + +class GrouperItem { +public: + GrouperItem(GroupId groupId, v8::Persistent<v8::Object> wrapper) : m_groupId(groupId), m_wrapper(wrapper) {} + uintptr_t groupId() const { return m_groupId.groupId(); } + RetainedObjectInfo* createRetainedObjectInfo() const { return m_groupId.createRetainedObjectInfo(); } v8::Persistent<v8::Object> wrapper() const { return m_wrapper; } private: - uintptr_t m_groupId; + GroupId m_groupId; v8::Persistent<v8::Object> m_wrapper; }; @@ -198,215 +258,160 @@ bool operator<(const GrouperItem& a, const GrouperItem& b) typedef Vector<GrouperItem> GrouperList; -void makeV8ObjectGroups(GrouperList& grouper) +// If the node is in document, put it in the ownerDocument's object group. +// +// If an image element was created by JavaScript "new Image", +// it is not in a document. However, if the load event has not +// been fired (still onloading), it is treated as in the document. +// +// Otherwise, the node is put in an object group identified by the root +// element of the tree to which it belongs. +static GroupId calculateGroupId(Node* node) { - // Group by sorting by the group id. - std::sort(grouper.begin(), grouper.end()); - - // FIXME Should probably work in iterators here, but indexes were easier for my simple mind. - for (size_t i = 0; i < grouper.size(); ) { - // Seek to the next key (or the end of the list). - size_t nextKeyIndex = grouper.size(); - for (size_t j = i; j < grouper.size(); ++j) { - if (grouper[i].groupId() != grouper[j].groupId()) { - nextKeyIndex = j; - break; - } - } + if (node->inDocument() || (node->hasTagName(HTMLNames::imgTag) && !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent())) + return GroupId(node->document()); + + Node* root = node; + if (node->isAttributeNode()) { + root = static_cast<Attr*>(node)->ownerElement(); + // If the attribute has no element, no need to put it in the group, + // because it'll always be a group of 1. + if (!root) + return GroupId(); + } else { + while (Node* parent = root->parentNode()) + root = parent; + } - ASSERT(nextKeyIndex > i); + return GroupId(root); +} - // We only care about a group if it has more than one object. If it only - // has one object, it has nothing else that needs to be kept alive. - if (nextKeyIndex - i <= 1) { - i = nextKeyIndex; - continue; +static GroupId calculateGroupId(StyleBase* styleBase) +{ + ASSERT(styleBase); + StyleBase* current = styleBase; + StyleSheet* styleSheet = 0; + while (true) { + // Special case: CSSStyleDeclarations might be either inline and in this case + // we need to group them with their node or regular ones. + if (current->isMutableStyleDeclaration()) { + CSSMutableStyleDeclaration* cssMutableStyleDeclaration = static_cast<CSSMutableStyleDeclaration*>(current); + if (cssMutableStyleDeclaration->isInlineStyleDeclaration()) { + ASSERT(cssMutableStyleDeclaration->parent()->isStyleSheet()); + return calculateGroupId(cssMutableStyleDeclaration->node()); + } + // Either we have no parent, or this parent is a CSSRule. + ASSERT(cssMutableStyleDeclaration->parent() == cssMutableStyleDeclaration->parentRule()); } - Vector<v8::Persistent<v8::Value> > group; - group.reserveCapacity(nextKeyIndex - i); - for (; i < nextKeyIndex; ++i) { - v8::Persistent<v8::Value> wrapper = grouper[i].wrapper(); - if (!wrapper.IsEmpty()) - group.append(wrapper); - } + if (current->isStyleSheet()) + styleSheet = static_cast<StyleSheet*>(current); - if (group.size() > 1) - v8::V8::AddObjectGroup(&group[0], group.size()); + StyleBase* parent = current->parent(); + if (!parent) + break; + current = parent; + } - ASSERT(i == nextKeyIndex); + if (styleSheet) { + if (Node* ownerNode = styleSheet->ownerNode()) + return calculateGroupId(ownerNode); + return GroupId(styleSheet); } + + return GroupId(current); } -class NodeGrouperVisitor : public DOMWrapperMap<Node>::Visitor { +class GrouperVisitor : public DOMWrapperMap<Node>::Visitor, public DOMWrapperMap<void>::Visitor { public: - NodeGrouperVisitor() - { - // FIXME: grouper_.reserveCapacity(node_map.size()); ? - } - void visitDOMWrapper(DOMDataStore* store, Node* node, v8::Persistent<v8::Object> wrapper) { - // If the node is in document, put it in the ownerDocument's object group. - // - // If an image element was created by JavaScript "new Image", - // it is not in a document. However, if the load event has not - // been fired (still onloading), it is treated as in the document. - // - // Otherwise, the node is put in an object group identified by the root - // element of the tree to which it belongs. - uintptr_t groupId; - if (node->inDocument() || (node->hasTagName(HTMLNames::imgTag) && !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent())) - groupId = reinterpret_cast<uintptr_t>(node->document()); - else { - Node* root = node; - if (node->isAttributeNode()) { - root = static_cast<Attr*>(node)->ownerElement(); - // If the attribute has no element, no need to put it in the group, - // because it'll always be a group of 1. - if (!root) - return; - } else { - while (root->parentNode()) - root = root->parentNode(); - - // If the node is alone in its DOM tree (doesn't have a parent or any - // children) then the group will be filtered out later anyway. - if (root == node && !node->hasChildNodes() && !node->hasAttributes()) - return; - } - groupId = reinterpret_cast<uintptr_t>(root); - } + GroupId groupId = calculateGroupId(node); + if (!groupId) + return; m_grouper.append(GrouperItem(groupId, wrapper)); + } - // If the node is styled and there is a wrapper for the inline - // style declaration, we need to keep that style declaration - // wrapper alive as well, so we add it to the object group. - if (node->isStyledElement()) { - StyledElement* element = reinterpret_cast<StyledElement*>(node); - addDOMObjectToGroup(store, groupId, element->inlineStyleDecl()); - } - - if (node->isDocumentNode()) { - Document* document = reinterpret_cast<Document*>(node); - addDOMObjectToGroup(store, groupId, document->styleSheets()); - addDOMObjectToGroup(store, groupId, document->implementation()); - } - + void visitDOMWrapper(DOMDataStore* store, void* object, v8::Persistent<v8::Object> wrapper) + { WrapperTypeInfo* typeInfo = V8DOMWrapper::domWrapperType(wrapper); - if (V8HTMLLinkElement::info.equals(typeInfo)) { - HTMLLinkElement* htmlLinkElement = static_cast<HTMLLinkElement*>(node); - addDOMObjectToGroup(store, groupId, htmlLinkElement->sheet()); - } + if (typeInfo->isSubclass(&V8StyleSheetList::info)) { + StyleSheetList* styleSheetList = static_cast<StyleSheetList*>(object); + GroupId groupId(styleSheetList); + if (Document* document = styleSheetList->document()) + groupId = GroupId(document); + m_grouper.append(GrouperItem(groupId, wrapper)); - if (V8HTMLStyleElement::info.equals(typeInfo)) { - HTMLStyleElement* htmlStyleElement = static_cast<HTMLStyleElement*>(node); - addDOMObjectToGroup(store, groupId, htmlStyleElement->sheet()); - } + } else if (typeInfo->isSubclass(&V8DOMImplementation::info)) { + DOMImplementation* domImplementation = static_cast<DOMImplementation*>(object); + GroupId groupId(domImplementation); + if (Document* document = domImplementation->ownerDocument()) + groupId = GroupId(document); + m_grouper.append(GrouperItem(groupId, wrapper)); - if (V8ProcessingInstruction::info.equals(typeInfo)) { - ProcessingInstruction* processingInstruction = static_cast<ProcessingInstruction*>(node); - addDOMObjectToGroup(store, groupId, processingInstruction->sheet()); - } - } + } else if (typeInfo->isSubclass(&V8StyleSheet::info) || typeInfo->isSubclass(&V8CSSRule::info)) { + m_grouper.append(GrouperItem(calculateGroupId(static_cast<StyleBase*>(object)), wrapper)); - void applyGrouping() - { - makeV8ObjectGroups(m_grouper); - } - -private: - GrouperList m_grouper; + } else if (typeInfo->isSubclass(&V8CSSStyleDeclaration::info)) { + CSSStyleDeclaration* cssStyleDeclaration = static_cast<CSSStyleDeclaration*>(object); - void addDOMObjectToGroup(DOMDataStore* store, uintptr_t groupId, void* object) - { - if (!object) - return; - v8::Persistent<v8::Object> wrapper = store->domObjectMap().get(object); - if (!wrapper.IsEmpty()) + GroupId groupId = calculateGroupId(cssStyleDeclaration); m_grouper.append(GrouperItem(groupId, wrapper)); - } -}; -class DOMObjectGrouperVisitor : public DOMWrapperMap<void>::Visitor { -public: - DOMObjectGrouperVisitor() - { + } else if (typeInfo->isSubclass(&V8CSSRuleList::info)) { + CSSRuleList* cssRuleList = static_cast<CSSRuleList*>(object); + GroupId groupId(cssRuleList); + StyleList* styleList = cssRuleList->styleList(); + if (styleList) + groupId = calculateGroupId(styleList); + m_grouper.append(GrouperItem(groupId, wrapper)); + } } - void startMap() + void applyGrouping() { - m_grouper.shrink(0); - } + // Group by sorting by the group id. + std::sort(m_grouper.begin(), m_grouper.end()); + + for (size_t i = 0; i < m_grouper.size(); ) { + // Seek to the next key (or the end of the list). + size_t nextKeyIndex = m_grouper.size(); + for (size_t j = i; j < m_grouper.size(); ++j) { + if (m_grouper[i].groupId() != m_grouper[j].groupId()) { + nextKeyIndex = j; + break; + } + } - void endMap() - { - makeV8ObjectGroups(m_grouper); - } + ASSERT(nextKeyIndex > i); - void visitDOMWrapper(DOMDataStore* store, void* object, v8::Persistent<v8::Object> wrapper) - { - WrapperTypeInfo* typeInfo = V8DOMWrapper::domWrapperType(wrapper); - // FIXME: extend WrapperTypeInfo with isStyle to simplify the check below or consider - // adding a virtual method to WrapperTypeInfo which would know how to group objects. - // FIXME: check if there are other StyleBase wrappers we should care of. - if (V8CSSStyleSheet::info.equals(typeInfo) - || V8CSSStyleDeclaration::info.equals(typeInfo) - || V8CSSCharsetRule::info.equals(typeInfo) - || V8CSSFontFaceRule::info.equals(typeInfo) - || V8CSSStyleRule::info.equals(typeInfo) - || V8CSSImportRule::info.equals(typeInfo) - || V8CSSMediaRule::info.equals(typeInfo)) { - StyleBase* styleBase = static_cast<StyleBase*>(object); - - // We put the whole tree of style elements into a single object group. - // To achieve that we group elements by the roots of their trees. - StyleBase* root = styleBase; - ASSERT(root); - while (true) { - StyleBase* parent = root->parent(); - if (!parent) - break; - root = parent; + // We only care about a group if it has more than one object. If it only + // has one object, it has nothing else that needs to be kept alive. + if (nextKeyIndex - i <= 1) { + i = nextKeyIndex; + continue; } - // Group id is an address of the root. - uintptr_t groupId = reinterpret_cast<uintptr_t>(root); - m_grouper.append(GrouperItem(groupId, wrapper)); - if (V8CSSStyleDeclaration::info.equals(typeInfo)) { - CSSStyleDeclaration* cssStyleDeclaration = static_cast<CSSStyleDeclaration*>(styleBase); - if (cssStyleDeclaration->isMutableStyleDeclaration()) { - CSSMutableStyleDeclaration* cssMutableStyleDeclaration = static_cast<CSSMutableStyleDeclaration*>(cssStyleDeclaration); - CSSMutableStyleDeclaration::const_iterator end = cssMutableStyleDeclaration->end(); - for (CSSMutableStyleDeclaration::const_iterator it = cssMutableStyleDeclaration->begin(); it != end; ++it) { - wrapper = store->domObjectMap().get(it->value()); - if (!wrapper.IsEmpty()) - m_grouper.append(GrouperItem(groupId, wrapper)); - } - } + size_t rootIndex = i; + + Vector<v8::Persistent<v8::Value> > group; + group.reserveCapacity(nextKeyIndex - i); + for (; i < nextKeyIndex; ++i) { + v8::Persistent<v8::Value> wrapper = m_grouper[i].wrapper(); + if (!wrapper.IsEmpty()) + group.append(wrapper); } - } else if (V8StyleSheetList::info.equals(typeInfo)) { - addAllItems(store, static_cast<StyleSheetList*>(object), wrapper); - } else if (V8CSSRuleList::info.equals(typeInfo)) { - addAllItems(store, static_cast<CSSRuleList*>(object), wrapper); + + if (group.size() > 1) + v8::V8::AddObjectGroup(&group[0], group.size(), m_grouper[rootIndex].createRetainedObjectInfo()); + + ASSERT(i == nextKeyIndex); } } private: GrouperList m_grouper; - - template <class C> - void addAllItems(DOMDataStore* store, C* collection, v8::Persistent<v8::Object> wrapper) - { - uintptr_t groupId = reinterpret_cast<uintptr_t>(collection); - m_grouper.append(GrouperItem(groupId, wrapper)); - for (unsigned i = 0; i < collection->length(); i++) { - wrapper = store->domObjectMap().get(collection->item(i)); - if (!wrapper.IsEmpty()) - m_grouper.append(GrouperItem(groupId, wrapper)); - } - } }; // Create object groups for DOM tree nodes. @@ -425,12 +430,10 @@ void V8GCController::gcPrologue() visitActiveDOMObjectsInCurrentThread(&prologueVisitor); // Create object groups. - NodeGrouperVisitor nodeGrouperVisitor; - visitDOMNodesInCurrentThread(&nodeGrouperVisitor); - nodeGrouperVisitor.applyGrouping(); - - DOMObjectGrouperVisitor domObjectGrouperVisitor; - visitDOMObjectsInCurrentThread(&domObjectGrouperVisitor); + GrouperVisitor grouperVisitor; + visitDOMNodesInCurrentThread(&grouperVisitor); + visitDOMObjectsInCurrentThread(&grouperVisitor); + grouperVisitor.applyGrouping(); // Clean single element cache for string conversions. lastStringImpl = 0; diff --git a/Source/WebCore/bindings/v8/V8LazyEventListener.cpp b/Source/WebCore/bindings/v8/V8LazyEventListener.cpp index 7f46333..0e2c368 100644 --- a/Source/WebCore/bindings/v8/V8LazyEventListener.cpp +++ b/Source/WebCore/bindings/v8/V8LazyEventListener.cpp @@ -31,6 +31,7 @@ #include "config.h" #include "V8LazyEventListener.h" +#include "ContentSecurityPolicy.h" #include "Frame.h" #include "V8Binding.h" #include "V8HiddenPropertyName.h" @@ -80,6 +81,9 @@ void V8LazyEventListener::prepareListenerObject(ScriptExecutionContext* context) if (hasExistingListenerObject()) return; + if (context->isDocument() && !static_cast<Document*>(context)->contentSecurityPolicy()->allowInlineEventHandlers()) + return; + v8::HandleScope handleScope; V8Proxy* proxy = V8Proxy::retrieve(context); diff --git a/Source/WebCore/bindings/v8/WorkerScriptDebugServer.cpp b/Source/WebCore/bindings/v8/WorkerScriptDebugServer.cpp new file mode 100755 index 0000000..5e2acd2 --- /dev/null +++ b/Source/WebCore/bindings/v8/WorkerScriptDebugServer.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WorkerScriptDebugServer.h" + +#if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(WORKERS) + +#include "WorkerContext.h" + +namespace WebCore { + +WorkerScriptDebugServer::WorkerScriptDebugServer() + : ScriptDebugServer() +{ +} + +void WorkerScriptDebugServer::addListener(ScriptDebugListener*, WorkerContext*) +{ +} + +void WorkerScriptDebugServer::removeListener(ScriptDebugListener*, WorkerContext*) +{ +} + +} // namespace WebCore + +#endif // ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(WORKERS) diff --git a/Source/WebCore/bindings/v8/WorkerScriptDebugServer.h b/Source/WebCore/bindings/v8/WorkerScriptDebugServer.h new file mode 100755 index 0000000..fdc47ac --- /dev/null +++ b/Source/WebCore/bindings/v8/WorkerScriptDebugServer.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WorkerScriptDebugServer_h +#define WorkerScriptDebugServer_h + +#if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(WORKERS) + +#include "ScriptDebugServer.h" + +namespace WebCore { + +class WorkerContext; + +class WorkerScriptDebugServer : public ScriptDebugServer { + WTF_MAKE_NONCOPYABLE(WorkerScriptDebugServer); +public: + WorkerScriptDebugServer(); + ~WorkerScriptDebugServer() { } + + void addListener(ScriptDebugListener*, WorkerContext*); + void removeListener(ScriptDebugListener*, WorkerContext*); + +private: + virtual ScriptDebugListener* getDebugListenerForContext(v8::Handle<v8::Context>) { return 0; } + virtual void runMessageLoopOnPause(v8::Handle<v8::Context>) { } + virtual void quitMessageLoopOnPause() { } +}; + +} // namespace WebCore + +#endif // ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(WORKERS) + +#endif // WorkerScriptDebugServer_h diff --git a/Source/WebCore/bindings/v8/WrapperTypeInfo.h b/Source/WebCore/bindings/v8/WrapperTypeInfo.h index 1d1cbfd..166d642 100644 --- a/Source/WebCore/bindings/v8/WrapperTypeInfo.h +++ b/Source/WebCore/bindings/v8/WrapperTypeInfo.h @@ -41,7 +41,9 @@ namespace WebCore { static const int v8DOMWrapperObjectIndex = 1; static const int v8DOMHiddenReferenceArrayIndex = 2; static const int v8DefaultWrapperInternalFieldCount = 3; - + + static const uint16_t v8DOMSubtreeClassId = 1; + typedef v8::Persistent<v8::FunctionTemplate> (*GetTemplateFunction)(); typedef void (*DerefObjectFunction)(void*); typedef ActiveDOMObject* (*ToActiveDOMObjectFunction)(v8::Handle<v8::Object>); @@ -61,6 +63,16 @@ namespace WebCore { { return this == that; } + + bool isSubclass(const WrapperTypeInfo* that) const + { + for (const WrapperTypeInfo* current = this; current; current = current->parentClass) { + if (current == that) + return true; + } + + return false; + } v8::Persistent<v8::FunctionTemplate> getTemplate() { return getTemplateFunction(); } @@ -80,6 +92,7 @@ namespace WebCore { const GetTemplateFunction getTemplateFunction; const DerefObjectFunction derefObjectFunction; const ToActiveDOMObjectFunction toActiveDOMObjectFunction; + const WrapperTypeInfo* parentClass; }; } diff --git a/Source/WebCore/bindings/v8/custom/V8HTMLCanvasElementCustom.cpp b/Source/WebCore/bindings/v8/custom/V8HTMLCanvasElementCustom.cpp index 8fd2d62..52465b6 100644 --- a/Source/WebCore/bindings/v8/custom/V8HTMLCanvasElementCustom.cpp +++ b/Source/WebCore/bindings/v8/custom/V8HTMLCanvasElementCustom.cpp @@ -76,6 +76,9 @@ v8::Handle<v8::Value> V8HTMLCanvasElement::getContextCallback(const v8::Argument v8::Handle<v8::String> premultipliedAlpha = v8::String::New("premultipliedAlpha"); if (jsAttrs->Has(premultipliedAlpha)) webGLAttrs->setPremultipliedAlpha(jsAttrs->Get(premultipliedAlpha)->BooleanValue()); + v8::Handle<v8::String> preserveDrawingBuffer = v8::String::New("preserveDrawingBuffer"); + if (jsAttrs->Has(preserveDrawingBuffer)) + webGLAttrs->setPreserveDrawingBuffer(jsAttrs->Get(preserveDrawingBuffer)->BooleanValue()); } } #endif diff --git a/Source/WebCore/bindings/v8/custom/V8IDBAnyCustom.cpp b/Source/WebCore/bindings/v8/custom/V8IDBAnyCustom.cpp index ccd6fb2..a1a8636 100644 --- a/Source/WebCore/bindings/v8/custom/V8IDBAnyCustom.cpp +++ b/Source/WebCore/bindings/v8/custom/V8IDBAnyCustom.cpp @@ -77,6 +77,6 @@ v8::Handle<v8::Value> toV8(IDBAny* impl) return v8::Undefined(); } -#endif // ENABLE(INDEXED_DATABASE) - } // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/Source/WebCore/bindings/v8/custom/V8IDBKeyCustom.cpp b/Source/WebCore/bindings/v8/custom/V8IDBKeyCustom.cpp index 3805dca..b8fa6bb 100644 --- a/Source/WebCore/bindings/v8/custom/V8IDBKeyCustom.cpp +++ b/Source/WebCore/bindings/v8/custom/V8IDBKeyCustom.cpp @@ -56,6 +56,6 @@ v8::Handle<v8::Value> toV8(IDBKey* key) return v8::Undefined(); } -#endif // ENABLE(INDEXED_DATABASE) - } // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/Source/WebCore/bindings/v8/custom/V8InjectedScriptHostCustom.cpp b/Source/WebCore/bindings/v8/custom/V8InjectedScriptHostCustom.cpp index 7a33ed0..3dbacb2 100644 --- a/Source/WebCore/bindings/v8/custom/V8InjectedScriptHostCustom.cpp +++ b/Source/WebCore/bindings/v8/custom/V8InjectedScriptHostCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2009 Google Inc. All rights reserved. + * Copyright (C) 2007-2011 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -31,27 +31,21 @@ #include "config.h" #include "V8InjectedScriptHost.h" -#include "DOMWindow.h" #include "Database.h" -#include "Frame.h" #include "InjectedScript.h" #include "InjectedScriptHost.h" +#include "InspectorDebuggerAgent.h" #include "InspectorValues.h" -#include "Node.h" -#include "Page.h" #include "ScriptDebugServer.h" #include "ScriptValue.h" - #include "V8Binding.h" #include "V8BindingState.h" -#include "V8DOMWindow.h" #include "V8Database.h" #include "V8HiddenPropertyName.h" #include "V8JavaScriptCallFrame.h" #include "V8Node.h" #include "V8Proxy.h" #include "V8Storage.h" -#include <wtf/RefPtr.h> namespace WebCore { @@ -71,86 +65,6 @@ ScriptValue InjectedScriptHost::nodeAsScriptValue(ScriptState* state, Node* node return ScriptValue(toV8(node)); } -static void WeakReferenceCallback(v8::Persistent<v8::Value> object, void* parameter) -{ - InjectedScriptHost* nativeObject = static_cast<InjectedScriptHost*>(parameter); - nativeObject->deref(); - object.Dispose(); -} - -static v8::Local<v8::Object> createInjectedScriptHostV8Wrapper(InjectedScriptHost* host) -{ - v8::Local<v8::Function> function = V8InjectedScriptHost::GetTemplate()->GetFunction(); - if (function.IsEmpty()) { - // Return if allocation failed. - return v8::Local<v8::Object>(); - } - v8::Local<v8::Object> instance = SafeAllocation::newInstance(function); - if (instance.IsEmpty()) { - // Avoid setting the wrapper if allocation failed. - return v8::Local<v8::Object>(); - } - V8DOMWrapper::setDOMWrapper(instance, &V8InjectedScriptHost::info, host); - // Create a weak reference to the v8 wrapper of InspectorBackend to deref - // InspectorBackend when the wrapper is garbage collected. - host->ref(); - v8::Persistent<v8::Object> weakHandle = v8::Persistent<v8::Object>::New(instance); - weakHandle.MakeWeak(host, &WeakReferenceCallback); - return instance; -} - -ScriptObject InjectedScriptHost::createInjectedScript(const String& scriptSource, ScriptState* inspectedScriptState, long id) -{ - v8::HandleScope scope; - - v8::Local<v8::Context> inspectedContext = inspectedScriptState->context(); - v8::Context::Scope contextScope(inspectedContext); - - // Call custom code to create InjectedScripHost wrapper specific for the context - // instead of calling toV8() that would create the - // wrapper in the current context. - // FIXME: make it possible to use generic bindings factory for InjectedScriptHost. - v8::Local<v8::Object> scriptHostWrapper = createInjectedScriptHostV8Wrapper(this); - if (scriptHostWrapper.IsEmpty()) - return ScriptObject(); - - v8::Local<v8::Object> windowGlobal = inspectedContext->Global(); - - // Inject javascript into the context. The compiled script is supposed to evaluate into - // a single anonymous function(it's anonymous to avoid cluttering the global object with - // inspector's stuff) the function is called a few lines below with InjectedScriptHost wrapper, - // injected script id and explicit reference to the inspected global object. The function is expected - // to create and configure InjectedScript instance that is going to be used by the inspector. - v8::Local<v8::Script> script = v8::Script::Compile(v8String(scriptSource)); - v8::Local<v8::Value> v = script->Run(); - ASSERT(!v.IsEmpty()); - ASSERT(v->IsFunction()); - - v8::Handle<v8::Value> args[] = { - scriptHostWrapper, - windowGlobal, - v8::Number::New(id), - }; - v8::Local<v8::Value> injectedScriptValue = v8::Function::Cast(*v)->Call(windowGlobal, 3, args); - v8::Local<v8::Object> injectedScript(v8::Object::Cast(*injectedScriptValue)); - return ScriptObject(inspectedScriptState, injectedScript); -} - -void InjectedScriptHost::discardInjectedScript(ScriptState* inspectedScriptState) -{ - v8::HandleScope handleScope; - v8::Local<v8::Context> context = inspectedScriptState->context(); - v8::Context::Scope contextScope(context); - - v8::Local<v8::Object> global = context->Global(); - // Skip proxy object. The proxy object will survive page navigation while we need - // an object whose lifetime consides with that of the inspected context. - global = v8::Local<v8::Object>::Cast(global->GetPrototype()); - - v8::Handle<v8::String> key = V8HiddenPropertyName::devtoolsInjectedScript(); - global->DeleteHiddenValue(key); -} - v8::Handle<v8::Value> V8InjectedScriptHost::inspectedNodeCallback(const v8::Arguments& args) { INC_STATS("InjectedScriptHost.inspectedNode()"); @@ -185,9 +99,9 @@ v8::Handle<v8::Value> V8InjectedScriptHost::inspectCallback(const v8::Arguments& return v8::Undefined(); InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder()); - ScriptValue objectId(args[0]); + ScriptValue object(args[0]); ScriptValue hints(args[1]); - host->inspectImpl(objectId.toInspectorValue(ScriptState::current()), hints.toInspectorValue(ScriptState::current())); + host->inspectImpl(object.toInspectorValue(ScriptState::current()), hints.toInspectorValue(ScriptState::current())); return v8::Undefined(); } @@ -196,7 +110,8 @@ v8::Handle<v8::Value> V8InjectedScriptHost::currentCallFrameCallback(const v8::A { #if ENABLE(JAVASCRIPT_DEBUGGER) INC_STATS("InjectedScriptHost.currentCallFrame()"); - return toV8(ScriptDebugServer::shared().currentCallFrame()); + InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder()); + return toV8(host->debuggerAgent()->scriptDebugServer().currentCallFrame()); #else UNUSED_PARAM(args); return v8::Undefined(); @@ -231,46 +146,4 @@ v8::Handle<v8::Value> V8InjectedScriptHost::storageIdCallback(const v8::Argument return v8::Undefined(); } -InjectedScript InjectedScriptHost::injectedScriptFor(ScriptState* inspectedScriptState) -{ - v8::HandleScope handleScope; - v8::Local<v8::Context> context = inspectedScriptState->context(); - v8::Context::Scope contextScope(context); - - v8::Local<v8::Object> global = context->Global(); - // Skip proxy object. The proxy object will survive page navigation while we need - // an object whose lifetime consides with that of the inspected context. - global = v8::Local<v8::Object>::Cast(global->GetPrototype()); - - v8::Handle<v8::String> key = V8HiddenPropertyName::devtoolsInjectedScript(); - v8::Local<v8::Value> val = global->GetHiddenValue(key); - if (!val.IsEmpty() && val->IsObject()) - return InjectedScript(ScriptObject(inspectedScriptState, v8::Local<v8::Object>::Cast(val))); - - if (!canAccessInspectedWindow(inspectedScriptState)) - return InjectedScript(); - - pair<long, ScriptObject> injectedScript = injectScript(injectedScriptSource(), inspectedScriptState); - InjectedScript result(injectedScript.second); - m_idToInjectedScript.set(injectedScript.first, result); - global->SetHiddenValue(key, injectedScript.second.v8Object()); - return result; -} - -bool InjectedScriptHost::canAccessInspectedWindow(ScriptState* scriptState) -{ - v8::HandleScope handleScope; - v8::Local<v8::Context> context = scriptState->context(); - v8::Local<v8::Object> global = context->Global(); - if (global.IsEmpty()) - return false; - v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), global); - if (holder.IsEmpty()) - return false; - Frame* frame = V8DOMWindow::toNative(holder)->frame(); - - v8::Context::Scope contextScope(context); - return V8BindingSecurity::canAccessFrame(V8BindingState::Only(), frame, false); -} - } // namespace WebCore diff --git a/Source/WebCore/bindings/v8/custom/V8InjectedScriptManager.cpp b/Source/WebCore/bindings/v8/custom/V8InjectedScriptManager.cpp new file mode 100644 index 0000000..f4006b8 --- /dev/null +++ b/Source/WebCore/bindings/v8/custom/V8InjectedScriptManager.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2007-2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "InjectedScriptManager.h" + +#include "DOMWindow.h" +#include "InjectedScript.h" +#include "InjectedScriptHost.h" +#include "ScriptValue.h" +#include "V8Binding.h" +#include "V8BindingState.h" +#include "V8DOMWindow.h" +#include "V8HiddenPropertyName.h" +#include "V8InjectedScriptHost.h" +#include "V8Proxy.h" +#include <wtf/RefPtr.h> + +namespace WebCore { + +static void WeakReferenceCallback(v8::Persistent<v8::Value> object, void* parameter) +{ + InjectedScriptHost* nativeObject = static_cast<InjectedScriptHost*>(parameter); + nativeObject->deref(); + object.Dispose(); +} + +static v8::Local<v8::Object> createInjectedScriptHostV8Wrapper(InjectedScriptHost* host) +{ + v8::Local<v8::Function> function = V8InjectedScriptHost::GetTemplate()->GetFunction(); + if (function.IsEmpty()) { + // Return if allocation failed. + return v8::Local<v8::Object>(); + } + v8::Local<v8::Object> instance = SafeAllocation::newInstance(function); + if (instance.IsEmpty()) { + // Avoid setting the wrapper if allocation failed. + return v8::Local<v8::Object>(); + } + V8DOMWrapper::setDOMWrapper(instance, &V8InjectedScriptHost::info, host); + // Create a weak reference to the v8 wrapper of InspectorBackend to deref + // InspectorBackend when the wrapper is garbage collected. + host->ref(); + v8::Persistent<v8::Object> weakHandle = v8::Persistent<v8::Object>::New(instance); + weakHandle.MakeWeak(host, &WeakReferenceCallback); + return instance; +} + +ScriptObject InjectedScriptManager::createInjectedScript(const String& scriptSource, ScriptState* inspectedScriptState, long id) +{ + v8::HandleScope scope; + + v8::Local<v8::Context> inspectedContext = inspectedScriptState->context(); + v8::Context::Scope contextScope(inspectedContext); + + // Call custom code to create InjectedScripHost wrapper specific for the context + // instead of calling toV8() that would create the + // wrapper in the current context. + // FIXME: make it possible to use generic bindings factory for InjectedScriptHost. + v8::Local<v8::Object> scriptHostWrapper = createInjectedScriptHostV8Wrapper(m_injectedScriptHost.get()); + if (scriptHostWrapper.IsEmpty()) + return ScriptObject(); + + v8::Local<v8::Object> windowGlobal = inspectedContext->Global(); + + // Inject javascript into the context. The compiled script is supposed to evaluate into + // a single anonymous function(it's anonymous to avoid cluttering the global object with + // inspector's stuff) the function is called a few lines below with InjectedScriptHost wrapper, + // injected script id and explicit reference to the inspected global object. The function is expected + // to create and configure InjectedScript instance that is going to be used by the inspector. + v8::Local<v8::Script> script = v8::Script::Compile(v8String(scriptSource)); + v8::Local<v8::Value> v = script->Run(); + ASSERT(!v.IsEmpty()); + ASSERT(v->IsFunction()); + + v8::Handle<v8::Value> args[] = { + scriptHostWrapper, + windowGlobal, + v8::Number::New(id), + }; + v8::Local<v8::Value> injectedScriptValue = v8::Function::Cast(*v)->Call(windowGlobal, 3, args); + v8::Local<v8::Object> injectedScript(v8::Object::Cast(*injectedScriptValue)); + return ScriptObject(inspectedScriptState, injectedScript); +} + +void InjectedScriptManager::discardInjectedScript(ScriptState* inspectedScriptState) +{ + v8::HandleScope handleScope; + v8::Local<v8::Context> context = inspectedScriptState->context(); + v8::Context::Scope contextScope(context); + + v8::Local<v8::Object> global = context->Global(); + // Skip proxy object. The proxy object will survive page navigation while we need + // an object whose lifetime consides with that of the inspected context. + global = v8::Local<v8::Object>::Cast(global->GetPrototype()); + + v8::Handle<v8::String> key = V8HiddenPropertyName::devtoolsInjectedScript(); + global->DeleteHiddenValue(key); +} + +InjectedScript InjectedScriptManager::injectedScriptFor(ScriptState* inspectedScriptState) +{ + v8::HandleScope handleScope; + v8::Local<v8::Context> context = inspectedScriptState->context(); + v8::Context::Scope contextScope(context); + + v8::Local<v8::Object> global = context->Global(); + // Skip proxy object. The proxy object will survive page navigation while we need + // an object whose lifetime consides with that of the inspected context. + global = v8::Local<v8::Object>::Cast(global->GetPrototype()); + + v8::Handle<v8::String> key = V8HiddenPropertyName::devtoolsInjectedScript(); + v8::Local<v8::Value> val = global->GetHiddenValue(key); + if (!val.IsEmpty() && val->IsObject()) + return InjectedScript(ScriptObject(inspectedScriptState, v8::Local<v8::Object>::Cast(val))); + + if (!canAccessInspectedWindow(inspectedScriptState)) + return InjectedScript(); + + pair<long, ScriptObject> injectedScript = injectScript(injectedScriptSource(), inspectedScriptState); + InjectedScript result(injectedScript.second); + m_idToInjectedScript.set(injectedScript.first, result); + global->SetHiddenValue(key, injectedScript.second.v8Object()); + return result; +} + +bool InjectedScriptManager::canAccessInspectedWindow(ScriptState* scriptState) +{ + v8::HandleScope handleScope; + v8::Local<v8::Context> context = scriptState->context(); + v8::Local<v8::Object> global = context->Global(); + if (global.IsEmpty()) + return false; + v8::Handle<v8::Object> holder = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), global); + if (holder.IsEmpty()) + return false; + Frame* frame = V8DOMWindow::toNative(holder)->frame(); + + v8::Context::Scope contextScope(context); + return V8BindingSecurity::canAccessFrame(V8BindingState::Only(), frame, false); +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/v8/custom/V8WebKitAnimationCustom.cpp b/Source/WebCore/bindings/v8/custom/V8WebKitAnimationCustom.cpp new file mode 100644 index 0000000..c0949ae --- /dev/null +++ b/Source/WebCore/bindings/v8/custom/V8WebKitAnimationCustom.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "V8WebKitAnimation.h" + +#include "V8Binding.h" +#include "V8BindingMacros.h" +#include "V8Proxy.h" +#include "WebKitAnimation.h" + +#include <v8.h> + +namespace WebCore { + +v8::Handle<v8::Value> V8WebKitAnimation::iterationCountAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) +{ + INC_STATS("DOM.WebKitAnimation.iterationCount._get"); + v8::Handle<v8::Object> holder = info.Holder(); + WebKitAnimation* imp = V8WebKitAnimation::toNative(holder); + int count = imp->iterationCount(); + if (count == Animation::IterationCountInfinite) + return v8::Number::New(std::numeric_limits<float>::infinity()); + return v8::Number::New(count); +} + +} // namespace WebCore + |