diff options
author | Ben Murdoch <benm@google.com> | 2011-06-02 12:07:03 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2011-06-10 10:47:21 +0100 |
commit | 2daae5fd11344eaa88a0d92b0f6d65f8d2255c00 (patch) | |
tree | e4964fbd1cb70599f7718ff03e50ea1dab33890b /Source/WebCore/bindings | |
parent | 87bdf0060a247bfbe668342b87e0874182e0ffa9 (diff) | |
download | external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.zip external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.tar.gz external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.tar.bz2 |
Merge WebKit at r84325: Initial merge by git.
Change-Id: Ic1a909300ecc0a13ddc6b4e784371d2ac6e3d59b
Diffstat (limited to 'Source/WebCore/bindings')
114 files changed, 1376 insertions, 872 deletions
diff --git a/Source/WebCore/bindings/generic/RuntimeEnabledFeatures.cpp b/Source/WebCore/bindings/generic/RuntimeEnabledFeatures.cpp index e9591fd..dd47184 100644 --- a/Source/WebCore/bindings/generic/RuntimeEnabledFeatures.cpp +++ b/Source/WebCore/bindings/generic/RuntimeEnabledFeatures.cpp @@ -142,4 +142,8 @@ bool RuntimeEnabledFeatures::openDatabaseSyncEnabled() } #endif +#if ENABLE(QUOTA) +bool RuntimeEnabledFeatures::isQuotaEnabled = false; +#endif + } // namespace WebCore diff --git a/Source/WebCore/bindings/generic/RuntimeEnabledFeatures.h b/Source/WebCore/bindings/generic/RuntimeEnabledFeatures.h index 1004ea4..3432d74 100644 --- a/Source/WebCore/bindings/generic/RuntimeEnabledFeatures.h +++ b/Source/WebCore/bindings/generic/RuntimeEnabledFeatures.h @@ -150,6 +150,11 @@ public: static bool webkitGetUserMediaEnabled() { return isMediaStreamEnabled; } #endif +#if ENABLE(QUOTA) + static bool quotaEnabled() { return isQuotaEnabled; } + static void setQuotaEnabled(bool isEnabled) { isQuotaEnabled = isEnabled; } +#endif + private: // Never instantiate. RuntimeEnabledFeatures() { } @@ -182,6 +187,10 @@ private: #if ENABLE(MEDIA_STREAM) static bool isMediaStreamEnabled; #endif + +#if ENABLE(QUOTA) + static bool isQuotaEnabled; +#endif }; } // namespace WebCore diff --git a/Source/WebCore/bindings/js/CallbackFunction.cpp b/Source/WebCore/bindings/js/CallbackFunction.cpp new file mode 100644 index 0000000..145d055 --- /dev/null +++ b/Source/WebCore/bindings/js/CallbackFunction.cpp @@ -0,0 +1,51 @@ +/* + * 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: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 "CallbackFunction.h" + +#include "ExceptionCode.h" +#include "JSDOMBinding.h" +#include <runtime/CallData.h> + +namespace WebCore { + +bool checkFunctionOnlyCallback(JSC::ExecState* exec, JSC::JSValue value, CallbackAllowedValueFlags acceptedValues) +{ + if (value.isUndefined() && (acceptedValues & CallbackAllowUndefined)) + return false; + + if (value.isNull() && (acceptedValues & CallbackAllowNull)) + return false; + + JSC::CallData callData; + if (getCallData(value, callData) == JSC::CallTypeNone) { + setDOMException(exec, TYPE_MISMATCH_ERR); + return false; + } + + return true; +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/CallbackFunction.h b/Source/WebCore/bindings/js/CallbackFunction.h new file mode 100644 index 0000000..2562ce9 --- /dev/null +++ b/Source/WebCore/bindings/js/CallbackFunction.h @@ -0,0 +1,58 @@ +/* + * 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: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 CallbackFunction_h +#define CallbackFunction_h + +#include <runtime/JSObject.h> + +namespace JSC { +class ExecState; +} + +namespace WebCore { + +class JSDOMGlobalObject; + +enum CallbackAllowedValueFlag { + CallbackAllowUndefined = 1, + CallbackAllowNull = 1 << 1 +}; + +typedef unsigned CallbackAllowedValueFlags; + +bool checkFunctionOnlyCallback(JSC::ExecState*, JSC::JSValue, CallbackAllowedValueFlags); + +// Creates callback objects for callbacks marked as FunctionOnly in WebIDL. +template <typename JSCallbackType> +PassRefPtr<JSCallbackType> createFunctionOnlyCallback(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, JSC::JSValue value, CallbackAllowedValueFlags acceptedValues = 0) +{ + if (checkFunctionOnlyCallback(exec, value, acceptedValues)) + return JSCallbackType::create(asObject(value), globalObject); + return 0; +} + +} // namespace WebCore + +#endif // CallbackFunction_h diff --git a/Source/WebCore/bindings/js/DOMWrapperWorld.cpp b/Source/WebCore/bindings/js/DOMWrapperWorld.cpp index 13ee37a..b78211e 100644 --- a/Source/WebCore/bindings/js/DOMWrapperWorld.cpp +++ b/Source/WebCore/bindings/js/DOMWrapperWorld.cpp @@ -29,9 +29,17 @@ using namespace JSC; namespace WebCore { +void JSDOMWrapperOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context) +{ + JSDOMWrapper* wrapper = static_cast<JSDOMWrapper*>(handle.get().asCell()); + void* domObject = context; + uncacheWrapper(m_world, domObject, wrapper); +} + DOMWrapperWorld::DOMWrapperWorld(JSC::JSGlobalData* globalData, bool isNormal) : m_globalData(globalData) , m_isNormal(isNormal) + , m_defaultWrapperOwner(this) { JSGlobalData::ClientData* clientData = m_globalData->clientData; ASSERT(clientData); @@ -45,9 +53,6 @@ DOMWrapperWorld::~DOMWrapperWorld() static_cast<WebCoreJSClientData*>(clientData)->forgetWorld(this); // These items are created lazily. - while (!m_documentsWithWrapperCaches.isEmpty()) - (*m_documentsWithWrapperCaches.begin())->destroyWrapperCache(this); - while (!m_scriptControllersWithWindowShells.isEmpty()) (*m_scriptControllersWithWindowShells.begin())->destroyWindowShell(this); } @@ -58,9 +63,6 @@ void DOMWrapperWorld::clearWrappers() m_stringCache.clear(); // These items are created lazily. - while (!m_documentsWithWrapperCaches.isEmpty()) - (*m_documentsWithWrapperCaches.begin())->destroyWrapperCache(this); - while (!m_scriptControllersWithWindowShells.isEmpty()) (*m_scriptControllersWithWindowShells.begin())->destroyWindowShell(this); } diff --git a/Source/WebCore/bindings/js/DOMWrapperWorld.h b/Source/WebCore/bindings/js/DOMWrapperWorld.h index 9825a08..cd7c59f 100644 --- a/Source/WebCore/bindings/js/DOMWrapperWorld.h +++ b/Source/WebCore/bindings/js/DOMWrapperWorld.h @@ -22,18 +22,32 @@ #ifndef DOMWrapperWorld_h #define DOMWrapperWorld_h -#include "Document.h" #include "JSDOMGlobalObject.h" -#include "JSDOMWrapper.h" +#include <heap/Weak.h> #include <runtime/WeakGCMap.h> #include <wtf/Forward.h> namespace WebCore { +class JSDOMWrapper; class ScriptController; -typedef JSC::WeakGCMap<void*, DOMObject> DOMObjectWrapperMap; -typedef JSC::WeakGCMap<StringImpl*, JSC::JSString> JSStringCache; +typedef HashMap<void*, JSC::Weak<JSDOMWrapper> > DOMObjectWrapperMap; +typedef JSC::WeakGCMap<StringImpl*, JSC::JSString> JSStringCache; + +class JSDOMWrapperOwner : public JSC::WeakHandleOwner { +public: + JSDOMWrapperOwner(DOMWrapperWorld*); + virtual void finalize(JSC::Handle<JSC::Unknown>, void* context); + +private: + DOMWrapperWorld* m_world; +}; + +inline JSDOMWrapperOwner::JSDOMWrapperOwner(DOMWrapperWorld* world) + : m_world(world) +{ +} class DOMWrapperWorld : public RefCounted<DOMWrapperWorld> { public: @@ -46,9 +60,6 @@ public: // Free as much memory held onto by this world as possible. void clearWrappers(); - void didCreateWrapperCache(Document* document) { m_documentsWithWrapperCaches.add(document); } - void didDestroyWrapperCache(Document* document) { m_documentsWithWrapperCaches.remove(document); } - void didCreateWindowShell(ScriptController* scriptController) { m_scriptControllersWithWindowShells.add(scriptController); } void didDestroyWindowShell(ScriptController* scriptController) { m_scriptControllersWithWindowShells.remove(scriptController); } @@ -59,15 +70,16 @@ public: bool isNormal() const { return m_isNormal; } JSC::JSGlobalData* globalData() const { return m_globalData; } + JSDOMWrapperOwner* defaultWrapperOwner() { return &m_defaultWrapperOwner; } protected: DOMWrapperWorld(JSC::JSGlobalData*, bool isNormal); private: JSC::JSGlobalData* m_globalData; - HashSet<Document*> m_documentsWithWrapperCaches; HashSet<ScriptController*> m_scriptControllersWithWindowShells; bool m_isNormal; + JSDOMWrapperOwner m_defaultWrapperOwner; }; DOMWrapperWorld* normalWorld(JSC::JSGlobalData&); @@ -80,19 +92,6 @@ inline DOMWrapperWorld* currentWorld(JSC::ExecState* exec) return static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())->world(); } -// From Document.h - -inline Document::JSWrapperCache* Document::getWrapperCache(DOMWrapperWorld* world) -{ - if (world->isNormal()) { - if (Document::JSWrapperCache* wrapperCache = m_normalWorldWrapperCache) - return wrapperCache; - ASSERT(!m_wrapperCacheMap.contains(world)); - } else if (Document::JSWrapperCache* wrapperCache = m_wrapperCacheMap.get(world)) - return wrapperCache; - return createWrapperCache(world); -} - } // namespace WebCore #endif // DOMWrapperWorld_h diff --git a/Source/WebCore/bindings/js/GCController.cpp b/Source/WebCore/bindings/js/GCController.cpp index fe0e36f..765e363 100644 --- a/Source/WebCore/bindings/js/GCController.cpp +++ b/Source/WebCore/bindings/js/GCController.cpp @@ -29,13 +29,9 @@ #include "JSDOMWindow.h" #include <runtime/JSGlobalData.h> #include <runtime/JSLock.h> -#include <runtime/Heap.h> +#include <heap/Heap.h> #include <wtf/StdLibExtras.h> -#if USE(PTHREADS) -#include <pthread.h> -#endif - using namespace JSC; namespace WebCore { @@ -78,13 +74,14 @@ void GCController::garbageCollectNow() void GCController::garbageCollectOnAlternateThreadForDebugging(bool waitUntilDone) { -#if USE(PTHREADS) - pthread_t thread; - pthread_create(&thread, NULL, collect, NULL); + ThreadIdentifier threadID = createThread(collect, 0, "WebCore: GCController"); + + if (waitUntilDone) { + waitForThreadCompletion(threadID, 0); + return; + } - if (waitUntilDone) - pthread_join(thread, NULL); -#endif + detachThread(threadID); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSArrayBufferViewHelper.h b/Source/WebCore/bindings/js/JSArrayBufferViewHelper.h index cb9981d..58aaf19 100644 --- a/Source/WebCore/bindings/js/JSArrayBufferViewHelper.h +++ b/Source/WebCore/bindings/js/JSArrayBufferViewHelper.h @@ -163,11 +163,11 @@ static JSC::JSValue toJSArrayBufferView(JSC::ExecState* exec, JSDOMGlobalObject* if (!object) return JSC::jsNull(); - if (DOMObject* wrapper = getCachedDOMObjectWrapper(exec, object)) + if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), object)) return wrapper; exec->heap()->reportExtraMemoryCost(object->byteLength()); - return createDOMObjectWrapper<JSType>(exec, globalObject, object); + return createWrapper<JSType>(exec, globalObject, object); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSAttrCustom.cpp b/Source/WebCore/bindings/js/JSAttrCustom.cpp index 227582d..305dc81 100644 --- a/Source/WebCore/bindings/js/JSAttrCustom.cpp +++ b/Source/WebCore/bindings/js/JSAttrCustom.cpp @@ -43,10 +43,10 @@ void JSAttr::markChildren(MarkStack& markStack) { Base::markChildren(markStack); - // Mark the element so that this will work to access the attribute even if the last - // other reference goes away. - if (Element* element = impl()->ownerElement()) - markDOMNodeWrapper(markStack, element->document(), element); + Element* element = impl()->ownerElement(); + if (!element) + return; + markStack.addOpaqueRoot(root(element)); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSAudioConstructor.h b/Source/WebCore/bindings/js/JSAudioConstructor.h index be0b800..1440355 100644 --- a/Source/WebCore/bindings/js/JSAudioConstructor.h +++ b/Source/WebCore/bindings/js/JSAudioConstructor.h @@ -38,7 +38,7 @@ namespace WebCore { public: JSAudioConstructor(JSC::ExecState*, JSDOMGlobalObject*); - static PassRefPtr<JSC::Structure> createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype) + static JSC::Structure* createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype) { return JSC::Structure::create(globalData, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } diff --git a/Source/WebCore/bindings/js/JSAudioContextCustom.cpp b/Source/WebCore/bindings/js/JSAudioContextCustom.cpp index 382d0cb..9ebf6b7 100644 --- a/Source/WebCore/bindings/js/JSAudioContextCustom.cpp +++ b/Source/WebCore/bindings/js/JSAudioContextCustom.cpp @@ -54,8 +54,28 @@ EncodedJSValue JSC_HOST_CALL JSAudioContextConstructor::constructJSAudioContext( Document* document = static_cast<Document*>(scriptExecutionContext); - RefPtr<AudioContext> context = AudioContext::create(document); - return JSValue::encode(asObject(toJS(exec, jsConstructor->globalObject(), context.get()))); + RefPtr<AudioContext> audioContext; + + if (!exec->argumentCount()) { + // Constructor for default AudioContext which talks to audio hardware. + audioContext = AudioContext::create(document); + } else { + // Constructor for offline (render-target) AudioContext which renders into an AudioBuffer. + // new AudioContext(in unsigned long numberOfChannels, in unsigned long numberOfFrames, in float sampleRate); + if (exec->argumentCount() < 3) + return throwError(exec, createSyntaxError(exec, "Not enough arguments")); + + unsigned numberOfChannels = exec->argument(0).toInt32(exec); + unsigned numberOfFrames = exec->argument(1).toInt32(exec); + float sampleRate = exec->argument(2).toFloat(exec); + + audioContext = AudioContext::createOfflineContext(document, numberOfChannels, numberOfFrames, sampleRate); + } + + if (!audioContext.get()) + return throwError(exec, createReferenceError(exec, "Error creating AudioContext")); + + return JSValue::encode(asObject(toJS(exec, jsConstructor->globalObject(), audioContext.get()))); } JSValue JSAudioContext::createBuffer(ExecState* exec) diff --git a/Source/WebCore/bindings/js/JSBindingsAllInOne.cpp b/Source/WebCore/bindings/js/JSBindingsAllInOne.cpp index d5c9135..a457ce8 100644 --- a/Source/WebCore/bindings/js/JSBindingsAllInOne.cpp +++ b/Source/WebCore/bindings/js/JSBindingsAllInOne.cpp @@ -25,6 +25,7 @@ // This all-in-one cpp file cuts down on template bloat to allow us to build our Windows release build. +#include "CallbackFunction.cpp" #include "DOMObjectHashTableMap.cpp" #include "DOMWrapperWorld.cpp" #include "GCController.cpp" diff --git a/Source/WebCore/bindings/js/JSCSSRuleCustom.cpp b/Source/WebCore/bindings/js/JSCSSRuleCustom.cpp index 4d226d0..935ec1a 100644 --- a/Source/WebCore/bindings/js/JSCSSRuleCustom.cpp +++ b/Source/WebCore/bindings/js/JSCSSRuleCustom.cpp @@ -63,7 +63,7 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, CSSRule* rule) if (!rule) return jsNull(); - DOMObject* wrapper = getCachedDOMObjectWrapper(exec, rule); + JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), rule); if (wrapper) return wrapper; diff --git a/Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp b/Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp index 1e750e5..c41c15b 100644 --- a/Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp +++ b/Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp @@ -34,6 +34,8 @@ #include <runtime/StringPrototype.h> #include <wtf/ASCIICType.h> #include <wtf/text/AtomicString.h> +#include <wtf/text/StringBuilder.h> +#include <wtf/text/StringConcatenate.h> using namespace JSC; using namespace WTF; @@ -94,8 +96,8 @@ static String cssPropertyName(const Identifier& propertyName, bool* hadPixelOrPo if (!length) return String(); - Vector<UChar> name; - name.reserveInitialCapacity(length); + StringBuilder builder; + builder.reserveCapacity(length); unsigned i = 0; @@ -112,32 +114,30 @@ static String cssPropertyName(const Identifier& propertyName, bool* hadPixelOrPo } else if (hasCSSPropertyNamePrefix(propertyName, "webkit") || hasCSSPropertyNamePrefix(propertyName, "khtml") || hasCSSPropertyNamePrefix(propertyName, "apple")) - name.append('-'); + builder.append('-'); else { if (isASCIIUpper(propertyName.characters()[0])) return String(); } - name.append(toASCIILower(propertyName.characters()[i++])); + builder.append(toASCIILower(propertyName.characters()[i++])); for (; i < length; ++i) { UChar c = propertyName.characters()[i]; if (!isASCIIUpper(c)) - name.append(c); - else { - name.append('-'); - name.append(toASCIILower(c)); - } + builder.append(c); + else + builder.append(makeString('-', toASCIILower(c))); } - return String::adopt(name); + return builder.toString(); } -static bool isCSSPropertyName(const Identifier& propertyName) +static bool isCSSPropertyName(const Identifier& propertyIdentifier) { // FIXME: This mallocs a string for the property name and then throws it // away. This shows up on peacekeeper's domDynamicCreationCreateElement. - return CSSStyleDeclaration::isPropertyName(cssPropertyName(propertyName)); + return CSSStyleDeclaration::isPropertyName(cssPropertyName(propertyIdentifier)); } bool JSCSSStyleDeclaration::canGetItemsForName(ExecState*, CSSStyleDeclaration*, const Identifier& propertyName) @@ -178,11 +178,11 @@ JSValue JSCSSStyleDeclaration::nameGetter(ExecState* exec, JSValue slotBase, con bool JSCSSStyleDeclaration::putDelegate(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot&) { - if (!isCSSPropertyName(propertyName)) - return false; - bool pixelOrPos; String prop = cssPropertyName(propertyName, &pixelOrPos); + if (!CSSStyleDeclaration::isPropertyName(prop)) + return false; + String propValue = valueToStringWithNullCheck(exec, value); if (pixelOrPos) propValue += "px"; diff --git a/Source/WebCore/bindings/js/JSCSSValueCustom.cpp b/Source/WebCore/bindings/js/JSCSSValueCustom.cpp index 83c1d3a..b1f8404 100644 --- a/Source/WebCore/bindings/js/JSCSSValueCustom.cpp +++ b/Source/WebCore/bindings/js/JSCSSValueCustom.cpp @@ -49,7 +49,7 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, CSSValue* value) if (!value) return jsNull(); - DOMObject* wrapper = getCachedDOMObjectWrapper(exec, value); + JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), value); if (wrapper) return wrapper; diff --git a/Source/WebCore/bindings/js/JSCallbackData.h b/Source/WebCore/bindings/js/JSCallbackData.h index 942cd9c..94ca48d 100644 --- a/Source/WebCore/bindings/js/JSCallbackData.h +++ b/Source/WebCore/bindings/js/JSCallbackData.h @@ -32,7 +32,7 @@ #include "JSDOMBinding.h" #include "JSDOMGlobalObject.h" #include "ScriptExecutionContext.h" -#include <collector/handles/Global.h> +#include <heap/Strong.h> #include <runtime/JSObject.h> #include <wtf/Threading.h> @@ -66,8 +66,8 @@ public: JSC::JSValue invokeCallback(JSC::MarkedArgumentBuffer&, bool* raisedException = 0); private: - JSC::Global<JSC::JSObject> m_callback; - JSC::Global<JSDOMGlobalObject> m_globalObject; + JSC::Strong<JSC::JSObject> m_callback; + JSC::Strong<JSDOMGlobalObject> m_globalObject; #ifndef NDEBUG ThreadIdentifier m_thread; #endif diff --git a/Source/WebCore/bindings/js/JSCanvasRenderingContextCustom.cpp b/Source/WebCore/bindings/js/JSCanvasRenderingContextCustom.cpp index cab7ba3..cd20dc9 100644 --- a/Source/WebCore/bindings/js/JSCanvasRenderingContextCustom.cpp +++ b/Source/WebCore/bindings/js/JSCanvasRenderingContextCustom.cpp @@ -44,10 +44,10 @@ JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, CanvasR #if ENABLE(WEBGL) if (object->is3d()) - return getDOMObjectWrapper<JSWebGLRenderingContext>(exec, globalObject, static_cast<WebGLRenderingContext*>(object)); + return wrap<JSWebGLRenderingContext>(exec, globalObject, static_cast<WebGLRenderingContext*>(object)); #endif ASSERT(object->is2d()); - return getDOMObjectWrapper<JSCanvasRenderingContext2D>(exec, globalObject, static_cast<CanvasRenderingContext2D*>(object)); + return wrap<JSCanvasRenderingContext2D>(exec, globalObject, static_cast<CanvasRenderingContext2D*>(object)); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSCustomVoidCallback.h b/Source/WebCore/bindings/js/JSCustomVoidCallback.h index 922e380..f342b8b 100644 --- a/Source/WebCore/bindings/js/JSCustomVoidCallback.h +++ b/Source/WebCore/bindings/js/JSCustomVoidCallback.h @@ -31,7 +31,7 @@ #include "JSDOMGlobalObject.h" #include "VoidCallback.h" -#include <collector/handles/Global.h> +#include <heap/Strong.h> #include <wtf/Forward.h> namespace WebCore { diff --git a/Source/WebCore/bindings/js/JSDOMBinding.cpp b/Source/WebCore/bindings/js/JSDOMBinding.cpp index 8501eb9..5ac07a7 100644 --- a/Source/WebCore/bindings/js/JSDOMBinding.cpp +++ b/Source/WebCore/bindings/js/JSDOMBinding.cpp @@ -44,7 +44,6 @@ #include "JSEventException.h" #include "JSExceptionBase.h" #include "JSMainThreadExecState.h" -#include "JSNode.h" #include "JSRangeException.h" #include "JSXMLHttpRequestException.h" #include "KURL.h" @@ -94,9 +93,6 @@ namespace WebCore { using namespace HTMLNames; -typedef Document::JSWrapperCache JSWrapperCache; -typedef Document::JSWrapperCacheMap JSWrapperCacheMap; - class JSGlobalDataWorldIterator { public: JSGlobalDataWorldIterator(JSGlobalData* globalData) @@ -138,163 +134,6 @@ const JSC::HashTable* getHashTableForGlobalData(JSGlobalData& globalData, const return DOMObjectHashTableMap::mapFor(globalData).get(staticTable); } -bool hasCachedDOMObjectWrapperUnchecked(JSGlobalData* globalData, void* objectHandle) -{ - for (JSGlobalDataWorldIterator worldIter(globalData); worldIter; ++worldIter) { - if (worldIter->m_wrappers.get(objectHandle)) - return true; - } - return false; -} - -bool hasCachedDOMObjectWrapper(JSGlobalData* globalData, void* objectHandle) -{ - for (JSGlobalDataWorldIterator worldIter(globalData); worldIter; ++worldIter) { - if (worldIter->m_wrappers.get(objectHandle)) - return true; - } - return false; -} - -DOMObject* getCachedDOMObjectWrapper(JSC::ExecState* exec, void* objectHandle) -{ - return domObjectWrapperMapFor(exec).get(objectHandle); -} - -void cacheDOMObjectWrapper(JSC::ExecState* exec, void* objectHandle, DOMObject* wrapper) -{ - domObjectWrapperMapFor(exec).set(exec->globalData(), objectHandle, wrapper); -} - -bool hasCachedDOMNodeWrapperUnchecked(Document* document, Node* node) -{ - if (!document) - return hasCachedDOMObjectWrapperUnchecked(JSDOMWindow::commonJSGlobalData(), node); - - JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap(); - for (JSWrapperCacheMap::iterator iter = wrapperCacheMap.begin(); iter != wrapperCacheMap.end(); ++iter) { - if (iter->second->get(node)) - return true; - } - return false; -} - -void cacheDOMNodeWrapper(JSC::ExecState* exec, Document* document, Node* node, JSNode* wrapper) -{ - if (!document) - domObjectWrapperMapFor(exec).set(exec->globalData(), node, wrapper); - else - document->getWrapperCache(currentWorld(exec))->set(exec->globalData(), node, wrapper); - - if (currentWorld(exec)->isNormal()) - node->setWrapper(exec->globalData(), wrapper); -} - -static inline bool isObservableThroughDOM(JSNode* jsNode, DOMWrapperWorld* world) -{ - // Certain conditions implicitly make existence of a JS DOM node wrapper observable - // through the DOM, even if no explicit reference to it remains. - - Node* node = jsNode->impl(); - - if (node->inDocument()) { - // If a node is in the document, and its wrapper has custom properties, - // the wrapper is observable because future access to the node through the - // DOM must reflect those properties. - if (jsNode->hasCustomProperties()) - return true; - - // If a node is in the document, and has event listeners, its wrapper is - // observable because its wrapper is responsible for marking those event listeners. - if (node->hasEventListeners()) - return true; // Technically, we may overzealously mark a wrapper for a node that has only non-JS event listeners. Oh well. - - // If a node owns another object with a wrapper with custom properties, - // the wrapper must be treated as observable, because future access to - // those objects through the DOM must reflect those properties. - // FIXME: It would be better if this logic could be in the node next to - // the custom markChildren functions rather than here. - // Note that for some compound objects like stylesheets and CSSStyleDeclarations, - // we don't descend to check children for custom properties, and just conservatively - // keep the node wrappers protecting them alive. - if (node->isElementNode()) { - if (NamedNodeMap* attributes = static_cast<Element*>(node)->attributeMap()) { - if (DOMObject* wrapper = world->m_wrappers.get(attributes)) { - // FIXME: This check seems insufficient, because NamedNodeMap items can have custom properties themselves. - // Maybe it would be OK to just keep the wrapper alive, as it is done for CSSOM objects below. - if (wrapper->hasCustomProperties()) - return true; - } - } - if (node->isStyledElement()) { - if (CSSMutableStyleDeclaration* style = static_cast<StyledElement*>(node)->inlineStyleDecl()) { - if (world->m_wrappers.get(style)) - return true; - } - } - if (static_cast<Element*>(node)->hasTagName(canvasTag)) { - if (CanvasRenderingContext* context = static_cast<HTMLCanvasElement*>(node)->renderingContext()) { - if (DOMObject* wrapper = world->m_wrappers.get(context)) { - if (wrapper->hasCustomProperties()) - return true; - } - } - } else if (static_cast<Element*>(node)->hasTagName(linkTag)) { - if (StyleSheet* sheet = static_cast<HTMLLinkElement*>(node)->sheet()) { - if (world->m_wrappers.get(sheet)) - return true; - } - } else if (static_cast<Element*>(node)->hasTagName(styleTag)) { - if (StyleSheet* sheet = static_cast<HTMLStyleElement*>(node)->sheet()) { - if (world->m_wrappers.get(sheet)) - return true; - } - } - } else if (node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) { - if (StyleSheet* sheet = static_cast<ProcessingInstruction*>(node)->sheet()) { - if (world->m_wrappers.get(sheet)) - return true; - } - } - } else { - // If a wrapper is the last reference to an image or script element - // that is loading but not in the document, the wrapper is observable - // because it is the only thing keeping the image element alive, and if - // the image element is destroyed, its load event will not fire. - // FIXME: The DOM should manage this issue without the help of JavaScript wrappers. - if (node->hasTagName(imgTag) && !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent()) - return true; - if (node->hasTagName(scriptTag) && !static_cast<HTMLScriptElement*>(node)->haveFiredLoadEvent()) - return true; -#if ENABLE(VIDEO) - if (node->hasTagName(audioTag) && !static_cast<HTMLAudioElement*>(node)->paused()) - return true; -#endif - } - - // If a node is firing event listeners, its wrapper is observable because - // its wrapper is responsible for marking those event listeners. - if (node->isFiringEventListeners()) - return true; - - return false; -} - -void markDOMNodesForDocument(MarkStack& markStack, Document* document) -{ - JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap(); - for (JSWrapperCacheMap::iterator wrappersIter = wrapperCacheMap.begin(); wrappersIter != wrapperCacheMap.end(); ++wrappersIter) { - DOMWrapperWorld* world = wrappersIter->first; - JSWrapperCache* nodeDict = wrappersIter->second; - - JSWrapperCache::iterator nodeEnd = nodeDict->end(); - for (JSWrapperCache::iterator nodeIt = nodeDict->begin(); nodeIt != nodeEnd; ++nodeIt) { - if (isObservableThroughDOM(nodeIt.get().second, world)) - markStack.deprecatedAppend(nodeIt.getSlot().second); - } - } -} - void markActiveObjectsForContext(MarkStack& markStack, JSGlobalData& globalData, ScriptExecutionContext* scriptExecutionContext) { // If an element has pending activity that may result in event listeners being called @@ -319,42 +158,6 @@ void markActiveObjectsForContext(MarkStack& markStack, JSGlobalData& globalData, } } -typedef std::pair<JSNode*, DOMWrapperWorld*> WrapperAndWorld; -typedef WTF::Vector<WrapperAndWorld, 8> WrapperSet; - -static inline void takeWrappers(Node* node, Document* document, WrapperSet& wrapperSet) -{ - if (document) { - JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap(); - for (JSWrapperCacheMap::iterator iter = wrapperCacheMap.begin(); iter != wrapperCacheMap.end(); ++iter) { - if (JSNode* wrapper = iter->second->take(node)) - wrapperSet.append(WrapperAndWorld(wrapper, iter->first)); - } - } else { - for (JSGlobalDataWorldIterator worldIter(JSDOMWindow::commonJSGlobalData()); worldIter; ++worldIter) { - DOMWrapperWorld* world = *worldIter; - if (JSNode* wrapper = static_cast<JSNode*>(world->m_wrappers.take(node))) - wrapperSet.append(WrapperAndWorld(wrapper, world)); - } - } -} - -void updateDOMNodeDocument(Node* node, Document* oldDocument, Document* newDocument) -{ - ASSERT(oldDocument != newDocument); - - WrapperSet wrapperSet; - takeWrappers(node, oldDocument, wrapperSet); - - for (unsigned i = 0; i < wrapperSet.size(); ++i) { - JSNode* wrapper = wrapperSet[i].first; - if (newDocument) - newDocument->getWrapperCache(wrapperSet[i].second)->set(*wrapperSet[i].second->globalData(), node, wrapper); - else - wrapperSet[i].second->m_wrappers.set(*wrapperSet[i].second->globalData(), node, wrapper); - } -} - void markDOMObjectWrapper(MarkStack& markStack, JSGlobalData& globalData, void* object) { // FIXME: This could be changed to only mark wrappers that are "observable" @@ -364,25 +167,8 @@ void markDOMObjectWrapper(MarkStack& markStack, JSGlobalData& globalData, void* return; for (JSGlobalDataWorldIterator worldIter(&globalData); worldIter; ++worldIter) { - if (HandleSlot wrapperSlot = worldIter->m_wrappers.getSlot(object)) - markStack.deprecatedAppend(wrapperSlot); - } -} - -void markDOMNodeWrapper(MarkStack& markStack, Document* document, Node* node) -{ - if (document) { - JSWrapperCacheMap& wrapperCacheMap = document->wrapperCacheMap(); - for (JSWrapperCacheMap::iterator iter = wrapperCacheMap.begin(); iter != wrapperCacheMap.end(); ++iter) { - if (HandleSlot wrapperSlot = iter->second->getSlot(node)) - markStack.deprecatedAppend(wrapperSlot); - } - return; - } - - for (JSGlobalDataWorldIterator worldIter(JSDOMWindow::commonJSGlobalData()); worldIter; ++worldIter) { - if (HandleSlot wrapperSlot = worldIter->m_wrappers.getSlot(node)) - markStack.deprecatedAppend(wrapperSlot); + if (JSDOMWrapper* wrapper = worldIter->m_wrappers.get(object).get()) + markStack.deprecatedAppend(reinterpret_cast<JSCell**>(&wrapper)); } } @@ -646,11 +432,11 @@ Structure* getCachedDOMStructure(JSDOMGlobalObject* globalObject, const ClassInf return structures.get(classInfo).get(); } -Structure* cacheDOMStructure(JSDOMGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure, const ClassInfo* classInfo) +Structure* cacheDOMStructure(JSDOMGlobalObject* globalObject, Structure* structure, const ClassInfo* classInfo) { JSDOMStructureMap& structures = globalObject->structures(); ASSERT(!structures.contains(classInfo)); - return structures.set(classInfo, structure).first->second.get(); + return structures.set(classInfo, WriteBarrier<Structure>(globalObject->globalData(), globalObject, structure)).first->second.get(); } JSC::JSObject* toJSSequence(ExecState* exec, JSValue value, unsigned& length) diff --git a/Source/WebCore/bindings/js/JSDOMBinding.h b/Source/WebCore/bindings/js/JSDOMBinding.h index 934d9b3..803429f 100644 --- a/Source/WebCore/bindings/js/JSDOMBinding.h +++ b/Source/WebCore/bindings/js/JSDOMBinding.h @@ -26,9 +26,9 @@ #include "JSDOMWrapper.h" #include "DOMWrapperWorld.h" #include "Document.h" +#include <heap/Weak.h> #include <runtime/Completion.h> #include <runtime/Lookup.h> -#include <runtime/WeakGCMap.h> #include <wtf/Forward.h> #include <wtf/Noncopyable.h> @@ -49,13 +49,13 @@ namespace WebCore { typedef int ExceptionCode; - // FIXME: This class should collapse into DOMObject once all DOMObjects are + // FIXME: This class should collapse into JSDOMWrapper once all JSDOMWrappers are // updated to store a globalObject pointer. - class DOMObjectWithGlobalPointer : public DOMObject { + class JSDOMWrapperWithGlobalPointer : public JSDOMWrapper { public: JSDOMGlobalObject* globalObject() const { - return static_cast<JSDOMGlobalObject*>(DOMObject::globalObject()); + return static_cast<JSDOMGlobalObject*>(JSDOMWrapper::globalObject()); } ScriptExecutionContext* scriptExecutionContext() const @@ -64,14 +64,14 @@ namespace WebCore { return globalObject()->scriptExecutionContext(); } - static PassRefPtr<JSC::Structure> createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype) + static JSC::Structure* createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype) { return JSC::Structure::create(globalData, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: - DOMObjectWithGlobalPointer(NonNullPassRefPtr<JSC::Structure> structure, JSDOMGlobalObject* globalObject) - : DOMObject(globalObject, structure) + JSDOMWrapperWithGlobalPointer(JSC::Structure* structure, JSDOMGlobalObject* globalObject) + : JSDOMWrapper(globalObject, structure) { // FIXME: This ASSERT is valid, but fires in fast/dom/gc-6.html when trying to create // new JavaScript objects on detached windows due to DOMWindow::document() @@ -81,17 +81,17 @@ namespace WebCore { }; // Base class for all constructor objects in the JSC bindings. - class DOMConstructorObject : public DOMObjectWithGlobalPointer { + class DOMConstructorObject : public JSDOMWrapperWithGlobalPointer { public: - static PassRefPtr<JSC::Structure> createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype) + static JSC::Structure* createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype) { return JSC::Structure::create(globalData, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } protected: - static const unsigned StructureFlags = JSC::ImplementsHasInstance | JSC::OverridesMarkChildren | DOMObjectWithGlobalPointer::StructureFlags; - DOMConstructorObject(NonNullPassRefPtr<JSC::Structure> structure, JSDOMGlobalObject* globalObject) - : DOMObjectWithGlobalPointer(structure, globalObject) + static const unsigned StructureFlags = JSC::ImplementsHasInstance | JSC::OverridesMarkChildren | JSDOMWrapperWithGlobalPointer::StructureFlags; + DOMConstructorObject(JSC::Structure* structure, JSDOMGlobalObject* globalObject) + : JSDOMWrapperWithGlobalPointer(structure, globalObject) { } }; @@ -106,30 +106,18 @@ namespace WebCore { } protected: - DOMConstructorWithDocument(NonNullPassRefPtr<JSC::Structure> structure, JSDOMGlobalObject* globalObject) + DOMConstructorWithDocument(JSC::Structure* structure, JSDOMGlobalObject* globalObject) : DOMConstructorObject(structure, globalObject) { ASSERT(globalObject->scriptExecutionContext()->isDocument()); } }; - - DOMObject* getCachedDOMObjectWrapper(JSC::ExecState*, void* objectHandle); - bool hasCachedDOMObjectWrapper(JSC::JSGlobalData*, void* objectHandle); - void cacheDOMObjectWrapper(JSC::ExecState*, void* objectHandle, DOMObject* wrapper); - - JSNode* getCachedDOMNodeWrapper(JSC::ExecState*, Document*, Node*); - void cacheDOMNodeWrapper(JSC::ExecState*, Document*, Node*, JSNode* wrapper); - void updateDOMNodeDocument(Node*, Document* oldDocument, Document* newDocument); - - void markDOMNodesForDocument(JSC::MarkStack&, Document*); + void markActiveObjectsForContext(JSC::MarkStack&, JSC::JSGlobalData&, ScriptExecutionContext*); void markDOMObjectWrapper(JSC::MarkStack&, JSC::JSGlobalData& globalData, void* object); - void markDOMNodeWrapper(JSC::MarkStack& markStack, Document* document, Node* node); - bool hasCachedDOMObjectWrapperUnchecked(JSC::JSGlobalData*, void* objectHandle); - bool hasCachedDOMNodeWrapperUnchecked(Document*, Node*); JSC::Structure* getCachedDOMStructure(JSDOMGlobalObject*, const JSC::ClassInfo*); - JSC::Structure* cacheDOMStructure(JSDOMGlobalObject*, NonNullPassRefPtr<JSC::Structure>, const JSC::ClassInfo*); + JSC::Structure* cacheDOMStructure(JSDOMGlobalObject*, JSC::Structure*, const JSC::ClassInfo*); inline JSDOMGlobalObject* deprecatedGlobalObjectForPrototype(JSC::ExecState* exec) { @@ -145,52 +133,70 @@ namespace WebCore { return structure; return cacheDOMStructure(globalObject, WrapperClass::createStructure(exec->globalData(), WrapperClass::createPrototype(exec, globalObject)), &WrapperClass::s_info); } + template<class WrapperClass> inline JSC::Structure* deprecatedGetDOMStructure(JSC::ExecState* exec) { // FIXME: This function is wrong. It uses the wrong global object for creating the prototype structure. return getDOMStructure<WrapperClass>(exec, deprecatedGlobalObjectForPrototype(exec)); } + template<class WrapperClass> inline JSC::JSObject* getDOMPrototype(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject) { return static_cast<JSC::JSObject*>(asObject(getDOMStructure<WrapperClass>(exec, static_cast<JSDOMGlobalObject*>(globalObject))->storedPrototype())); } - #define CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, className, object) createDOMObjectWrapper<JS##className>(exec, globalObject, static_cast<className*>(object)) - template<class WrapperClass, class DOMClass> inline DOMObject* createDOMObjectWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* object) + + // Overload these functions to provide a fast path for wrapper access. + inline JSDOMWrapper* getInlineCachedWrapper(DOMWrapperWorld*, void*) { return 0; } + inline bool setInlineCachedWrapper(DOMWrapperWorld*, void*, JSDOMWrapper*) { return false; } + inline bool clearInlineCachedWrapper(DOMWrapperWorld*, void*, JSDOMWrapper*) { return false; } + + // Overload these functions to provide a custom WeakHandleOwner. + inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld* world, void*) { return world->defaultWrapperOwner(); } + inline void* wrapperContext(DOMWrapperWorld*, void* domObject) { return domObject; } + + template <typename DOMClass> inline JSDOMWrapper* getCachedWrapper(DOMWrapperWorld* world, DOMClass* domObject) { - ASSERT(object); - ASSERT(!getCachedDOMObjectWrapper(exec, object)); - // FIXME: new (exec) could use a different globalData than the globalData this wrapper is cached on. - WrapperClass* wrapper = new (exec) WrapperClass(getDOMStructure<WrapperClass>(exec, globalObject), globalObject, object); - cacheDOMObjectWrapper(exec, object, wrapper); - return wrapper; + if (JSDOMWrapper* wrapper = getInlineCachedWrapper(world, domObject)) + return wrapper; + return world->m_wrappers.get(domObject).get(); } - template<class WrapperClass, class DOMClass> inline JSC::JSValue getDOMObjectWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* object) + + template <typename DOMClass> inline void cacheWrapper(DOMWrapperWorld* world, DOMClass* domObject, JSDOMWrapper* wrapper) { - if (!object) - return JSC::jsNull(); - if (DOMObject* wrapper = getCachedDOMObjectWrapper(exec, object)) - return wrapper; - return createDOMObjectWrapper<WrapperClass>(exec, globalObject, object); + if (setInlineCachedWrapper(world, domObject, wrapper)) + return; + ASSERT(!world->m_wrappers.contains(domObject)); + world->m_wrappers.set(domObject, JSC::Weak<JSDOMWrapper>(*world->globalData(), wrapper, wrapperOwner(world, domObject), wrapperContext(world, domObject))); } - #define CREATE_DOM_NODE_WRAPPER(exec, globalObject, className, object) createDOMNodeWrapper<JS##className>(exec, globalObject, static_cast<className*>(object)) - template<class WrapperClass, class DOMClass> inline JSNode* createDOMNodeWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* node) + template <typename DOMClass> inline void uncacheWrapper(DOMWrapperWorld* world, DOMClass* domObject, JSDOMWrapper* wrapper) + { + if (clearInlineCachedWrapper(world, domObject, wrapper)) + return; + ASSERT(world->m_wrappers.find(domObject)->second.get() == wrapper); + world->m_wrappers.remove(domObject); + } + + #define CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, className, object) createWrapper<JS##className>(exec, globalObject, static_cast<className*>(object)) + #define CREATE_DOM_NODE_WRAPPER(exec, globalObject, className, object) static_cast<JSNode*>(createWrapper<JS##className>(exec, globalObject, static_cast<className*>(object))) + template<class WrapperClass, class DOMClass> inline JSDOMWrapper* createWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* node) { ASSERT(node); - ASSERT(!getCachedDOMNodeWrapper(exec, node->document(), node)); + ASSERT(!getCachedWrapper(currentWorld(exec), node)); WrapperClass* wrapper = new (exec) WrapperClass(getDOMStructure<WrapperClass>(exec, globalObject), globalObject, node); // FIXME: The entire function can be removed, once we fix caching. // This function is a one-off hack to make Nodes cache in the right global object. - cacheDOMNodeWrapper(exec, node->document(), node, wrapper); + cacheWrapper(currentWorld(exec), node, wrapper); return wrapper; } - template<class WrapperClass, class DOMClass> inline JSC::JSValue getDOMNodeWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* node) + + template<class WrapperClass, class DOMClass> inline JSC::JSValue wrap(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* domObject) { - if (!node) + if (!domObject) return JSC::jsNull(); - if (JSC::JSCell* wrapper = getCachedDOMNodeWrapper(exec, node->document(), node)) + if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), domObject)) return wrapper; - return createDOMNodeWrapper<WrapperClass>(exec, globalObject, node); + return createWrapper<WrapperClass>(exec, globalObject, domObject); } const JSC::HashTable* getHashTableForGlobalData(JSC::JSGlobalData&, const JSC::HashTable* staticTable); diff --git a/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp b/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp index 8183b6e..3e3d037 100644 --- a/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp +++ b/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp @@ -42,8 +42,8 @@ namespace WebCore { const ClassInfo JSDOMGlobalObject::s_info = { "DOMGlobalObject", &JSGlobalObject::s_info, 0, 0 }; -JSDOMGlobalObject::JSDOMGlobalObject(NonNullPassRefPtr<Structure> structure, PassRefPtr<DOMWrapperWorld> world, JSObject* thisValue) - : JSGlobalObject(structure, thisValue) +JSDOMGlobalObject::JSDOMGlobalObject(JSGlobalData& globalData, Structure* structure, PassRefPtr<DOMWrapperWorld> world, JSObject* thisValue) + : JSGlobalObject(globalData, structure, thisValue) , m_currentEvent(0) , m_world(world) { @@ -56,7 +56,7 @@ void JSDOMGlobalObject::markChildren(MarkStack& markStack) JSDOMStructureMap::iterator end = structures().end(); for (JSDOMStructureMap::iterator it = structures().begin(); it != end; ++it) - markStack.append(it->second->storedPrototypeSlot()); + markStack.append(&it->second); JSDOMConstructorMap::iterator end2 = constructors().end(); for (JSDOMConstructorMap::iterator it2 = constructors().begin(); it2 != end2; ++it2) diff --git a/Source/WebCore/bindings/js/JSDOMGlobalObject.h b/Source/WebCore/bindings/js/JSDOMGlobalObject.h index 1e992c5..9190e01 100644 --- a/Source/WebCore/bindings/js/JSDOMGlobalObject.h +++ b/Source/WebCore/bindings/js/JSDOMGlobalObject.h @@ -38,7 +38,7 @@ namespace WebCore { class JSEventListener; class ScriptExecutionContext; - typedef HashMap<const JSC::ClassInfo*, RefPtr<JSC::Structure> > JSDOMStructureMap; + typedef HashMap<const JSC::ClassInfo*, JSC::WriteBarrier<JSC::Structure> > JSDOMStructureMap; typedef HashMap<const JSC::ClassInfo*, JSC::WriteBarrier<JSC::JSObject> > JSDOMConstructorMap; class JSDOMGlobalObject : public JSC::JSGlobalObject { @@ -46,7 +46,7 @@ namespace WebCore { protected: struct JSDOMGlobalObjectData; - JSDOMGlobalObject(NonNullPassRefPtr<JSC::Structure>, PassRefPtr<DOMWrapperWorld>, JSC::JSObject* thisValue); + JSDOMGlobalObject(JSC::JSGlobalData&, JSC::Structure*, PassRefPtr<DOMWrapperWorld>, JSC::JSObject* thisValue); public: JSDOMStructureMap& structures() { return m_structures; } @@ -69,7 +69,7 @@ namespace WebCore { static const JSC::ClassInfo s_info; - static PassRefPtr<JSC::Structure> createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype) + static JSC::Structure* createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype) { return JSC::Structure::create(globalData, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } diff --git a/Source/WebCore/bindings/js/JSDOMImplementationCustom.cpp b/Source/WebCore/bindings/js/JSDOMImplementationCustom.cpp index ac83c69..aa3a607 100644 --- a/Source/WebCore/bindings/js/JSDOMImplementationCustom.cpp +++ b/Source/WebCore/bindings/js/JSDOMImplementationCustom.cpp @@ -33,10 +33,10 @@ void JSDOMImplementation::markChildren(MarkStack& markStack) { Base::markChildren(markStack); - DOMImplementation* domImplementation = impl(); - Document* ownerDocument = domImplementation->ownerDocument(); - if (ownerDocument) - markDOMNodeWrapper(markStack, ownerDocument, ownerDocument); + Document* ownerDocument = impl()->ownerDocument(); + if (!ownerDocument) + return; + markStack.addOpaqueRoot(ownerDocument); } } diff --git a/Source/WebCore/bindings/js/JSDOMWindowBase.cpp b/Source/WebCore/bindings/js/JSDOMWindowBase.cpp index 584f610..10f7cd9 100644 --- a/Source/WebCore/bindings/js/JSDOMWindowBase.cpp +++ b/Source/WebCore/bindings/js/JSDOMWindowBase.cpp @@ -45,8 +45,8 @@ namespace WebCore { const ClassInfo JSDOMWindowBase::s_info = { "Window", &JSDOMGlobalObject::s_info, 0, 0 }; -JSDOMWindowBase::JSDOMWindowBase(NonNullPassRefPtr<Structure> structure, PassRefPtr<DOMWindow> window, JSDOMWindowShell* shell) - : JSDOMGlobalObject(structure, shell->world(), shell) +JSDOMWindowBase::JSDOMWindowBase(JSGlobalData& globalData, Structure* structure, PassRefPtr<DOMWindow> window, JSDOMWindowShell* shell) + : JSDOMGlobalObject(globalData, structure, shell->world(), shell) , m_impl(window) , m_shell(shell) { diff --git a/Source/WebCore/bindings/js/JSDOMWindowBase.h b/Source/WebCore/bindings/js/JSDOMWindowBase.h index bfec31c..946f95c 100644 --- a/Source/WebCore/bindings/js/JSDOMWindowBase.h +++ b/Source/WebCore/bindings/js/JSDOMWindowBase.h @@ -22,7 +22,7 @@ #include "PlatformString.h" #include "JSDOMBinding.h" -#include <collector/handles/Global.h> +#include <heap/Strong.h> #include <wtf/Forward.h> #include <wtf/HashMap.h> #include <wtf/OwnPtr.h> @@ -44,7 +44,7 @@ namespace WebCore { class JSDOMWindowBase : public JSDOMGlobalObject { typedef JSDOMGlobalObject Base; protected: - JSDOMWindowBase(NonNullPassRefPtr<JSC::Structure>, PassRefPtr<DOMWindow>, JSDOMWindowShell*); + JSDOMWindowBase(JSC::JSGlobalData&, JSC::Structure*, PassRefPtr<DOMWindow>, JSDOMWindowShell*); public: void updateDocument(); @@ -57,7 +57,7 @@ namespace WebCore { static const JSC::ClassInfo s_info; - static PassRefPtr<JSC::Structure> createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype) + static JSC::Structure* createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype) { return JSC::Structure::create(globalData, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } diff --git a/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp b/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp index 03f9d68..4bde9e5 100644 --- a/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp +++ b/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp @@ -441,24 +441,24 @@ JSValue JSDOMWindow::lookupSetter(ExecState* exec, const Identifier& propertyNam JSValue JSDOMWindow::history(ExecState* exec) const { History* history = impl()->history(); - if (DOMObject* wrapper = getCachedDOMObjectWrapper(exec, history)) + if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), history)) return wrapper; JSDOMWindow* window = const_cast<JSDOMWindow*>(this); JSHistory* jsHistory = new (exec) JSHistory(getDOMStructure<JSHistory>(exec, window), window, history); - cacheDOMObjectWrapper(exec, history, jsHistory); + cacheWrapper(currentWorld(exec), history, jsHistory); return jsHistory; } JSValue JSDOMWindow::location(ExecState* exec) const { Location* location = impl()->location(); - if (DOMObject* wrapper = getCachedDOMObjectWrapper(exec, location)) + if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), location)) return wrapper; JSDOMWindow* window = const_cast<JSDOMWindow*>(this); JSLocation* jsLocation = new (exec) JSLocation(getDOMStructure<JSLocation>(exec, window), window, location); - cacheDOMObjectWrapper(exec, location, jsLocation); + cacheWrapper(currentWorld(exec), location, jsLocation); return jsLocation; } @@ -732,9 +732,14 @@ JSValue JSDOMWindow::postMessage(ExecState* exec) JSValue JSDOMWindow::setTimeout(ExecState* exec) { - OwnPtr<ScheduledAction> action = ScheduledAction::create(exec, currentWorld(exec)); + ContentSecurityPolicy* contentSecurityPolicy = impl()->document() ? impl()->document()->contentSecurityPolicy() : 0; + OwnPtr<ScheduledAction> action = ScheduledAction::create(exec, currentWorld(exec), contentSecurityPolicy); if (exec->hadException()) return jsUndefined(); + + if (!action) + return jsNumber(0); + int delay = exec->argument(1).toInt32(exec); ExceptionCode ec = 0; @@ -746,11 +751,15 @@ JSValue JSDOMWindow::setTimeout(ExecState* exec) JSValue JSDOMWindow::setInterval(ExecState* exec) { - OwnPtr<ScheduledAction> action = ScheduledAction::create(exec, currentWorld(exec)); + ContentSecurityPolicy* contentSecurityPolicy = impl()->document() ? impl()->document()->contentSecurityPolicy() : 0; + OwnPtr<ScheduledAction> action = ScheduledAction::create(exec, currentWorld(exec), contentSecurityPolicy); if (exec->hadException()) return jsUndefined(); int delay = exec->argument(1).toInt32(exec); + if (!action) + return jsNumber(0); + ExceptionCode ec = 0; int result = impl()->setInterval(action.release(), delay, ec); setDOMException(exec, ec); diff --git a/Source/WebCore/bindings/js/JSDOMWindowShell.cpp b/Source/WebCore/bindings/js/JSDOMWindowShell.cpp index 817e9c0..0aec968 100644 --- a/Source/WebCore/bindings/js/JSDOMWindowShell.cpp +++ b/Source/WebCore/bindings/js/JSDOMWindowShell.cpp @@ -44,7 +44,7 @@ ASSERT_CLASS_FITS_IN_CELL(JSDOMWindowShell); const ClassInfo JSDOMWindowShell::s_info = { "JSDOMWindowShell", &Base::s_info, 0, 0 }; JSDOMWindowShell::JSDOMWindowShell(PassRefPtr<DOMWindow> window, DOMWrapperWorld* world) - : Base(JSDOMWindowShell::createStructure(*world->globalData(), jsNull())) + : Base(*world->globalData(), JSDOMWindowShell::createStructure(*world->globalData(), jsNull())) , m_world(world) { ASSERT(inherits(&s_info)); @@ -60,11 +60,11 @@ void JSDOMWindowShell::setWindow(PassRefPtr<DOMWindow> domWindow) // Explicitly protect the global object's prototype so it isn't collected // when we allocate the global object. (Once the global object is fully // constructed, it can mark its own prototype.) - RefPtr<Structure> prototypeStructure = JSDOMWindowPrototype::createStructure(*JSDOMWindow::commonJSGlobalData(), jsNull()); - Global<JSDOMWindowPrototype> prototype(*JSDOMWindow::commonJSGlobalData(), new JSDOMWindowPrototype(0, prototypeStructure.release())); + Structure* prototypeStructure = JSDOMWindowPrototype::createStructure(*JSDOMWindow::commonJSGlobalData(), jsNull()); + Strong<JSDOMWindowPrototype> prototype(*JSDOMWindow::commonJSGlobalData(), new JSDOMWindowPrototype(*JSDOMWindow::commonJSGlobalData(), 0, prototypeStructure)); - RefPtr<Structure> structure = JSDOMWindow::createStructure(*JSDOMWindow::commonJSGlobalData(), prototype.get()); - JSDOMWindow* jsDOMWindow = new (JSDOMWindow::commonJSGlobalData()) JSDOMWindow(structure.release(), domWindow, this); + Structure* structure = JSDOMWindow::createStructure(*JSDOMWindow::commonJSGlobalData(), prototype.get()); + JSDOMWindow* jsDOMWindow = new (JSDOMWindow::commonJSGlobalData()) JSDOMWindow(*JSDOMWindow::commonJSGlobalData(), structure, domWindow, this); prototype->putAnonymousValue(*JSDOMWindow::commonJSGlobalData(), 0, jsDOMWindow); setWindow(*JSDOMWindow::commonJSGlobalData(), jsDOMWindow); } diff --git a/Source/WebCore/bindings/js/JSDOMWindowShell.h b/Source/WebCore/bindings/js/JSDOMWindowShell.h index 4307c1c..c2c5336 100644 --- a/Source/WebCore/bindings/js/JSDOMWindowShell.h +++ b/Source/WebCore/bindings/js/JSDOMWindowShell.h @@ -48,7 +48,7 @@ namespace WebCore { { ASSERT_ARG(window, window); m_window.set(globalData, this, window); - setPrototype(window->prototype()); + setPrototype(globalData, window->prototype()); } void setWindow(PassRefPtr<DOMWindow>); @@ -58,7 +58,7 @@ namespace WebCore { void* operator new(size_t); - static PassRefPtr<JSC::Structure> createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype) + static JSC::Structure* createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype) { return JSC::Structure::create(globalData, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } diff --git a/Source/WebCore/bindings/js/JSDOMWrapper.cpp b/Source/WebCore/bindings/js/JSDOMWrapper.cpp index c91230b..60c0ed1 100644 --- a/Source/WebCore/bindings/js/JSDOMWrapper.cpp +++ b/Source/WebCore/bindings/js/JSDOMWrapper.cpp @@ -34,7 +34,7 @@ namespace WebCore { #ifndef NDEBUG -DOMObject::~DOMObject() +JSDOMWrapper::~JSDOMWrapper() { } diff --git a/Source/WebCore/bindings/js/JSDOMWrapper.h b/Source/WebCore/bindings/js/JSDOMWrapper.h index 0f8031c..1484dc6 100644 --- a/Source/WebCore/bindings/js/JSDOMWrapper.h +++ b/Source/WebCore/bindings/js/JSDOMWrapper.h @@ -26,16 +26,15 @@ namespace WebCore { -// FIXME: Rename to JSDOMWrapper. -class DOMObject : public JSC::JSObjectWithGlobalObject { +class JSDOMWrapper : public JSC::JSObjectWithGlobalObject { protected: - explicit DOMObject(JSC::JSGlobalObject* globalObject, NonNullPassRefPtr<JSC::Structure> structure) + explicit JSDOMWrapper(JSC::JSGlobalObject* globalObject, JSC::Structure* structure) : JSObjectWithGlobalObject(globalObject, structure) { } #ifndef NDEBUG - virtual ~DOMObject(); + virtual ~JSDOMWrapper(); #endif }; diff --git a/Source/WebCore/bindings/js/JSDataGridDataSource.h b/Source/WebCore/bindings/js/JSDataGridDataSource.h index 684a663..f82ff63 100644 --- a/Source/WebCore/bindings/js/JSDataGridDataSource.h +++ b/Source/WebCore/bindings/js/JSDataGridDataSource.h @@ -29,7 +29,7 @@ #if ENABLE(DATAGRID) #include "DataGridDataSource.h" -#include <collector/handles/Global.h> +#include <heap/Strong.h> #include <runtime/JSValue.h> #include <wtf/PassRefPtr.h> #include <wtf/RefPtr.h> diff --git a/Source/WebCore/bindings/js/JSDataViewCustom.cpp b/Source/WebCore/bindings/js/JSDataViewCustom.cpp index eaf57bd..48d56d8 100644 --- a/Source/WebCore/bindings/js/JSDataViewCustom.cpp +++ b/Source/WebCore/bindings/js/JSDataViewCustom.cpp @@ -44,7 +44,7 @@ enum DataViewAccessType { JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, DataView* object) { - return getDOMObjectWrapper<JSDataView>(exec, globalObject, object); + return wrap<JSDataView>(exec, globalObject, object); } EncodedJSValue JSC_HOST_CALL JSDataViewConstructor::constructJSDataView(ExecState* exec) diff --git a/Source/WebCore/bindings/js/JSDirectoryEntryCustom.cpp b/Source/WebCore/bindings/js/JSDirectoryEntryCustom.cpp index ceb3ccb..82d7c1f 100644 --- a/Source/WebCore/bindings/js/JSDirectoryEntryCustom.cpp +++ b/Source/WebCore/bindings/js/JSDirectoryEntryCustom.cpp @@ -38,7 +38,7 @@ #include "JSDOMBinding.h" #include "JSEntryCallback.h" #include "JSErrorCallback.h" -#include "JSFlags.h" +#include "JSWebKitFlags.h" #include <wtf/Assertions.h> using namespace JSC; @@ -58,16 +58,16 @@ JSValue JSDirectoryEntry::getFile(ExecState* exec) return jsUndefined(); } - RefPtr<Flags> flags; - if (!exec->argument(1).isNull() && !exec->argument(1).isUndefined() && exec->argument(1).isObject() && !exec->argument(1).inherits(&JSFlags::s_info)) { + RefPtr<WebKitFlags> flags; + if (!exec->argument(1).isNull() && !exec->argument(1).isUndefined() && exec->argument(1).isObject() && !exec->argument(1).inherits(&JSWebKitFlags::s_info)) { JSObject* object = exec->argument(1).getObject(); - flags = Flags::create(); + flags = WebKitFlags::create(); JSValue jsCreate = object->get(exec, Identifier(exec, "create")); flags->setCreate(jsCreate.toBoolean(exec)); JSValue jsExclusive = object->get(exec, Identifier(exec, "exclusive")); flags->setExclusive(jsExclusive.toBoolean(exec)); } else - flags = toFlags(exec->argument(1)); + flags = toWebKitFlags(exec->argument(1)); if (exec->hadException()) return jsUndefined(); RefPtr<EntryCallback> successCallback; @@ -104,16 +104,16 @@ JSValue JSDirectoryEntry::getDirectory(ExecState* exec) return jsUndefined(); } - RefPtr<Flags> flags; - if (!exec->argument(1).isNull() && !exec->argument(1).isUndefined() && exec->argument(1).isObject() && !exec->argument(1).inherits(&JSFlags::s_info)) { + RefPtr<WebKitFlags> flags; + if (!exec->argument(1).isNull() && !exec->argument(1).isUndefined() && exec->argument(1).isObject() && !exec->argument(1).inherits(&JSWebKitFlags::s_info)) { JSObject* object = exec->argument(1).getObject(); - flags = Flags::create(); + flags = WebKitFlags::create(); JSValue jsCreate = object->get(exec, Identifier(exec, "create")); flags->setCreate(jsCreate.toBoolean(exec)); JSValue jsExclusive = object->get(exec, Identifier(exec, "exclusive")); flags->setExclusive(jsExclusive.toBoolean(exec)); } else - flags = toFlags(exec->argument(1)); + flags = toWebKitFlags(exec->argument(1)); if (exec->hadException()) return jsUndefined(); RefPtr<EntryCallback> successCallback; diff --git a/Source/WebCore/bindings/js/JSDirectoryEntrySyncCustom.cpp b/Source/WebCore/bindings/js/JSDirectoryEntrySyncCustom.cpp index ef14b79..21006ab 100644 --- a/Source/WebCore/bindings/js/JSDirectoryEntrySyncCustom.cpp +++ b/Source/WebCore/bindings/js/JSDirectoryEntrySyncCustom.cpp @@ -38,23 +38,23 @@ #include "JSEntryCallback.h" #include "JSErrorCallback.h" #include "JSFileEntrySync.h" -#include "JSFlags.h" +#include "JSWebKitFlags.h" #include <wtf/Assertions.h> using namespace JSC; namespace WebCore { -static PassRefPtr<Flags> getFlags(ExecState* exec, const JSValue& argument) +static PassRefPtr<WebKitFlags> getFlags(ExecState* exec, const JSValue& argument) { if (argument.isNull() || argument.isUndefined() || !argument.isObject()) return 0; - if (argument.inherits(&JSFlags::s_info)) + if (argument.inherits(&JSWebKitFlags::s_info)) return toFlags(argument); - RefPtr<Flags> flags; + RefPtr<WebKitFlags> flags; JSObject* object = argument.getObject(); - flags = Flags::create(); + flags = WebKitFlags::create(); JSValue jsCreate = object->get(exec, Identifier(exec, "create")); flags->setCreate(jsCreate.toBoolean(exec)); JSValue jsExclusive = object->get(exec, Identifier(exec, "exclusive")); @@ -69,7 +69,7 @@ JSValue JSDirectoryEntrySync::getFile(ExecState* exec) if (exec->hadException()) return jsUndefined(); - RefPtr<Flags> flags = getFlags(exec, exec->argument(1)); + RefPtr<WebKitFlags> flags = getFlags(exec, exec->argument(1)); if (exec->hadException()) return jsUndefined(); @@ -86,7 +86,7 @@ JSValue JSDirectoryEntrySync::getDirectory(ExecState* exec) if (exec->hadException()) return jsUndefined(); - RefPtr<Flags> flags = getFlags(exec, exec->argument(1)); + RefPtr<WebKitFlags> flags = getFlags(exec, exec->argument(1)); if (exec->hadException()) return jsUndefined(); diff --git a/Source/WebCore/bindings/js/JSDocumentCustom.cpp b/Source/WebCore/bindings/js/JSDocumentCustom.cpp index fa2b93c..65641cc 100644 --- a/Source/WebCore/bindings/js/JSDocumentCustom.cpp +++ b/Source/WebCore/bindings/js/JSDocumentCustom.cpp @@ -55,11 +55,9 @@ void JSDocument::markChildren(MarkStack& markStack) Document* document = impl(); JSGlobalData& globalData = *Heap::heap(this)->globalData(); - markDOMNodesForDocument(markStack, document); markActiveObjectsForContext(markStack, globalData, document); markDOMObjectWrapper(markStack, globalData, document->implementation()); markDOMObjectWrapper(markStack, globalData, document->styleSheets()); - document->markCachedNodeLists(markStack, globalData); } JSValue JSDocument::location(ExecState* exec) const @@ -69,11 +67,11 @@ JSValue JSDocument::location(ExecState* exec) const return jsNull(); Location* location = frame->domWindow()->location(); - if (DOMObject* wrapper = getCachedDOMObjectWrapper(exec, location)) + if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), location)) return wrapper; JSLocation* jsLocation = new (exec) JSLocation(getDOMStructure<JSLocation>(exec, globalObject()), globalObject(), location); - cacheDOMObjectWrapper(exec, location, jsLocation); + cacheWrapper(currentWorld(exec), location, jsLocation); return jsLocation; } @@ -101,7 +99,7 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, Document* documen if (!document) return jsNull(); - DOMObject* wrapper = getCachedDOMNodeWrapper(exec, document, document); + JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), document); if (wrapper) return wrapper; diff --git a/Source/WebCore/bindings/js/JSElementCustom.cpp b/Source/WebCore/bindings/js/JSElementCustom.cpp index 9ed3739..4bedf3a 100644 --- a/Source/WebCore/bindings/js/JSElementCustom.cpp +++ b/Source/WebCore/bindings/js/JSElementCustom.cpp @@ -71,7 +71,7 @@ JSValue toJSNewlyCreated(ExecState* exec, JSDOMGlobalObject* globalObject, Eleme if (!element) return jsNull(); - ASSERT(!getCachedDOMNodeWrapper(exec, element->document(), element)); + ASSERT(!getCachedWrapper(currentWorld(exec), element)); JSNode* wrapper; if (element->isHTMLElement()) diff --git a/Source/WebCore/bindings/js/JSEventCustom.cpp b/Source/WebCore/bindings/js/JSEventCustom.cpp index 9e95e74..9763b4b 100644 --- a/Source/WebCore/bindings/js/JSEventCustom.cpp +++ b/Source/WebCore/bindings/js/JSEventCustom.cpp @@ -101,6 +101,8 @@ #if ENABLE(WEB_AUDIO) #include "AudioProcessingEvent.h" #include "JSAudioProcessingEvent.h" +#include "JSOfflineAudioCompletionEvent.h" +#include "OfflineAudioCompletionEvent.h" #endif using namespace JSC; @@ -119,7 +121,7 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, Event* event) if (!event) return jsNull(); - DOMObject* wrapper = getCachedDOMObjectWrapper(exec, event); + JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), event); if (wrapper) return wrapper; @@ -190,6 +192,8 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, Event* event) #if ENABLE(WEB_AUDIO) else if (event->isAudioProcessingEvent()) wrapper = CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, AudioProcessingEvent, event); + else if (event->isOfflineAudioCompletionEvent()) + wrapper = CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, OfflineAudioCompletionEvent, event); #endif #if ENABLE(INPUT_SPEECH) else if (event->isSpeechInputEvent()) diff --git a/Source/WebCore/bindings/js/JSEventListener.cpp b/Source/WebCore/bindings/js/JSEventListener.cpp index e444d88..436251e 100644 --- a/Source/WebCore/bindings/js/JSEventListener.cpp +++ b/Source/WebCore/bindings/js/JSEventListener.cpp @@ -25,6 +25,7 @@ #include "JSEvent.h" #include "JSEventTarget.h" #include "JSMainThreadExecState.h" +#include "WorkerContext.h" #include <runtime/JSLock.h> #include <wtf/RefCountedLeakCounter.h> @@ -38,7 +39,11 @@ JSEventListener::JSEventListener(JSObject* function, JSObject* wrapper, bool isA , m_isAttribute(isAttribute) , m_isolatedWorld(isolatedWorld) { - m_jsFunction.set(*m_isolatedWorld->globalData(), wrapper, function); + if (wrapper) + m_jsFunction.set(*m_isolatedWorld->globalData(), wrapper, function); + else + ASSERT(!function); + } JSEventListener::~JSEventListener() @@ -60,7 +65,7 @@ void JSEventListener::markJSFunction(MarkStack& markStack) void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event) { ASSERT(scriptExecutionContext); - if (!scriptExecutionContext || scriptExecutionContext->isJSExecutionTerminated()) + if (!scriptExecutionContext || scriptExecutionContext->isJSExecutionForbidden()) return; JSLock lock(SilenceAssertionsOnly); @@ -126,6 +131,14 @@ void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext globalObject->setCurrentEvent(savedEvent); +#if ENABLE(WORKERS) + if (scriptExecutionContext->isWorkerContext()) { + bool terminatorCausedException = (exec->hadException() && exec->exception().isObject() && asObject(exec->exception())->exceptionType() == Terminated); + if (terminatorCausedException || globalData.terminator.shouldTerminate()) + static_cast<WorkerContext*>(scriptExecutionContext)->script()->forbidExecution(); + } +#endif + if (exec->hadException()) { event->target()->uncaughtExceptionInEventHandler(); reportCurrentException(exec); diff --git a/Source/WebCore/bindings/js/JSEventListener.h b/Source/WebCore/bindings/js/JSEventListener.h index 0af0f86..a599be7 100644 --- a/Source/WebCore/bindings/js/JSEventListener.h +++ b/Source/WebCore/bindings/js/JSEventListener.h @@ -22,7 +22,7 @@ #include "EventListener.h" #include "JSDOMWindow.h" -#include <runtime/WeakGCPtr.h> +#include <heap/Weak.h> namespace WebCore { @@ -66,7 +66,7 @@ namespace WebCore { private: mutable JSC::WriteBarrier<JSC::JSObject> m_jsFunction; - mutable JSC::WeakGCPtr<JSC::JSObject> m_wrapper; + mutable JSC::Weak<JSC::JSObject> m_wrapper; bool m_isAttribute; RefPtr<DOMWrapperWorld> m_isolatedWorld; diff --git a/Source/WebCore/bindings/js/JSEventTarget.cpp b/Source/WebCore/bindings/js/JSEventTarget.cpp index e4d6724..3ccdd6f 100644 --- a/Source/WebCore/bindings/js/JSEventTarget.cpp +++ b/Source/WebCore/bindings/js/JSEventTarget.cpp @@ -84,6 +84,8 @@ #endif #if ENABLE(WEB_AUDIO) +#include "AudioContext.h" +#include "JSAudioContext.h" #include "JSJavaScriptAudioNode.h" #include "JavaScriptAudioNode.h" #endif @@ -173,6 +175,8 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, EventTarget* targ #if ENABLE(WEB_AUDIO) if (JavaScriptAudioNode* jsAudioNode = target->toJavaScriptAudioNode()) return toJS(exec, globalObject, jsAudioNode); + if (AudioContext* audioContext = target->toAudioContext()) + return toJS(exec, globalObject, audioContext); #endif #if ENABLE(WEB_SOCKETS) diff --git a/Source/WebCore/bindings/js/JSGeolocationCustom.cpp b/Source/WebCore/bindings/js/JSGeolocationCustom.cpp index 248adcf..b93c4ce 100644 --- a/Source/WebCore/bindings/js/JSGeolocationCustom.cpp +++ b/Source/WebCore/bindings/js/JSGeolocationCustom.cpp @@ -28,14 +28,13 @@ #if ENABLE(GEOLOCATION) +#include "CallbackFunction.h" #include "DOMWindow.h" -#include "ExceptionCode.h" #include "Geolocation.h" #include "JSCustomPositionCallback.h" #include "JSCustomPositionErrorCallback.h" #include "JSDOMWindow.h" #include "PositionOptions.h" -#include <runtime/JSFunction.h> #if !ENABLE(CLIENT_BASED_GEOLOCATION) #include "GeolocationService.h" @@ -46,36 +45,6 @@ using namespace std; namespace WebCore { -static PassRefPtr<PositionCallback> createPositionCallback(ExecState* exec, JSDOMGlobalObject* globalObject, JSValue value) -{ - // The spec specifies 'FunctionOnly' for this object. - // FIXME: This check disallows callable objects created via JSC API. It's not clear what exactly the specification intends to allow. - if (!value.inherits(&JSFunction::s_info)) { - setDOMException(exec, TYPE_MISMATCH_ERR); - return 0; - } - - JSObject* object = asObject(value); - return JSCustomPositionCallback::create(object, globalObject); -} - -static PassRefPtr<PositionErrorCallback> createPositionErrorCallback(ExecState* exec, JSDOMGlobalObject* globalObject, JSValue value) -{ - // Argument is optional (hence undefined is allowed), and null is allowed. - if (value.isUndefinedOrNull()) - return 0; - - // The spec specifies 'FunctionOnly' for this object. - // FIXME: This check disallows callable objects created via JSC API. It's not clear what exactly the specification intends to allow. - if (!value.inherits(&JSFunction::s_info)) { - setDOMException(exec, TYPE_MISMATCH_ERR); - return 0; - } - - JSObject* object = asObject(value); - return JSCustomPositionErrorCallback::create(object, globalObject); -} - static PassRefPtr<PositionOptions> createPositionOptions(ExecState* exec, JSValue value) { // Create default options. @@ -144,12 +113,12 @@ JSValue JSGeolocation::getCurrentPosition(ExecState* exec) { // Arguments: PositionCallback, (optional)PositionErrorCallback, (optional)PositionOptions - RefPtr<PositionCallback> positionCallback = createPositionCallback(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), exec->argument(0)); + RefPtr<PositionCallback> positionCallback = createFunctionOnlyCallback<JSCustomPositionCallback>(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), exec->argument(0)); if (exec->hadException()) return jsUndefined(); ASSERT(positionCallback); - RefPtr<PositionErrorCallback> positionErrorCallback = createPositionErrorCallback(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), exec->argument(1)); + RefPtr<PositionErrorCallback> positionErrorCallback = createFunctionOnlyCallback<JSCustomPositionErrorCallback>(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), exec->argument(1), CallbackAllowUndefined | CallbackAllowNull); if (exec->hadException()) return jsUndefined(); @@ -166,12 +135,12 @@ JSValue JSGeolocation::watchPosition(ExecState* exec) { // Arguments: PositionCallback, (optional)PositionErrorCallback, (optional)PositionOptions - RefPtr<PositionCallback> positionCallback = createPositionCallback(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), exec->argument(0)); + RefPtr<PositionCallback> positionCallback = createFunctionOnlyCallback<JSCustomPositionCallback>(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), exec->argument(0)); if (exec->hadException()) return jsUndefined(); ASSERT(positionCallback); - RefPtr<PositionErrorCallback> positionErrorCallback = createPositionErrorCallback(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), exec->argument(1)); + RefPtr<PositionErrorCallback> positionErrorCallback = createFunctionOnlyCallback<JSCustomPositionErrorCallback>(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), exec->argument(1), CallbackAllowUndefined | CallbackAllowNull); if (exec->hadException()) return jsUndefined(); diff --git a/Source/WebCore/bindings/js/JSHTMLCollectionCustom.cpp b/Source/WebCore/bindings/js/JSHTMLCollectionCustom.cpp index 6b2f350..622a15a 100644 --- a/Source/WebCore/bindings/js/JSHTMLCollectionCustom.cpp +++ b/Source/WebCore/bindings/js/JSHTMLCollectionCustom.cpp @@ -134,7 +134,7 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, HTMLCollection* c if (!collection) return jsNull(); - DOMObject* wrapper = getCachedDOMObjectWrapper(exec, collection); + JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), collection); if (wrapper) return wrapper; diff --git a/Source/WebCore/bindings/js/JSHTMLDocumentCustom.cpp b/Source/WebCore/bindings/js/JSHTMLDocumentCustom.cpp index 192ef5d..c33f859 100644 --- a/Source/WebCore/bindings/js/JSHTMLDocumentCustom.cpp +++ b/Source/WebCore/bindings/js/JSHTMLDocumentCustom.cpp @@ -86,7 +86,7 @@ JSValue JSHTMLDocument::nameGetter(ExecState* exec, JSValue slotBase, const Iden JSValue JSHTMLDocument::all(ExecState* exec) const { // If "all" has been overwritten, return the overwritten value - JSValue v = getDirect(Identifier(exec, "all")); + JSValue v = getDirect(exec->globalData(), Identifier(exec, "all")); if (v) return v; diff --git a/Source/WebCore/bindings/js/JSImageConstructor.h b/Source/WebCore/bindings/js/JSImageConstructor.h index 654e223..4ef405d 100644 --- a/Source/WebCore/bindings/js/JSImageConstructor.h +++ b/Source/WebCore/bindings/js/JSImageConstructor.h @@ -29,7 +29,7 @@ namespace WebCore { public: JSImageConstructor(JSC::ExecState*, JSDOMGlobalObject*); - static PassRefPtr<JSC::Structure> createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype) + static JSC::Structure* createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype) { return JSC::Structure::create(globalData, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } diff --git a/Source/WebCore/bindings/js/JSImageDataCustom.cpp b/Source/WebCore/bindings/js/JSImageDataCustom.cpp index a92ed47..fb955b1 100644 --- a/Source/WebCore/bindings/js/JSImageDataCustom.cpp +++ b/Source/WebCore/bindings/js/JSImageDataCustom.cpp @@ -41,15 +41,15 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, ImageData* imageD if (!imageData) return jsNull(); - DOMObject* wrapper = getCachedDOMObjectWrapper(exec, imageData); + JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), imageData); if (wrapper) return wrapper; wrapper = CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, ImageData, imageData); Identifier dataName(exec, "data"); static const ClassInfo cpaClassInfo = { "CanvasPixelArray", &JSByteArray::Base::s_info, 0, 0 }; - DEFINE_STATIC_LOCAL(RefPtr<Structure>, cpaStructure, (JSByteArray::createStructure(exec->globalData(), jsNull(), &cpaClassInfo))); - wrapper->putDirect(exec->globalData(), dataName, new (exec) JSByteArray(exec, cpaStructure, imageData->data()->data()), DontDelete | ReadOnly); + DEFINE_STATIC_LOCAL(Strong<Structure>, cpaStructure, (exec->globalData(), JSByteArray::createStructure(exec->globalData(), jsNull(), &cpaClassInfo))); + wrapper->putDirect(exec->globalData(), dataName, new (exec) JSByteArray(exec, cpaStructure.get(), imageData->data()->data()), DontDelete | ReadOnly); exec->heap()->reportExtraMemoryCost(imageData->data()->length()); return wrapper; diff --git a/Source/WebCore/bindings/js/JSInjectedScriptHostCustom.cpp b/Source/WebCore/bindings/js/JSInjectedScriptHostCustom.cpp index d56251f..2453215 100644 --- a/Source/WebCore/bindings/js/JSInjectedScriptHostCustom.cpp +++ b/Source/WebCore/bindings/js/JSInjectedScriptHostCustom.cpp @@ -70,6 +70,7 @@ Node* InjectedScriptHost::scriptValueAsNode(ScriptValue value) ScriptValue InjectedScriptHost::nodeAsScriptValue(ScriptState* state, Node* node) { + JSLock lock(SilenceAssertionsOnly); return ScriptValue(state->globalData(), toJS(state, node)); } diff --git a/Source/WebCore/bindings/js/JSInjectedScriptManager.cpp b/Source/WebCore/bindings/js/JSInjectedScriptManager.cpp index 1843cd2..b784e6a 100644 --- a/Source/WebCore/bindings/js/JSInjectedScriptManager.cpp +++ b/Source/WebCore/bindings/js/JSInjectedScriptManager.cpp @@ -85,14 +85,14 @@ InjectedScript InjectedScriptManager::injectedScriptFor(ScriptState* scriptState JSDOMGlobalObject* globalObject = static_cast<JSDOMGlobalObject*>(scriptState->lexicalGlobalObject()); JSObject* injectedScript = globalObject->injectedScript(); if (injectedScript) - return InjectedScript(ScriptObject(scriptState, injectedScript)); + return InjectedScript(ScriptObject(scriptState, injectedScript), m_inspectedStateAccessCheck); - if (!canAccessInspectedWindow(scriptState)) + if (!m_inspectedStateAccessCheck(scriptState)) return InjectedScript(); pair<long, ScriptObject> injectedScriptObject = injectScript(injectedScriptSource(), scriptState); globalObject->setInjectedScript(injectedScriptObject.second.jsObject()); - InjectedScript result(injectedScriptObject.second); + InjectedScript result(injectedScriptObject.second, m_inspectedStateAccessCheck); m_idToInjectedScript.set(injectedScriptObject.first, result); return result; } diff --git a/Source/WebCore/bindings/js/JSMessageEventCustom.cpp b/Source/WebCore/bindings/js/JSMessageEventCustom.cpp index b3dabae..9dfc70a 100644 --- a/Source/WebCore/bindings/js/JSMessageEventCustom.cpp +++ b/Source/WebCore/bindings/js/JSMessageEventCustom.cpp @@ -60,6 +60,8 @@ JSC::JSValue JSMessageEvent::initMessageEvent(JSC::ExecState* exec) bool canBubbleArg = exec->argument(1).toBoolean(exec); bool cancelableArg = exec->argument(2).toBoolean(exec); PassRefPtr<SerializedScriptValue> dataArg = SerializedScriptValue::create(exec, exec->argument(3)); + if (exec->hadException()) + return jsUndefined(); const UString& originArg = exec->argument(4).toString(exec); const UString& lastEventIdArg = exec->argument(5).toString(exec); DOMWindow* sourceArg = toDOMWindow(exec->argument(6)); diff --git a/Source/WebCore/bindings/js/JSNamedNodeMapCustom.cpp b/Source/WebCore/bindings/js/JSNamedNodeMapCustom.cpp index 8df9304..9b06767 100644 --- a/Source/WebCore/bindings/js/JSNamedNodeMapCustom.cpp +++ b/Source/WebCore/bindings/js/JSNamedNodeMapCustom.cpp @@ -27,7 +27,6 @@ #include "JSNamedNodeMap.h" #include "JSNode.h" - #include "Element.h" #include "NamedNodeMap.h" @@ -35,6 +34,40 @@ using namespace JSC; namespace WebCore { +class JSNamedNodeMapOwner : public JSC::WeakHandleOwner { + virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::MarkStack&); + virtual void finalize(JSC::Handle<JSC::Unknown>, void* context); +}; + +bool JSNamedNodeMapOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, MarkStack& markStack) +{ + JSNamedNodeMap* jsNamedNodeMap = static_cast<JSNamedNodeMap*>(handle.get().asCell()); + if (!jsNamedNodeMap->hasCustomProperties()) + return false; + Element* element = jsNamedNodeMap->impl()->element(); + if (!element) + return false; + return markStack.containsOpaqueRoot(root(element)); +} + +void JSNamedNodeMapOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context) +{ + JSNamedNodeMap* jsNamedNodeMap = static_cast<JSNamedNodeMap*>(handle.get().asCell()); + DOMWrapperWorld* world = static_cast<DOMWrapperWorld*>(context); + uncacheWrapper(world, jsNamedNodeMap->impl(), jsNamedNodeMap); +} + +inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld*, NamedNodeMap*) +{ + DEFINE_STATIC_LOCAL(JSNamedNodeMapOwner, jsNamedNodeMapOwner, ()); + return &jsNamedNodeMapOwner; +} + +inline void* wrapperContext(DOMWrapperWorld* world, NamedNodeMap*) +{ + return world; +} + bool JSNamedNodeMap::canGetItemsForName(ExecState*, NamedNodeMap* impl, const Identifier& propertyName) { return impl->getNamedItem(identifierToString(propertyName)); @@ -50,10 +83,19 @@ void JSNamedNodeMap::markChildren(MarkStack& markStack) { Base::markChildren(markStack); - // Mark the element so that this will work to access the attribute even if the last - // other reference goes away. - if (Element* element = impl()->element()) - markDOMNodeWrapper(markStack, element->document(), element); + // We need to keep the wrapper for our underlying NamedNodeMap's element + // alive because NamedNodeMap and Attr rely on the element for data, and + // don't know how to keep it alive correctly. + // FIXME: Fix this lifetime issue in the DOM, and remove this. + Element* element = impl()->element(); + if (!element) + return; + markStack.addOpaqueRoot(root(element)); +} + +JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, NamedNodeMap* impl) +{ + return wrap<JSNamedNodeMap>(exec, globalObject, impl); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSNavigatorCustom.cpp b/Source/WebCore/bindings/js/JSNavigatorCustom.cpp index c8429ed..26e93e3 100644 --- a/Source/WebCore/bindings/js/JSNavigatorCustom.cpp +++ b/Source/WebCore/bindings/js/JSNavigatorCustom.cpp @@ -23,7 +23,13 @@ #include "config.h" #include "JSNavigator.h" +<<<<<<< HEAD #include "ExceptionCode.h" +======= +#include "CallbackFunction.h" +#include "JSNavigatorUserMediaErrorCallback.h" +#include "JSNavigatorUserMediaSuccessCallback.h" +>>>>>>> WebKit.org at r84325 #include "Navigator.h" #include <runtime/InternalFunction.h> @@ -44,6 +50,7 @@ void JSNavigator::markChildren(MarkStack& markStack) markDOMObjectWrapper(markStack, globalData, impl()->optionalGeolocation()); } +<<<<<<< HEAD #if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED) JSC::JSValue WebCore::JSNavigator::isApplicationInstalled(JSC::ExecState* exec) @@ -75,5 +82,28 @@ JSC::JSValue WebCore::JSNavigator::isApplicationInstalled(JSC::ExecState* exec) } #endif +======= +#if ENABLE(MEDIA_STREAM) +JSValue JSNavigator::webkitGetUserMedia(ExecState* exec) +{ + // Arguments: Options, successCallback, (optional)errorCallback + + String options = ustringToString(exec->argument(0).toString(exec)); + if (exec->hadException()) + return jsUndefined(); + + RefPtr<NavigatorUserMediaSuccessCallback> successCallback = createFunctionOnlyCallback<JSNavigatorUserMediaSuccessCallback>(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), exec->argument(1)); + if (exec->hadException()) + return jsUndefined(); + + RefPtr<NavigatorUserMediaErrorCallback> errorCallback = createFunctionOnlyCallback<JSNavigatorUserMediaErrorCallback>(exec, static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), exec->argument(2), CallbackAllowUndefined); + if (exec->hadException()) + return jsUndefined(); + + m_impl->webkitGetUserMedia(options, successCallback.release(), errorCallback.release()); + return jsUndefined(); +} +#endif // ENABLE(MEDIA_STREAM) +>>>>>>> WebKit.org at r84325 } diff --git a/Source/WebCore/bindings/js/JSNodeCustom.cpp b/Source/WebCore/bindings/js/JSNodeCustom.cpp index 17f57f4..d305be7 100644 --- a/Source/WebCore/bindings/js/JSNodeCustom.cpp +++ b/Source/WebCore/bindings/js/JSNodeCustom.cpp @@ -35,7 +35,15 @@ #include "Entity.h" #include "EntityReference.h" #include "ExceptionCode.h" +#include "HTMLAudioElement.h" +#include "HTMLCanvasElement.h" #include "HTMLElement.h" +#include "HTMLFrameElementBase.h" +#include "HTMLImageElement.h" +#include "HTMLLinkElement.h" +#include "HTMLNames.h" +#include "HTMLScriptElement.h" +#include "HTMLStyleElement.h" #include "JSAttr.h" #include "JSCDATASection.h" #include "JSComment.h" @@ -55,6 +63,8 @@ #include "Notation.h" #include "ProcessingInstruction.h" #include "RegisteredEventListener.h" +#include "StyleSheet.h" +#include "StyledElement.h" #include "Text.h" #include <wtf/PassRefPtr.h> #include <wtf/RefPtr.h> @@ -68,6 +78,114 @@ using namespace JSC; namespace WebCore { +using namespace HTMLNames; + +static bool isObservable(JSNode* jsNode, Node* node, DOMWrapperWorld* world) +{ + // Certain conditions implicitly make existence of a JS DOM node wrapper observable + // through the DOM, even if no explicit reference to it remains. + + // The DOM doesn't know how to keep a tree of nodes alive without the root + // being explicitly referenced. So, we artificially treat the root of + // every tree as observable. + // FIXME: Resolve this lifetime issue in the DOM, and remove this inefficiency. + if (!node->parentNode()) + return true; + + // If a node is in the document, and its wrapper has custom properties, + // the wrapper is observable because future access to the node through the + // DOM must reflect those properties. + if (jsNode->hasCustomProperties()) + return true; + + // If a node is in the document, and has event listeners, its wrapper is + // observable because its wrapper is responsible for marking those event listeners. + if (node->hasEventListeners()) + return true; + + // If a node owns another object with a wrapper with custom properties, + // the wrapper must be treated as observable, because future access to + // those objects through the DOM must reflect those properties. + // FIXME: It would be better if this logic could be in the node next to + // the custom markChildren functions rather than here. + // Note that for some compound objects like stylesheets and CSSStyleDeclarations, + // we don't descend to check children for custom properties, and just conservatively + // keep the node wrappers protecting them alive. + if (node->isElementNode()) { + if (node->isStyledElement()) { + if (CSSMutableStyleDeclaration* style = static_cast<StyledElement*>(node)->inlineStyleDecl()) { + if (world->m_wrappers.get(style)) + return true; + } + } + if (static_cast<Element*>(node)->hasTagName(canvasTag)) { + if (CanvasRenderingContext* context = static_cast<HTMLCanvasElement*>(node)->renderingContext()) { + if (JSDOMWrapper* wrapper = world->m_wrappers.get(context).get()) { + if (wrapper->hasCustomProperties()) + return true; + } + } + } else if (static_cast<Element*>(node)->hasTagName(linkTag)) { + if (StyleSheet* sheet = static_cast<HTMLLinkElement*>(node)->sheet()) { + if (world->m_wrappers.get(sheet)) + return true; + } + } else if (static_cast<Element*>(node)->hasTagName(styleTag)) { + if (StyleSheet* sheet = static_cast<HTMLStyleElement*>(node)->sheet()) { + if (world->m_wrappers.get(sheet)) + return true; + } + } + } else if (node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE) { + if (StyleSheet* sheet = static_cast<ProcessingInstruction*>(node)->sheet()) { + if (world->m_wrappers.get(sheet)) + return true; + } + } + + return false; +} + +static inline bool isReachableFromDOM(JSNode* jsNode, Node* node, DOMWrapperWorld* world, MarkStack& markStack) +{ + if (!node->inDocument()) { + // If a wrapper is the last reference to an image or script element + // that is loading but not in the document, the wrapper is observable + // because it is the only thing keeping the image element alive, and if + // the image element is destroyed, its load event will not fire. + // FIXME: The DOM should manage this issue without the help of JavaScript wrappers. + if (node->hasTagName(imgTag) && !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent()) + return true; + if (node->hasTagName(scriptTag) && !static_cast<HTMLScriptElement*>(node)->haveFiredLoadEvent()) + return true; + #if ENABLE(VIDEO) + if (node->hasTagName(audioTag) && !static_cast<HTMLAudioElement*>(node)->paused()) + return true; + #endif + + // If a node is firing event listeners, its wrapper is observable because + // its wrapper is responsible for marking those event listeners. + if (node->isFiringEventListeners()) + return true; + } + + return isObservable(jsNode, node, world) && markStack.containsOpaqueRoot(root(node)); +} + +bool JSNodeOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void* context, MarkStack& markStack) +{ + JSNode* jsNode = static_cast<JSNode*>(handle.get().asCell()); + DOMWrapperWorld* world = static_cast<DOMWrapperWorld*>(context); + return isReachableFromDOM(jsNode, jsNode->impl(), world, markStack); +} + +void JSNodeOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context) +{ + JSNode* jsNode = static_cast<JSNode*>(handle.get().asCell()); + DOMWrapperWorld* world = static_cast<DOMWrapperWorld*>(context); + uncacheWrapper(world, jsNode->impl(), jsNode); +} + JSValue JSNode::insertBefore(ExecState* exec) { Node* imp = static_cast<Node*>(impl()); @@ -124,47 +242,13 @@ void JSNode::markChildren(MarkStack& markStack) Node* node = m_impl.get(); node->markJSEventListeners(markStack); - // Nodes in the document are kept alive by JSDocument::mark, so, if we're in - // the document, we need to mark the document, but we don't need to explicitly - // mark any other nodes. - if (node->inDocument()) { - // FIXME: Do we really want to call a virtual function, ownerDocument here, - // when the non-virtual inline function, document, is so much faster?! - if (Document* doc = node->ownerDocument()) - markDOMNodeWrapper(markStack, doc, doc); - return; - } - - // This is a node outside the document. - // Find the the root, and the highest ancestor with a wrapper. - Node* root = node; - Node* outermostNodeWithWrapper = node; - for (Node* current = m_impl.get(); current; current = current->parentNode()) { - root = current; - if (hasCachedDOMNodeWrapperUnchecked(current->document(), current)) - outermostNodeWithWrapper = current; - } - - // Only nodes that have no ancestors with wrappers mark the subtree. In the common - // case, the root of the detached subtree has a wrapper, so the tree will only - // get marked once. Nodes that aren't outermost need to mark the outermost - // in case it is otherwise unreachable. - // FIXME: In the non-common case of root not having a wrapper, this is still an O(n^2) algorithm, - // as we will traverse the whole tree as many times as there are nodes with wrappers in it. - if (node != outermostNodeWithWrapper) { - markDOMNodeWrapper(markStack, m_impl->document(), outermostNodeWithWrapper); - return; - } - - // Mark the whole tree subtree. - for (Node* nodeToMark = root; nodeToMark; nodeToMark = nodeToMark->traverseNextNode()) - markDOMNodeWrapper(markStack, m_impl->document(), nodeToMark); + markStack.addOpaqueRoot(root(node)); } static ALWAYS_INLINE JSValue createWrapperInline(ExecState* exec, JSDOMGlobalObject* globalObject, Node* node) { ASSERT(node); - ASSERT(!getCachedDOMNodeWrapper(exec, node->document(), node)); + ASSERT(!getCachedWrapper(currentWorld(exec), node)); JSNode* wrapper; switch (node->nodeType()) { diff --git a/Source/WebCore/bindings/js/JSNodeCustom.h b/Source/WebCore/bindings/js/JSNodeCustom.h index 9d06ae6..cefa3e3 100644 --- a/Source/WebCore/bindings/js/JSNodeCustom.h +++ b/Source/WebCore/bindings/js/JSNodeCustom.h @@ -31,16 +31,45 @@ namespace WebCore { -inline JSNode* getCachedDOMNodeWrapper(JSC::ExecState* exec, Document* document, Node* node) +class JSNodeOwner : public JSC::WeakHandleOwner { + virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::MarkStack&); + virtual void finalize(JSC::Handle<JSC::Unknown>, void* context); +}; + +inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld*, Node*) +{ + DEFINE_STATIC_LOCAL(JSNodeOwner, jsNodeOwner, ()); + return &jsNodeOwner; +} + +inline void* wrapperContext(DOMWrapperWorld* world, Node*) +{ + return world; +} + +inline JSDOMWrapper* getInlineCachedWrapper(DOMWrapperWorld* world, Node* node) +{ + if (!world->isNormal()) + return 0; + return node->wrapper(); +} + +inline bool setInlineCachedWrapper(DOMWrapperWorld* world, Node* node, JSDOMWrapper* wrapper) { - if (currentWorld(exec)->isNormal()) { - ASSERT(node->wrapper() == (document ? document->getWrapperCache(currentWorld(exec))->get(node) : domObjectWrapperMapFor(exec).get(node))); - return static_cast<JSNode*>(node->wrapper()); - } + if (!world->isNormal()) + return false; + ASSERT(!node->wrapper()); + node->setWrapper(*world->globalData(), wrapper, wrapperOwner(world, node), wrapperContext(world, node)); + return true; +} - if (document) - return document->getWrapperCache(currentWorld(exec))->get(node); - return static_cast<JSNode*>(domObjectWrapperMapFor(exec).get(node)); +inline bool clearInlineCachedWrapper(DOMWrapperWorld* world, Node* node, JSDOMWrapper* wrapper) +{ + if (!world->isNormal()) + return false; + ASSERT_UNUSED(wrapper, node->wrapper() == wrapper); + node->clearWrapper(); + return true; } JSC::JSValue createWrapper(JSC::ExecState*, JSDOMGlobalObject*, Node*); @@ -50,13 +79,23 @@ inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, if (!node) return JSC::jsNull(); - JSNode* wrapper = getCachedDOMNodeWrapper(exec, node->document(), node); + JSNode* wrapper = static_cast<JSNode*>(getCachedWrapper(currentWorld(exec), node)); if (wrapper) return wrapper; return createWrapper(exec, globalObject, node); } +static inline Node* root(Node* node) +{ + if (node->inDocument()) + return node->document(); + + while (node->parentNode()) + node = node->parentNode(); + return node; +} + } #endif // JSDOMNodeCustom_h diff --git a/Source/WebCore/bindings/js/JSNodeFilterCondition.cpp b/Source/WebCore/bindings/js/JSNodeFilterCondition.cpp index 1cf72a5..927b1a3 100644 --- a/Source/WebCore/bindings/js/JSNodeFilterCondition.cpp +++ b/Source/WebCore/bindings/js/JSNodeFilterCondition.cpp @@ -32,21 +32,16 @@ using namespace JSC; ASSERT_CLASS_FITS_IN_CELL(JSNodeFilterCondition); -JSNodeFilterCondition::JSNodeFilterCondition(JSValue filter) - : m_filter(filter) +JSNodeFilterCondition::JSNodeFilterCondition(JSGlobalData& globalData, NodeFilter* owner, JSValue filter) + : m_filter(globalData, filter, &m_weakOwner, owner) { } -void JSNodeFilterCondition::markAggregate(MarkStack& markStack) -{ - markStack.append(&m_filter); -} - short JSNodeFilterCondition::acceptNode(JSC::ExecState* exec, Node* filterNode) const { JSLock lock(SilenceAssertionsOnly); - if (!m_filter->isObject()) + if (!m_filter.isObject()) return NodeFilter::FILTER_ACCEPT; // The exec argument here should only be null if this was called from a @@ -62,7 +57,7 @@ short JSNodeFilterCondition::acceptNode(JSC::ExecState* exec, Node* filterNode) CallData callData; CallType callType = getCallData(function, callData); if (callType == CallTypeNone) { - function = m_filter->get(exec, Identifier(exec, "acceptNode")); + function = m_filter.get().get(exec, Identifier(exec, "acceptNode")); callType = getCallData(function, callData); if (callType == CallTypeNone) { throwError(exec, createTypeError(exec, "NodeFilter object does not have an acceptNode function")); @@ -88,4 +83,9 @@ short JSNodeFilterCondition::acceptNode(JSC::ExecState* exec, Node* filterNode) return intResult; } +bool JSNodeFilterCondition::WeakOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, MarkStack& markStack) +{ + return markStack.containsOpaqueRoot(context); +} + } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSNodeFilterCondition.h b/Source/WebCore/bindings/js/JSNodeFilterCondition.h index 14b0c1d..80148f1 100644 --- a/Source/WebCore/bindings/js/JSNodeFilterCondition.h +++ b/Source/WebCore/bindings/js/JSNodeFilterCondition.h @@ -21,27 +21,32 @@ #define JSNodeFilterCondition_h #include "NodeFilterCondition.h" +#include <heap/Weak.h> #include <runtime/JSValue.h> #include <wtf/PassRefPtr.h> namespace WebCore { class Node; + class NodeFilter; class JSNodeFilterCondition : public NodeFilterCondition { public: - static PassRefPtr<JSNodeFilterCondition> create(JSC::JSValue filter) + static PassRefPtr<JSNodeFilterCondition> create(JSC::JSGlobalData& globalData, NodeFilter* owner, JSC::JSValue filter) { - return adoptRef(new JSNodeFilterCondition(filter)); + return adoptRef(new JSNodeFilterCondition(globalData, owner, filter)); } private: - JSNodeFilterCondition(JSC::JSValue filter); + JSNodeFilterCondition(JSC::JSGlobalData&, NodeFilter* owner, JSC::JSValue filter); virtual short acceptNode(ScriptState*, Node*) const; - virtual void markAggregate(JSC::MarkStack&); - mutable JSC::DeprecatedPtr<JSC::Unknown> m_filter; + class WeakOwner : public JSC::WeakHandleOwner { + virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::MarkStack&); + }; + WeakOwner m_weakOwner; + mutable JSC::Weak<JSC::Unknown> m_filter; }; } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSNodeFilterCustom.cpp b/Source/WebCore/bindings/js/JSNodeFilterCustom.cpp index bc79e99..ad4aa7e 100644 --- a/Source/WebCore/bindings/js/JSNodeFilterCustom.cpp +++ b/Source/WebCore/bindings/js/JSNodeFilterCustom.cpp @@ -39,15 +39,17 @@ namespace WebCore { void JSNodeFilter::markChildren(MarkStack& markStack) { Base::markChildren(markStack); - impl()->markAggregate(markStack); + markStack.addOpaqueRoot(impl()); } -PassRefPtr<NodeFilter> toNodeFilter(JSValue value) +PassRefPtr<NodeFilter> toNodeFilter(JSGlobalData& globalData, JSValue value) { if (value.inherits(&JSNodeFilter::s_info)) return static_cast<JSNodeFilter*>(asObject(value))->impl(); - return NodeFilter::create(JSNodeFilterCondition::create(value)); + RefPtr<NodeFilter> result = NodeFilter::create(); + result->setCondition(JSNodeFilterCondition::create(globalData, result.get(), value)); + return result.release(); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSNodeIteratorCustom.cpp b/Source/WebCore/bindings/js/JSNodeIteratorCustom.cpp index 7c858e5..77f2dc3 100644 --- a/Source/WebCore/bindings/js/JSNodeIteratorCustom.cpp +++ b/Source/WebCore/bindings/js/JSNodeIteratorCustom.cpp @@ -34,7 +34,7 @@ void JSNodeIterator::markChildren(MarkStack& markStack) Base::markChildren(markStack); if (NodeFilter* filter = m_impl->filter()) - filter->markAggregate(markStack); + markStack.addOpaqueRoot(filter); } } diff --git a/Source/WebCore/bindings/js/JSNodeListCustom.cpp b/Source/WebCore/bindings/js/JSNodeListCustom.cpp index c81914c..a52ac64 100644 --- a/Source/WebCore/bindings/js/JSNodeListCustom.cpp +++ b/Source/WebCore/bindings/js/JSNodeListCustom.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "JSNodeList.h" +#include "DynamicNodeList.h" #include "JSNode.h" #include "Node.h" #include "NodeList.h" @@ -35,6 +36,44 @@ using namespace JSC; namespace WebCore { +class JSNodeListOwner : public JSC::WeakHandleOwner { + virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::MarkStack&); + virtual void finalize(JSC::Handle<JSC::Unknown>, void* context); +}; + +bool JSNodeListOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, MarkStack& markStack) +{ + JSNodeList* jsNodeList = static_cast<JSNodeList*>(handle.get().asCell()); + if (!jsNodeList->hasCustomProperties()) + return false; + if (!jsNodeList->impl()->isDynamicNodeList()) + return false; + return markStack.containsOpaqueRoot(root(static_cast<DynamicNodeList*>(jsNodeList->impl())->rootNode())); +} + +void JSNodeListOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context) +{ + JSNodeList* jsNodeList = static_cast<JSNodeList*>(handle.get().asCell()); + DOMWrapperWorld* world = static_cast<DOMWrapperWorld*>(context); + uncacheWrapper(world, jsNodeList->impl(), jsNodeList); +} + +inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld*, NodeList*) +{ + DEFINE_STATIC_LOCAL(JSNodeListOwner, jsNodeListOwner, ()); + return &jsNodeListOwner; +} + +inline void* wrapperContext(DOMWrapperWorld* world, NodeList*) +{ + return world; +} + +JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, NodeList* impl) +{ + return wrap<JSNodeList>(exec, globalObject, impl); +} + // Need to support call so that list(0) works. static EncodedJSValue JSC_HOST_CALL callNodeList(ExecState* exec) { diff --git a/Source/WebCore/bindings/js/JSOptionConstructor.h b/Source/WebCore/bindings/js/JSOptionConstructor.h index 8a18007..3317978 100644 --- a/Source/WebCore/bindings/js/JSOptionConstructor.h +++ b/Source/WebCore/bindings/js/JSOptionConstructor.h @@ -30,7 +30,7 @@ namespace WebCore { public: JSOptionConstructor(JSC::ExecState*, JSDOMGlobalObject*); - static PassRefPtr<JSC::Structure> createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype) + static JSC::Structure* createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype) { return JSC::Structure::create(globalData, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } diff --git a/Source/WebCore/bindings/js/JSSVGElementInstanceCustom.cpp b/Source/WebCore/bindings/js/JSSVGElementInstanceCustom.cpp index dec4be0..defbd5f 100644 --- a/Source/WebCore/bindings/js/JSSVGElementInstanceCustom.cpp +++ b/Source/WebCore/bindings/js/JSSVGElementInstanceCustom.cpp @@ -28,6 +28,7 @@ #include "JSSVGElementInstance.h" #if ENABLE(SVG) +#include "JSNode.h" #include "SVGElementInstance.h" namespace WebCore { @@ -35,9 +36,7 @@ namespace WebCore { void JSSVGElementInstance::markChildren(JSC::MarkStack& markStack) { Base::markChildren(markStack); - - // Mark the wrapper for our corresponding element, so it can mark its event handlers. - markDOMNodeWrapper(markStack, impl()->correspondingElement()->document(), impl()->correspondingElement()); + markStack.addOpaqueRoot(root(impl()->correspondingElement())); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSSVGPathSegCustom.cpp b/Source/WebCore/bindings/js/JSSVGPathSegCustom.cpp index f0aa86b..dc5eadd 100644 --- a/Source/WebCore/bindings/js/JSSVGPathSegCustom.cpp +++ b/Source/WebCore/bindings/js/JSSVGPathSegCustom.cpp @@ -63,7 +63,7 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, SVGPathSeg* objec if (!object) return jsNull(); - if (DOMObject* wrapper = getCachedDOMObjectWrapper(exec, object)) + if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), object)) return wrapper; switch (object->pathSegType()) { diff --git a/Source/WebCore/bindings/js/JSStyleSheetCustom.cpp b/Source/WebCore/bindings/js/JSStyleSheetCustom.cpp index 04c6561..66e5244 100644 --- a/Source/WebCore/bindings/js/JSStyleSheetCustom.cpp +++ b/Source/WebCore/bindings/js/JSStyleSheetCustom.cpp @@ -40,7 +40,7 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, StyleSheet* style if (!styleSheet) return jsNull(); - DOMObject* wrapper = getCachedDOMObjectWrapper(exec, styleSheet); + JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), styleSheet); if (wrapper) return wrapper; diff --git a/Source/WebCore/bindings/js/JSTreeWalkerCustom.cpp b/Source/WebCore/bindings/js/JSTreeWalkerCustom.cpp index 0c1947f..fc64900 100644 --- a/Source/WebCore/bindings/js/JSTreeWalkerCustom.cpp +++ b/Source/WebCore/bindings/js/JSTreeWalkerCustom.cpp @@ -34,7 +34,7 @@ void JSTreeWalker::markChildren(MarkStack& markStack) Base::markChildren(markStack); if (NodeFilter* filter = m_impl->filter()) - filter->markAggregate(markStack); + markStack.addOpaqueRoot(filter); } } diff --git a/Source/WebCore/bindings/js/JSWorkerContextBase.cpp b/Source/WebCore/bindings/js/JSWorkerContextBase.cpp index c6f86b5..cbf01b7 100644 --- a/Source/WebCore/bindings/js/JSWorkerContextBase.cpp +++ b/Source/WebCore/bindings/js/JSWorkerContextBase.cpp @@ -31,6 +31,7 @@ #include "JSWorkerContextBase.h" +#include "DOMWrapperWorld.h" #include "JSDedicatedWorkerContext.h" #include "JSSharedWorkerContext.h" #include "JSWorkerContext.h" @@ -44,8 +45,8 @@ ASSERT_CLASS_FITS_IN_CELL(JSWorkerContextBase); const ClassInfo JSWorkerContextBase::s_info = { "WorkerContext", &JSDOMGlobalObject::s_info, 0, 0 }; -JSWorkerContextBase::JSWorkerContextBase(NonNullPassRefPtr<JSC::Structure> structure, PassRefPtr<WorkerContext> impl) - : JSDOMGlobalObject(structure, normalWorld(*impl->script()->globalData()), this) +JSWorkerContextBase::JSWorkerContextBase(JSC::JSGlobalData& globalData, JSC::Structure* structure, PassRefPtr<WorkerContext> impl) + : JSDOMGlobalObject(globalData, structure, normalWorld(globalData), this) , m_impl(impl) { ASSERT(inherits(&s_info)); diff --git a/Source/WebCore/bindings/js/JSWorkerContextBase.h b/Source/WebCore/bindings/js/JSWorkerContextBase.h index b9c234a..af68b58 100644 --- a/Source/WebCore/bindings/js/JSWorkerContextBase.h +++ b/Source/WebCore/bindings/js/JSWorkerContextBase.h @@ -41,7 +41,7 @@ namespace WebCore { class JSWorkerContextBase : public JSDOMGlobalObject { typedef JSDOMGlobalObject Base; public: - JSWorkerContextBase(NonNullPassRefPtr<JSC::Structure>, PassRefPtr<WorkerContext>); + JSWorkerContextBase(JSC::JSGlobalData&, JSC::Structure*, PassRefPtr<WorkerContext>); virtual ~JSWorkerContextBase(); static const JSC::ClassInfo s_info; @@ -49,7 +49,7 @@ namespace WebCore { WorkerContext* impl() const { return m_impl.get(); } virtual ScriptExecutionContext* scriptExecutionContext() const; - static PassRefPtr<JSC::Structure> createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype) + static JSC::Structure* createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype) { return JSC::Structure::create(globalData, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), AnonymousSlotCount, &s_info); } diff --git a/Source/WebCore/bindings/js/JSWorkerContextCustom.cpp b/Source/WebCore/bindings/js/JSWorkerContextCustom.cpp index 8c1caef..1103d0b 100644 --- a/Source/WebCore/bindings/js/JSWorkerContextCustom.cpp +++ b/Source/WebCore/bindings/js/JSWorkerContextCustom.cpp @@ -122,7 +122,8 @@ JSValue JSWorkerContext::importScripts(ExecState* exec) JSValue JSWorkerContext::setTimeout(ExecState* exec) { - OwnPtr<ScheduledAction> action = ScheduledAction::create(exec, currentWorld(exec)); + // FIXME: Should we enforce a Content-Security-Policy on workers? + OwnPtr<ScheduledAction> action = ScheduledAction::create(exec, currentWorld(exec), 0); if (exec->hadException()) return jsUndefined(); int delay = exec->argument(1).toInt32(exec); @@ -131,7 +132,8 @@ JSValue JSWorkerContext::setTimeout(ExecState* exec) JSValue JSWorkerContext::setInterval(ExecState* exec) { - OwnPtr<ScheduledAction> action = ScheduledAction::create(exec, currentWorld(exec)); + // FIXME: Should we enforce a Content-Security-Policy on workers? + OwnPtr<ScheduledAction> action = ScheduledAction::create(exec, currentWorld(exec), 0); if (exec->hadException()) return jsUndefined(); int delay = exec->argument(1).toInt32(exec); diff --git a/Source/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp b/Source/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp index 1d6f1cb..eba5db7 100644 --- a/Source/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp +++ b/Source/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp @@ -64,10 +64,8 @@ void JSXMLHttpRequest::markChildren(MarkStack& markStack) if (Document* responseDocument = m_impl->optionalResponseXML()) markDOMObjectWrapper(markStack, *Heap::heap(this)->globalData(), responseDocument); -#if ENABLE(WEBGL) || ENABLE(BLOB) if (ArrayBuffer* responseArrayBuffer = m_impl->optionalResponseArrayBuffer()) markDOMObjectWrapper(markStack, *Heap::heap(this)->globalData(), responseArrayBuffer); -#endif #if ENABLE(XHR_RESPONSE_BLOB) if (Blob* responseBlob = m_impl->optionalResponseBlob()) @@ -124,10 +122,8 @@ JSValue JSXMLHttpRequest::send(ExecState* exec) impl()->send(toBlob(val), ec); else if (val.inherits(&JSDOMFormData::s_info)) impl()->send(toDOMFormData(val), ec); -#if ENABLE(WEBGL) || ENABLE(BLOB) else if (val.inherits(&JSArrayBuffer::s_info)) impl()->send(toArrayBuffer(val), ec); -#endif else impl()->send(ustringToString(val.toString(exec)), ec); } @@ -189,7 +185,6 @@ JSValue JSXMLHttpRequest::response(ExecState* exec) const #endif case XMLHttpRequest::ResponseTypeArrayBuffer: -#if ENABLE(WEBGL) || ENABLE(BLOB) { ExceptionCode ec = 0; ArrayBuffer* arrayBuffer = impl()->responseArrayBuffer(ec); @@ -199,9 +194,6 @@ JSValue JSXMLHttpRequest::response(ExecState* exec) const } return toJS(exec, globalObject(), arrayBuffer); } -#else - return jsUndefined(); -#endif } return jsUndefined(); diff --git a/Source/WebCore/bindings/js/ScheduledAction.cpp b/Source/WebCore/bindings/js/ScheduledAction.cpp index f623017..b8a623b 100644 --- a/Source/WebCore/bindings/js/ScheduledAction.cpp +++ b/Source/WebCore/bindings/js/ScheduledAction.cpp @@ -24,6 +24,7 @@ #include "config.h" #include "ScheduledAction.h" +#include "ContentSecurityPolicy.h" #include "DOMWindow.h" #include "Document.h" #include "Frame.h" @@ -46,11 +47,13 @@ using namespace JSC; namespace WebCore { -PassOwnPtr<ScheduledAction> ScheduledAction::create(ExecState* exec, DOMWrapperWorld* isolatedWorld) +PassOwnPtr<ScheduledAction> ScheduledAction::create(ExecState* exec, DOMWrapperWorld* isolatedWorld, ContentSecurityPolicy* policy) { JSValue v = exec->argument(0); CallData callData; if (getCallData(v, callData) == CallTypeNone) { + if (policy && !policy->allowEval()) + return 0; UString string = v.toString(exec); if (exec->hadException()) return 0; @@ -67,7 +70,7 @@ ScheduledAction::ScheduledAction(ExecState* exec, JSValue function, DOMWrapperWo // setTimeout(function, interval, arg0, arg1...). // Start at 2 to skip function and interval. for (size_t i = 2; i < exec->argumentCount(); ++i) - m_args.append(Global<JSC::Unknown>(exec->globalData(), exec->argument(i))); + m_args.append(Strong<JSC::Unknown>(exec->globalData(), exec->argument(i))); } void ScheduledAction::execute(ScriptExecutionContext* context) diff --git a/Source/WebCore/bindings/js/ScheduledAction.h b/Source/WebCore/bindings/js/ScheduledAction.h index 3adc185..1595758 100644 --- a/Source/WebCore/bindings/js/ScheduledAction.h +++ b/Source/WebCore/bindings/js/ScheduledAction.h @@ -22,7 +22,7 @@ #include "JSDOMBinding.h" #include "PlatformString.h" -#include <collector/handles/Global.h> +#include <heap/Strong.h> #include <runtime/JSCell.h> #include <wtf/PassOwnPtr.h> #include <wtf/Vector.h> @@ -34,6 +34,7 @@ namespace JSC { namespace WebCore { class Document; + class ContentSecurityPolicy; class ScriptExecutionContext; class WorkerContext; @@ -44,7 +45,7 @@ namespace WebCore { class ScheduledAction { WTF_MAKE_NONCOPYABLE(ScheduledAction); WTF_MAKE_FAST_ALLOCATED; public: - static PassOwnPtr<ScheduledAction> create(JSC::ExecState*, DOMWrapperWorld* isolatedWorld); + static PassOwnPtr<ScheduledAction> create(JSC::ExecState*, DOMWrapperWorld* isolatedWorld, ContentSecurityPolicy*); void execute(ScriptExecutionContext*); @@ -63,8 +64,8 @@ namespace WebCore { void execute(WorkerContext*); #endif - JSC::Global<JSC::Unknown> m_function; - Vector<JSC::Global<JSC::Unknown> > m_args; + JSC::Strong<JSC::Unknown> m_function; + Vector<JSC::Strong<JSC::Unknown> > m_args; String m_code; RefPtr<DOMWrapperWorld> m_isolatedWorld; }; diff --git a/Source/WebCore/bindings/js/ScriptCachedFrameData.cpp b/Source/WebCore/bindings/js/ScriptCachedFrameData.cpp index 5a467f2..1f0953b 100644 --- a/Source/WebCore/bindings/js/ScriptCachedFrameData.cpp +++ b/Source/WebCore/bindings/js/ScriptCachedFrameData.cpp @@ -54,7 +54,7 @@ ScriptCachedFrameData::ScriptCachedFrameData(Frame* frame) ScriptController::ShellMap::iterator windowShellsEnd = windowShells.end(); for (ScriptController::ShellMap::iterator iter = windowShells.begin(); iter != windowShellsEnd; ++iter) { JSDOMWindow* window = iter->second->window(); - m_windows.add(iter->first.get(), Global<JSDOMWindow>(window->globalData(), window)); + m_windows.add(iter->first.get(), Strong<JSDOMWindow>(window->globalData(), window)); m_domWindow = window->impl(); } diff --git a/Source/WebCore/bindings/js/ScriptCachedFrameData.h b/Source/WebCore/bindings/js/ScriptCachedFrameData.h index 08874d5..a85e16f 100644 --- a/Source/WebCore/bindings/js/ScriptCachedFrameData.h +++ b/Source/WebCore/bindings/js/ScriptCachedFrameData.h @@ -32,7 +32,8 @@ #ifndef ScriptCachedFrameData_h #define ScriptCachedFrameData_h -#include <collector/handles/Global.h> +#include <heap/Strong.h> +#include <wtf/HashMap.h> namespace WebCore { class Frame; @@ -42,7 +43,7 @@ namespace WebCore { class ScriptCachedFrameData { WTF_MAKE_NONCOPYABLE(ScriptCachedFrameData); WTF_MAKE_FAST_ALLOCATED; - typedef HashMap< RefPtr<DOMWrapperWorld>, JSC::Global<JSDOMWindow> > JSDOMWindowSet; + typedef HashMap< RefPtr<DOMWrapperWorld>, JSC::Strong<JSDOMWindow> > JSDOMWindowSet; public: ScriptCachedFrameData(Frame*); diff --git a/Source/WebCore/bindings/js/ScriptController.cpp b/Source/WebCore/bindings/js/ScriptController.cpp index 4b0f44f..45c4faa 100644 --- a/Source/WebCore/bindings/js/ScriptController.cpp +++ b/Source/WebCore/bindings/js/ScriptController.cpp @@ -108,8 +108,8 @@ void ScriptController::destroyWindowShell(DOMWrapperWorld* world) JSDOMWindowShell* ScriptController::createWindowShell(DOMWrapperWorld* world) { ASSERT(!m_windowShells.contains(world)); - Global<JSDOMWindowShell> windowShell(*world->globalData(), new JSDOMWindowShell(m_frame->domWindow(), world)); - Global<JSDOMWindowShell> windowShell2(windowShell); + Strong<JSDOMWindowShell> windowShell(*world->globalData(), new JSDOMWindowShell(m_frame->domWindow(), world)); + Strong<JSDOMWindowShell> windowShell2(windowShell); m_windowShells.add(world, windowShell); world->didCreateWindowShell(this); return windowShell.get(); diff --git a/Source/WebCore/bindings/js/ScriptController.h b/Source/WebCore/bindings/js/ScriptController.h index 2ec3872..7a132b3 100644 --- a/Source/WebCore/bindings/js/ScriptController.h +++ b/Source/WebCore/bindings/js/ScriptController.h @@ -25,7 +25,7 @@ #include "JSDOMWindowShell.h" #include "ScriptControllerBase.h" #include "ScriptInstance.h" -#include <collector/handles/Global.h> +#include <heap/Strong.h> #include <wtf/Forward.h> #include <wtf/RefPtr.h> @@ -64,7 +64,7 @@ typedef HashMap<void*, RefPtr<JSC::Bindings::RootObject> > RootObjectMap; class ScriptController { friend class ScriptCachedFrameData; - typedef WTF::HashMap< RefPtr<DOMWrapperWorld>, JSC::Global<JSDOMWindowShell> > ShellMap; + typedef WTF::HashMap< RefPtr<DOMWrapperWorld>, JSC::Strong<JSDOMWindowShell> > ShellMap; public: ScriptController(Frame*); diff --git a/Source/WebCore/bindings/js/ScriptDebugServer.cpp b/Source/WebCore/bindings/js/ScriptDebugServer.cpp index 05c0f2c..88e685f 100644 --- a/Source/WebCore/bindings/js/ScriptDebugServer.cpp +++ b/Source/WebCore/bindings/js/ScriptDebugServer.cpp @@ -112,7 +112,7 @@ bool ScriptDebugServer::hasBreakpoint(intptr_t sourceID, const TextPosition0& po if (lineNumber <= 0) return false; LineToBreakpointMap::const_iterator breakIt = it->second.find(lineNumber); - if (breakIt == it->second.end() || !breakIt->second.enabled) + if (breakIt == it->second.end()) return false; // An empty condition counts as no condition which is equivalent to "true". @@ -189,7 +189,7 @@ void ScriptDebugServer::stepOutOfFunction() m_doneProcessingDebuggerEvents = true; } -bool ScriptDebugServer::editScriptSource(const String&, const String&, String&) +bool ScriptDebugServer::editScriptSource(const String&, const String&, String*) { // FIXME(40300): implement this. return false; @@ -214,7 +214,7 @@ void ScriptDebugServer::dispatchDidContinue(ScriptDebugListener* listener) listener->didContinue(); } -void ScriptDebugServer::dispatchDidParseSource(const ListenerSet& listeners, SourceProvider* sourceProvider, ScriptWorldType worldType) +void ScriptDebugServer::dispatchDidParseSource(const ListenerSet& listeners, SourceProvider* sourceProvider, bool isContentScript) { String sourceID = ustringToString(JSC::UString::number(sourceProvider->asID())); String url = ustringToString(sourceProvider->url()); @@ -225,7 +225,7 @@ void ScriptDebugServer::dispatchDidParseSource(const ListenerSet& listeners, Sou Vector<ScriptDebugListener*> copy; copyToVector(listeners, copy); for (size_t i = 0; i < copy.size(); ++i) - copy[i]->didParseSource(sourceID, url, data, lineOffset, columnOffset, worldType); + copy[i]->didParseSource(sourceID, url, data, lineOffset, columnOffset, isContentScript); } void ScriptDebugServer::dispatchFailedToParseSource(const ListenerSet& listeners, SourceProvider* sourceProvider, int errorLine, const String& errorMessage) @@ -240,11 +240,9 @@ void ScriptDebugServer::dispatchFailedToParseSource(const ListenerSet& listeners copy[i]->failedToParseSource(url, data, firstLine, errorLine, errorMessage); } -static ScriptWorldType currentWorldType(ExecState* exec) +static bool isContentScript(ExecState* exec) { - if (currentWorld(exec) == mainThreadNormalWorld()) - return MAIN_WORLD; - return EXTENSIONS_WORLD; + return currentWorld(exec) != mainThreadNormalWorld(); } void ScriptDebugServer::detach(JSGlobalObject* globalObject) @@ -275,10 +273,8 @@ void ScriptDebugServer::sourceParsed(ExecState* exec, SourceProvider* sourceProv bool isError = errorLine != -1; if (isError) dispatchFailedToParseSource(*listeners, sourceProvider, errorLine, ustringToString(errorMessage)); - else { - ScriptWorldType worldType = currentWorldType(exec); - dispatchDidParseSource(*listeners, sourceProvider, worldType); - } + else + dispatchDidParseSource(*listeners, sourceProvider, isContentScript(exec)); m_callingListeners = false; } diff --git a/Source/WebCore/bindings/js/ScriptDebugServer.h b/Source/WebCore/bindings/js/ScriptDebugServer.h index e53cb4d..f6ac9a1 100644 --- a/Source/WebCore/bindings/js/ScriptDebugServer.h +++ b/Source/WebCore/bindings/js/ScriptDebugServer.h @@ -78,7 +78,7 @@ public: void stepOverStatement(); void stepOutOfFunction(); - bool editScriptSource(const String& sourceID, const String& newContent, String& newSourceOrErrorMessage); + bool editScriptSource(const String& sourceID, const String& newContent, String* error); void recompileAllJSFunctionsSoon(); virtual void recompileAllJSFunctions(Timer<ScriptDebugServer>* = 0) = 0; @@ -102,7 +102,7 @@ protected: void dispatchFunctionToListeners(const ListenerSet& listeners, JavaScriptExecutionCallback callback); void dispatchDidPause(ScriptDebugListener*); void dispatchDidContinue(ScriptDebugListener*); - void dispatchDidParseSource(const ListenerSet& listeners, JSC::SourceProvider*, enum ScriptWorldType); + void dispatchDidParseSource(const ListenerSet& listeners, JSC::SourceProvider*, bool isContentScript); void dispatchFailedToParseSource(const ListenerSet& listeners, JSC::SourceProvider*, int errorLine, const String& errorMessage); void createCallFrameAndPauseIfNeeded(const JSC::DebuggerCallFrame&, intptr_t sourceID, int lineNumber); diff --git a/Source/WebCore/bindings/js/ScriptGCEvent.cpp b/Source/WebCore/bindings/js/ScriptGCEvent.cpp index dd027b4..b694c7c 100644 --- a/Source/WebCore/bindings/js/ScriptGCEvent.cpp +++ b/Source/WebCore/bindings/js/ScriptGCEvent.cpp @@ -34,7 +34,7 @@ #if ENABLE(INSPECTOR) #include "JSDOMWindow.h" -#include <runtime/Heap.h> +#include <heap/Heap.h> #include <runtime/JSGlobalData.h> #include <wtf/CurrentTime.h> diff --git a/Source/WebCore/bindings/js/ScriptObject.h b/Source/WebCore/bindings/js/ScriptObject.h index c10bf18..eb02e9b 100644 --- a/Source/WebCore/bindings/js/ScriptObject.h +++ b/Source/WebCore/bindings/js/ScriptObject.h @@ -34,7 +34,7 @@ #include "ScriptState.h" #include "ScriptValue.h" -#include <collector/handles/Global.h> +#include <heap/Strong.h> #include <runtime/JSObject.h> namespace WebCore { diff --git a/Source/WebCore/bindings/js/ScriptState.cpp b/Source/WebCore/bindings/js/ScriptState.cpp index 8a7c9a5..a4b9793 100644 --- a/Source/WebCore/bindings/js/ScriptState.cpp +++ b/Source/WebCore/bindings/js/ScriptState.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Google Inc. All rights reserved. + * Copyright (C) 2009, 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,8 +33,11 @@ #include "Frame.h" #include "JSDOMWindowBase.h" +#include "JSWorkerContext.h" #include "Node.h" #include "Page.h" +#include "WorkerContext.h" +#include "WorkerScriptController.h" #include <interpreter/CallFrame.h> #include <runtime/JSGlobalObject.h> @@ -83,4 +86,11 @@ ScriptState* scriptStateFromPage(DOMWrapperWorld* world, Page* page) return page->mainFrame()->script()->globalObject(world)->globalExec(); } +#if ENABLE(WORKERS) +ScriptState* scriptStateFromWorkerContext(WorkerContext* workerContext) +{ + return workerContext->script()->workerContextWrapper()->globalExec(); +} +#endif + } diff --git a/Source/WebCore/bindings/js/ScriptState.h b/Source/WebCore/bindings/js/ScriptState.h index f27b306..cdc3fbf 100644 --- a/Source/WebCore/bindings/js/ScriptState.h +++ b/Source/WebCore/bindings/js/ScriptState.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Google Inc. + * Copyright (c) 2008, 2011 Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,7 +32,7 @@ #ifndef ScriptState_h #define ScriptState_h -#include <collector/handles/Global.h> +#include <heap/Strong.h> #include <wtf/Noncopyable.h> namespace JSC { @@ -45,6 +45,7 @@ class DOMWrapperWorld; class Frame; class Node; class Page; +class WorkerContext; // The idea is to expose "state-like" methods (hadException, and any other // methods where ExecState just dips into globalData) of JSC::ExecState as a @@ -59,7 +60,7 @@ public: ~ScriptStateProtectedPtr(); ScriptState* get() const; private: - JSC::Global<JSC::JSGlobalObject> m_globalObject; + JSC::Strong<JSC::JSGlobalObject> m_globalObject; }; ScriptState* mainWorldScriptState(Frame*); @@ -67,6 +68,10 @@ ScriptState* mainWorldScriptState(Frame*); ScriptState* scriptStateFromNode(DOMWrapperWorld*, Node*); ScriptState* scriptStateFromPage(DOMWrapperWorld*, Page*); +#if ENABLE(WORKERS) +ScriptState* scriptStateFromWorkerContext(WorkerContext*); +#endif + } // namespace WebCore #endif // ScriptState_h diff --git a/Source/WebCore/bindings/js/ScriptValue.cpp b/Source/WebCore/bindings/js/ScriptValue.cpp index 6fe6ea3..4f51ddb 100644 --- a/Source/WebCore/bindings/js/ScriptValue.cpp +++ b/Source/WebCore/bindings/js/ScriptValue.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * 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 @@ -35,7 +36,7 @@ #include <JavaScriptCore/APICast.h> #include <JavaScriptCore/JSValueRef.h> -#include <collector/handles/Global.h> +#include <heap/Strong.h> #include <runtime/JSLock.h> #include <runtime/UString.h> @@ -55,6 +56,15 @@ bool ScriptValue::getString(ScriptState* scriptState, String& result) const return true; } +String ScriptValue::toString(ScriptState* scriptState) const +{ + String result = ustringToString(m_value.get().toString(scriptState)); + // Handle the case where an exception is thrown as part of invoking toString on the object. + if (scriptState->hadException()) + scriptState->clearException(); + return result; +} + bool ScriptValue::isEqual(ScriptState* scriptState, const ScriptValue& anotherValue) const { if (hasNoValue()) @@ -90,14 +100,14 @@ bool ScriptValue::isFunction() const return getCallData(m_value.get(), callData) != CallTypeNone; } -PassRefPtr<SerializedScriptValue> ScriptValue::serialize(ScriptState* scriptState) +PassRefPtr<SerializedScriptValue> ScriptValue::serialize(ScriptState* scriptState, SerializationErrorMode throwExceptions) { - return SerializedScriptValue::create(scriptState, jsValue()); + return SerializedScriptValue::create(scriptState, jsValue(), throwExceptions); } -ScriptValue ScriptValue::deserialize(ScriptState* scriptState, SerializedScriptValue* value) +ScriptValue ScriptValue::deserialize(ScriptState* scriptState, SerializedScriptValue* value, SerializationErrorMode throwExceptions) { - return ScriptValue(scriptState->globalData(), value->deserialize(scriptState, scriptState->lexicalGlobalObject())); + return ScriptValue(scriptState->globalData(), value->deserialize(scriptState, scriptState->lexicalGlobalObject(), throwExceptions)); } #if ENABLE(INSPECTOR) diff --git a/Source/WebCore/bindings/js/ScriptValue.h b/Source/WebCore/bindings/js/ScriptValue.h index 37cf243..fade830 100644 --- a/Source/WebCore/bindings/js/ScriptValue.h +++ b/Source/WebCore/bindings/js/ScriptValue.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, Google Inc. All rights reserved. + * Copyright (c) 2008, 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,8 +33,9 @@ #include "JSDOMBinding.h" #include "PlatformString.h" +#include "SerializedScriptValue.h" #include "ScriptState.h" -#include <collector/handles/Global.h> +#include <heap/Strong.h> #include <runtime/JSValue.h> #include <wtf/PassRefPtr.h> @@ -45,24 +46,24 @@ class SerializedScriptValue; class ScriptValue { public: - ScriptValue() : m_value(JSC::Global<JSC::Unknown>::EmptyValue) { } + ScriptValue() { } ScriptValue(JSC::JSGlobalData& globalData, JSC::JSValue value) : m_value(globalData, value) {} virtual ~ScriptValue() {} JSC::JSValue jsValue() const { return m_value.get(); } bool getString(ScriptState*, String& result) const; - String toString(ScriptState* scriptState) const { return ustringToString(m_value.get().toString(scriptState)); } + String toString(ScriptState*) const; bool isEqual(ScriptState*, const ScriptValue&) const; bool isNull() const; bool isUndefined() const; bool isObject() const; bool isFunction() const; - bool hasNoValue() const { return m_value.isEmpty(); } + bool hasNoValue() const { return !m_value; } bool operator==(const ScriptValue& other) const { return m_value == other.m_value; } - PassRefPtr<SerializedScriptValue> serialize(ScriptState*); - static ScriptValue deserialize(ScriptState*, SerializedScriptValue*); + PassRefPtr<SerializedScriptValue> serialize(ScriptState*, SerializationErrorMode = Throwing); + static ScriptValue deserialize(ScriptState*, SerializedScriptValue*, SerializationErrorMode = Throwing); static ScriptValue undefined(); @@ -71,7 +72,7 @@ public: #endif private: - JSC::Global<JSC::Unknown> m_value; + JSC::Strong<JSC::Unknown> m_value; }; } // namespace WebCore diff --git a/Source/WebCore/bindings/js/ScriptWrappable.h b/Source/WebCore/bindings/js/ScriptWrappable.h index 0fbe9e4..4fef506 100644 --- a/Source/WebCore/bindings/js/ScriptWrappable.h +++ b/Source/WebCore/bindings/js/ScriptWrappable.h @@ -32,28 +32,29 @@ #define ScriptWrappable_h #include "JSDOMWrapper.h" -#include <runtime/WeakGCPtr.h> +#include <heap/Weak.h> namespace WebCore { class ScriptWrappable { public: - ScriptWrappable() + JSDOMWrapper* wrapper() const { + return m_wrapper.get(); } - DOMObject* wrapper() const + void setWrapper(JSC::JSGlobalData& globalData, JSDOMWrapper* wrapper, JSC::WeakHandleOwner* wrapperOwner, void* context) { - return m_wrapper.get(); + m_wrapper.set(globalData, wrapper, wrapperOwner, context); } - void setWrapper(JSC::JSGlobalData& globalData, DOMObject* wrapper) + void clearWrapper() { - m_wrapper.set(globalData, wrapper, 0); + m_wrapper.clear(); } private: - JSC::WeakGCPtr<DOMObject> m_wrapper; + JSC::Weak<JSDOMWrapper> m_wrapper; }; } // namespace WebCore diff --git a/Source/WebCore/bindings/js/SerializedScriptValue.cpp b/Source/WebCore/bindings/js/SerializedScriptValue.cpp index a9c1b24..bbe0ca4 100644 --- a/Source/WebCore/bindings/js/SerializedScriptValue.cpp +++ b/Source/WebCore/bindings/js/SerializedScriptValue.cpp @@ -36,6 +36,7 @@ #include "JSFile.h" #include "JSFileList.h" #include "JSImageData.h" +#include "JSNavigator.h" #include "SharedBuffer.h" #include <limits> #include <JavaScriptCore/APICast.h> @@ -160,6 +161,8 @@ static const unsigned int StringPoolTag = 0xFFFFFFFE; * RegExpTag <pattern:StringData><flags:StringData> */ +typedef pair<JSC::JSValue, SerializationReturnCode> DeserializationResult; + class CloneBase { protected: CloneBase(ExecState* exec) @@ -247,7 +250,7 @@ template <typename T> static bool writeLittleEndian(Vector<uint8_t>& buffer, con class CloneSerializer : CloneBase { public: - static bool serialize(ExecState* exec, JSValue value, Vector<uint8_t>& out) + static SerializationReturnCode serialize(ExecState* exec, JSValue value, Vector<uint8_t>& out) { CloneSerializer serializer(exec, out); return serializer.serialize(value); @@ -274,7 +277,7 @@ private: write(CurrentVersion); } - bool serialize(JSValue in); + SerializationReturnCode serialize(JSValue in); bool isArray(JSValue value) { @@ -414,6 +417,13 @@ private: if (isArray(value)) return false; + + // Object cannot be serialized because the act of walking the object creates new objects + if (value.isObject() && asObject(value)->inherits(&JSNavigator::s_info)) { + fail(); + write(NullTag); + return true; + } if (value.isObject()) { JSObject* obj = asObject(value); @@ -598,7 +608,7 @@ private: Identifier m_emptyIdentifier; }; -bool CloneSerializer::serialize(JSValue in) +SerializationReturnCode CloneSerializer::serialize(JSValue in) { Vector<uint32_t, 16> indexStack; Vector<uint32_t, 16> lengthStack; @@ -614,10 +624,8 @@ bool CloneSerializer::serialize(JSValue in) arrayStartState: case ArrayStartState: { ASSERT(isArray(inValue)); - if (inputObjectStack.size() + inputArrayStack.size() > maximumFilterRecursion) { - throwStackOverflow(); - return false; - } + if (inputObjectStack.size() + inputArrayStack.size() > maximumFilterRecursion) + return StackOverflowError; JSArray* inArray = asArray(inValue); unsigned length = inArray->length(); @@ -631,10 +639,8 @@ bool CloneSerializer::serialize(JSValue in) arrayStartVisitMember: case ArrayStartVisitMember: { if (!--tickCount) { - if (didTimeOut()) { - throwInterruptedException(); - return false; - } + if (didTimeOut()) + return InterruptedExecutionError; tickCount = ticksUntilNextCheck(); } @@ -673,10 +679,8 @@ bool CloneSerializer::serialize(JSValue in) objectStartState: case ObjectStartState: { ASSERT(inValue.isObject()); - if (inputObjectStack.size() + inputArrayStack.size() > maximumFilterRecursion) { - throwStackOverflow(); - return false; - } + if (inputObjectStack.size() + inputArrayStack.size() > maximumFilterRecursion) + return StackOverflowError; JSObject* inObject = asObject(inValue); if (!startObject(inObject)) break; @@ -689,10 +693,8 @@ bool CloneSerializer::serialize(JSValue in) objectStartVisitMember: case ObjectStartVisitMember: { if (!--tickCount) { - if (didTimeOut()) { - throwInterruptedException(); - return false; - } + if (didTimeOut()) + return InterruptedExecutionError; tickCount = ticksUntilNextCheck(); } @@ -708,7 +710,7 @@ bool CloneSerializer::serialize(JSValue in) } inValue = getProperty(object, properties[index]); if (shouldTerminate()) - return false; + return ExistingExceptionError; if (!inValue) { // Property was removed during serialisation @@ -718,7 +720,7 @@ bool CloneSerializer::serialize(JSValue in) write(properties[index]); if (shouldTerminate()) - return false; + return ExistingExceptionError; if (!dumpIfTerminal(inValue)) { stateStack.append(ObjectEndVisitMember); @@ -728,7 +730,7 @@ bool CloneSerializer::serialize(JSValue in) } case ObjectEndVisitMember: { if (shouldTerminate()) - return false; + return ExistingExceptionError; indexStack.last()++; goto objectStartVisitMember; @@ -749,17 +751,15 @@ bool CloneSerializer::serialize(JSValue in) stateStack.removeLast(); if (!--tickCount) { - if (didTimeOut()) { - throwInterruptedException(); - return false; - } + if (didTimeOut()) + return InterruptedExecutionError; tickCount = ticksUntilNextCheck(); } } if (m_failed) - return false; + return UnspecifiedError; - return true; + return SuccessfullyCompleted; } class CloneDeserializer : CloneBase { @@ -783,15 +783,13 @@ public: return String(str.impl()); } - static JSValue deserialize(ExecState* exec, JSGlobalObject* globalObject, const Vector<uint8_t>& buffer) + static DeserializationResult deserialize(ExecState* exec, JSGlobalObject* globalObject, const Vector<uint8_t>& buffer) { if (!buffer.size()) - return jsNull(); + return make_pair(jsNull(), UnspecifiedError); CloneDeserializer deserializer(exec, globalObject, buffer); - if (!deserializer.isValid()) { - deserializer.throwValidationError(); - return JSValue(); - } + if (!deserializer.isValid()) + return make_pair(JSValue(), ValidationError); return deserializer.deserialize(); } @@ -846,7 +844,7 @@ private: m_version = 0xFFFFFFFF; } - JSValue deserialize(); + DeserializationResult deserialize(); void throwValidationError() { @@ -1193,7 +1191,7 @@ private: Vector<CachedString> m_constantPool; }; -JSValue CloneDeserializer::deserialize() +DeserializationResult CloneDeserializer::deserialize() { Vector<uint32_t, 16> indexStack; Vector<Identifier, 16> propertyNameStack; @@ -1222,10 +1220,8 @@ JSValue CloneDeserializer::deserialize() arrayStartVisitMember: case ArrayStartVisitMember: { if (!--tickCount) { - if (didTimeOut()) { - throwInterruptedException(); - return JSValue(); - } + if (didTimeOut()) + return make_pair(JSValue(), InterruptedExecutionError); tickCount = ticksUntilNextCheck(); } @@ -1259,10 +1255,8 @@ JSValue CloneDeserializer::deserialize() } objectStartState: case ObjectStartState: { - if (outputObjectStack.size() + outputArrayStack.size() > maximumFilterRecursion) { - throwStackOverflow(); - return JSValue(); - } + if (outputObjectStack.size() + outputArrayStack.size() > maximumFilterRecursion) + return make_pair(JSValue(), StackOverflowError); JSObject* outObject = constructEmptyObject(m_exec, m_globalObject); m_gcBuffer.append(outObject); outputObjectStack.append(outObject); @@ -1271,10 +1265,8 @@ JSValue CloneDeserializer::deserialize() objectStartVisitMember: case ObjectStartVisitMember: { if (!--tickCount) { - if (didTimeOut()) { - throwInterruptedException(); - return JSValue(); - } + if (didTimeOut()) + return make_pair(JSValue(), InterruptedExecutionError); tickCount = ticksUntilNextCheck(); } @@ -1322,20 +1314,17 @@ JSValue CloneDeserializer::deserialize() stateStack.removeLast(); if (!--tickCount) { - if (didTimeOut()) { - throwInterruptedException(); - return JSValue(); - } + if (didTimeOut()) + return make_pair(JSValue(), InterruptedExecutionError); tickCount = ticksUntilNextCheck(); } } ASSERT(outValue); ASSERT(!m_failed); - return outValue; + return make_pair(outValue, SuccessfullyCompleted); error: fail(); - throwValidationError(); - return JSValue(); + return make_pair(JSValue(), ValidationError); } @@ -1349,11 +1338,16 @@ SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer) m_data.swap(buffer); } -PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(ExecState* exec, JSValue value) +PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(ExecState* exec, JSValue value, SerializationErrorMode throwExceptions) { Vector<uint8_t> buffer; - if (!CloneSerializer::serialize(exec, value, buffer)) + SerializationReturnCode code = CloneSerializer::serialize(exec, value, buffer); + if (throwExceptions == Throwing) + maybeThrowExceptionIfSerializationFailed(exec, code); + + if (!serializationDidCompleteSuccessfully(code)) return 0; + return adoptRef(new SerializedScriptValue(buffer)); } @@ -1392,9 +1386,12 @@ String SerializedScriptValue::toString() return CloneDeserializer::deserializeString(m_data); } -JSValue SerializedScriptValue::deserialize(ExecState* exec, JSGlobalObject* globalObject) +JSValue SerializedScriptValue::deserialize(ExecState* exec, JSGlobalObject* globalObject, SerializationErrorMode throwExceptions) { - return CloneDeserializer::deserialize(exec, globalObject, m_data); + DeserializationResult result = CloneDeserializer::deserialize(exec, globalObject, m_data); + if (throwExceptions == Throwing) + maybeThrowExceptionIfSerializationFailed(exec, result.second); + return result.first; } JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, JSValueRef* exception) @@ -1418,4 +1415,33 @@ SerializedScriptValue* SerializedScriptValue::nullValue() return emptyValue.get(); } +void SerializedScriptValue::maybeThrowExceptionIfSerializationFailed(ExecState* exec, SerializationReturnCode code) +{ + if (code == SuccessfullyCompleted) + return; + + switch (code) { + case StackOverflowError: + throwError(exec, createStackOverflowError(exec)); + break; + case InterruptedExecutionError: + throwError(exec, createInterruptedExecutionException(&exec->globalData())); + break; + case ValidationError: + throwError(exec, createTypeError(exec, "Unable to deserialize data.")); + break; + case ExistingExceptionError: + break; + case UnspecifiedError: + break; + default: + ASSERT_NOT_REACHED(); + } +} + +bool SerializedScriptValue::serializationDidCompleteSuccessfully(SerializationReturnCode code) +{ + return (code == SuccessfullyCompleted); +} + } diff --git a/Source/WebCore/bindings/js/SerializedScriptValue.h b/Source/WebCore/bindings/js/SerializedScriptValue.h index 94bc477..0e7fed0 100644 --- a/Source/WebCore/bindings/js/SerializedScriptValue.h +++ b/Source/WebCore/bindings/js/SerializedScriptValue.h @@ -27,19 +27,34 @@ #ifndef SerializedScriptValue_h #define SerializedScriptValue_h -#include "ScriptValue.h" +#include <heap/Strong.h> +#include <runtime/JSValue.h> #include <wtf/Forward.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> typedef const struct OpaqueJSContext* JSContextRef; typedef const struct OpaqueJSValue* JSValueRef; namespace WebCore { + +enum SerializationReturnCode { + SuccessfullyCompleted, + StackOverflowError, + InterruptedExecutionError, + ValidationError, + ExistingExceptionError, + UnspecifiedError +}; + +enum SerializationErrorMode { NonThrowing, Throwing }; + class SharedBuffer; class SerializedScriptValue : public RefCounted<SerializedScriptValue> { public: - static PassRefPtr<SerializedScriptValue> create(JSC::ExecState* exec, JSC::JSValue value); + static PassRefPtr<SerializedScriptValue> create(JSC::ExecState*, JSC::JSValue, SerializationErrorMode = Throwing); static PassRefPtr<SerializedScriptValue> create(JSContextRef, JSValueRef value, JSValueRef* exception); static PassRefPtr<SerializedScriptValue> create(String string); static PassRefPtr<SerializedScriptValue> adopt(Vector<uint8_t>& buffer) @@ -50,14 +65,19 @@ public: static PassRefPtr<SerializedScriptValue> create(); static SerializedScriptValue* nullValue(); - JSC::JSValue deserialize(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject); String toString(); + + JSC::JSValue deserialize(JSC::ExecState*, JSC::JSGlobalObject*, SerializationErrorMode = Throwing); JSValueRef deserialize(JSContextRef, JSValueRef* exception); + const Vector<uint8_t>& data() { return m_data; } ~SerializedScriptValue(); private: + static void maybeThrowExceptionIfSerializationFailed(JSC::ExecState*, SerializationReturnCode); + static bool serializationDidCompleteSuccessfully(SerializationReturnCode); + SerializedScriptValue(Vector<unsigned char>&); Vector<unsigned char> m_data; }; diff --git a/Source/WebCore/bindings/js/WorkerScriptController.cpp b/Source/WebCore/bindings/js/WorkerScriptController.cpp index 67b0441..1f29dfc 100644 --- a/Source/WebCore/bindings/js/WorkerScriptController.cpp +++ b/Source/WebCore/bindings/js/WorkerScriptController.cpp @@ -61,6 +61,7 @@ WorkerScriptController::WorkerScriptController(WorkerContext* workerContext) WorkerScriptController::~WorkerScriptController() { m_workerContextWrapper.clear(); // Unprotect the global object. + m_globalData->clearBuiltinStructures(); m_globalData->heap.destroy(); } @@ -73,25 +74,25 @@ void WorkerScriptController::initScript() // Explicitly protect the global object's prototype so it isn't collected // when we allocate the global object. (Once the global object is fully // constructed, it can mark its own prototype.) - RefPtr<Structure> workerContextPrototypeStructure = JSWorkerContextPrototype::createStructure(*m_globalData, jsNull()); - Global<JSWorkerContextPrototype> workerContextPrototype(*m_globalData, new (m_globalData.get()) JSWorkerContextPrototype(0, workerContextPrototypeStructure.release())); + Structure* workerContextPrototypeStructure = JSWorkerContextPrototype::createStructure(*m_globalData, jsNull()); + Strong<JSWorkerContextPrototype> workerContextPrototype(*m_globalData, new (m_globalData.get()) JSWorkerContextPrototype(*m_globalData, 0, workerContextPrototypeStructure)); if (m_workerContext->isDedicatedWorkerContext()) { - RefPtr<Structure> dedicatedContextPrototypeStructure = JSDedicatedWorkerContextPrototype::createStructure(*m_globalData, workerContextPrototype.get()); - Global<JSDedicatedWorkerContextPrototype> dedicatedContextPrototype(*m_globalData, new (m_globalData.get()) JSDedicatedWorkerContextPrototype(0, dedicatedContextPrototypeStructure.release())); - RefPtr<Structure> structure = JSDedicatedWorkerContext::createStructure(*m_globalData, dedicatedContextPrototype.get()); + Structure* dedicatedContextPrototypeStructure = JSDedicatedWorkerContextPrototype::createStructure(*m_globalData, workerContextPrototype.get()); + Strong<JSDedicatedWorkerContextPrototype> dedicatedContextPrototype(*m_globalData, new (m_globalData.get()) JSDedicatedWorkerContextPrototype(*m_globalData, 0, dedicatedContextPrototypeStructure)); + Structure* structure = JSDedicatedWorkerContext::createStructure(*m_globalData, dedicatedContextPrototype.get()); - m_workerContextWrapper.set(*m_globalData, new (m_globalData.get()) JSDedicatedWorkerContext(structure.release(), m_workerContext->toDedicatedWorkerContext())); + m_workerContextWrapper.set(*m_globalData, new (m_globalData.get()) JSDedicatedWorkerContext(*m_globalData, structure, m_workerContext->toDedicatedWorkerContext())); workerContextPrototype->putAnonymousValue(*m_globalData, 0, m_workerContextWrapper.get()); dedicatedContextPrototype->putAnonymousValue(*m_globalData, 0, m_workerContextWrapper.get()); #if ENABLE(SHARED_WORKERS) } else { ASSERT(m_workerContext->isSharedWorkerContext()); - RefPtr<Structure> sharedContextPrototypeStructure = JSSharedWorkerContextPrototype::createStructure(*m_globalData, workerContextPrototype.get()); - Global<JSSharedWorkerContextPrototype> sharedContextPrototype(*m_globalData, new (m_globalData.get()) JSSharedWorkerContextPrototype(0, sharedContextPrototypeStructure.release())); - RefPtr<Structure> structure = JSSharedWorkerContext::createStructure(*m_globalData, sharedContextPrototype.get()); + Structure* sharedContextPrototypeStructure = JSSharedWorkerContextPrototype::createStructure(*m_globalData, workerContextPrototype.get()); + Strong<JSSharedWorkerContextPrototype> sharedContextPrototype(*m_globalData, new (m_globalData.get()) JSSharedWorkerContextPrototype(*m_globalData, 0, sharedContextPrototypeStructure)); + Structure* structure = JSSharedWorkerContext::createStructure(*m_globalData, sharedContextPrototype.get()); - m_workerContextWrapper.set(*m_globalData, new (m_globalData.get()) JSSharedWorkerContext(structure.release(), m_workerContext->toSharedWorkerContext())); + m_workerContextWrapper.set(*m_globalData, new (m_globalData.get()) JSSharedWorkerContext(*m_globalData, structure, m_workerContext->toSharedWorkerContext())); workerContextPrototype->putAnonymousValue(*m_globalData, 0, m_workerContextWrapper.get()); sharedContextPrototype->putAnonymousValue(*m_globalData, 0, m_workerContextWrapper.get()); #endif @@ -100,11 +101,9 @@ void WorkerScriptController::initScript() ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode) { - { - MutexLocker lock(m_sharedDataMutex); - if (m_executionForbidden) - return ScriptValue(); - } + if (isExecutionForbidden()) + return ScriptValue(); + ScriptValue exception; ScriptValue result(evaluate(sourceCode, &exception)); if (exception.jsValue()) { @@ -116,11 +115,8 @@ ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode) ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, ScriptValue* exception) { - { - MutexLocker lock(m_sharedDataMutex); - if (m_executionForbidden) - return ScriptValue(); - } + if (isExecutionForbidden()) + return ScriptValue(); initScriptIfNeeded(); JSLock lock(SilenceAssertionsOnly); @@ -130,10 +126,18 @@ ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, Completion comp = JSC::evaluate(exec, exec->dynamicGlobalObject()->globalScopeChain(), sourceCode.jsSourceCode(), m_workerContextWrapper.get()); m_workerContextWrapper->globalData().timeoutChecker.stop(); - if (comp.complType() == Normal || comp.complType() == ReturnValue) + + ComplType completionType = comp.complType(); + + if (completionType == Terminated || m_workerContextWrapper->globalData().terminator.shouldTerminate()) { + forbidExecution(); + return ScriptValue(); + } + + if (completionType == Normal || completionType == ReturnValue) return ScriptValue(*m_globalData, comp.value()); - if (comp.complType() == Throw) { + if (completionType == Throw) { String errorMessage; int lineNumber = 0; String sourceURL = sourceCode.url().string(); @@ -150,16 +154,21 @@ void WorkerScriptController::setException(ScriptValue exception) throwError(m_workerContextWrapper->globalExec(), exception.jsValue()); } -void WorkerScriptController::forbidExecution(ForbidExecutionOption option) +void WorkerScriptController::scheduleExecutionTermination() { - // This function may be called from another thread. - // Mutex protection for m_executionForbidden is needed to guarantee that the value is synchronized between processors, because - // if it were not, the worker could re-enter JSC::evaluate(), but with timeout already reset. - // It is not critical for Terminator::m_shouldTerminate to be synchronized, we just rely on it reaching the worker thread's processor sooner or later. - MutexLocker lock(m_sharedDataMutex); + m_globalData->terminator.terminateSoon(); +} + +void WorkerScriptController::forbidExecution() +{ + ASSERT(m_workerContext->isContextThread()); m_executionForbidden = true; - if (option == TerminateRunningScript) - m_globalData->terminator.terminateSoon(); +} + +bool WorkerScriptController::isExecutionForbidden() const +{ + ASSERT(m_workerContext->isContextThread()); + return m_executionForbidden; } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/WorkerScriptController.h b/Source/WebCore/bindings/js/WorkerScriptController.h index c3b8215..0e52988 100644 --- a/Source/WebCore/bindings/js/WorkerScriptController.h +++ b/Source/WebCore/bindings/js/WorkerScriptController.h @@ -29,7 +29,7 @@ #if ENABLE(WORKERS) -#include <collector/handles/Global.h> +#include <heap/Strong.h> #include <wtf/Forward.h> #include <wtf/Threading.h> @@ -61,9 +61,17 @@ namespace WebCore { void setException(ScriptValue); - enum ForbidExecutionOption { TerminateRunningScript, LetRunningScriptFinish }; - void forbidExecution(ForbidExecutionOption); - bool isExecutionForbidden() const { return m_executionForbidden; } + // Async request to terminate a JS run execution. Eventually causes termination + // exception raised during JS execution, if the worker thread happens to run JS. + // After JS execution was terminated in this way, the Worker thread has to use + // forbidExecution()/isExecutionForbidden() to guard against reentry into JS. + // Can be called from any thread. + void scheduleExecutionTermination(); + + // Called on Worker thread when JS exits with termination exception caused by forbidExecution() request, + // or by Worker thread termination code to prevent future entry into JS. + void forbidExecution(); + bool isExecutionForbidden() const; JSC::JSGlobalData* globalData() { return m_globalData.get(); } @@ -77,9 +85,7 @@ namespace WebCore { RefPtr<JSC::JSGlobalData> m_globalData; WorkerContext* m_workerContext; - JSC::Global<JSWorkerContext> m_workerContextWrapper; - - Mutex m_sharedDataMutex; + JSC::Strong<JSWorkerContext> m_workerContextWrapper; bool m_executionForbidden; }; diff --git a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm b/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm index 12b477b..181fd24 100644 --- a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm +++ b/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm @@ -200,7 +200,7 @@ sub GetParentClassName my $dataNode = shift; return $dataNode->extendedAttributes->{"LegacyParent"} if $dataNode->extendedAttributes->{"LegacyParent"}; - return "DOMObjectWithGlobalPointer" if (@{$dataNode->parents} eq 0); + return "JSDOMWrapperWithGlobalPointer" if (@{$dataNode->parents} eq 0); return "JS" . $codeGenerator->StripModule($dataNode->parents(0)); } @@ -682,11 +682,11 @@ sub GenerateHeader # Constructor if ($interfaceName eq "DOMWindow") { - push(@headerContent, " $className(NonNullPassRefPtr<JSC::Structure>, PassRefPtr<$implType>, JSDOMWindowShell*);\n"); + push(@headerContent, " $className(JSC::JSGlobalData&, JSC::Structure*, PassRefPtr<$implType>, JSDOMWindowShell*);\n"); } elsif ($dataNode->extendedAttributes->{"IsWorkerContext"}) { - push(@headerContent, " $className(NonNullPassRefPtr<JSC::Structure>, PassRefPtr<$implType>);\n"); + push(@headerContent, " $className(JSC::JSGlobalData&, JSC::Structure*, PassRefPtr<$implType>);\n"); } else { - push(@headerContent, " $className(NonNullPassRefPtr<JSC::Structure>, JSDOMGlobalObject*, PassRefPtr<$implType>);\n"); + push(@headerContent, " $className(JSC::Structure*, JSDOMGlobalObject*, PassRefPtr<$implType>);\n"); } # Prototype @@ -746,7 +746,7 @@ sub GenerateHeader $structureFlags{"JSC::NeedsThisConversion"} = 1; } push(@headerContent, - " static PassRefPtr<JSC::Structure> createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype)\n" . + " static JSC::Structure* createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype)\n" . " {\n" . " return JSC::Structure::create(globalData, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), AnonymousSlotCount, &s_info);\n" . " }\n\n"); @@ -923,7 +923,7 @@ sub GenerateHeader } if (!$hasParent || $dataNode->extendedAttributes->{"GenerateNativeConverter"}) { if ($interfaceName eq "NodeFilter") { - push(@headerContent, "PassRefPtr<NodeFilter> toNodeFilter(JSC::JSValue);\n"); + push(@headerContent, "PassRefPtr<NodeFilter> toNodeFilter(JSC::JSGlobalData&, JSC::JSValue);\n"); } else { push(@headerContent, "$implType* to${interfaceName}(JSC::JSValue);\n"); } @@ -958,7 +958,7 @@ sub GenerateHeader $structureFlags{"JSC::OverridesMarkChildren"} = 1; } push(@headerContent, - " static PassRefPtr<JSC::Structure> createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype)\n" . + " static JSC::Structure* createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype)\n" . " {\n" . " return JSC::Structure::create(globalData, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), AnonymousSlotCount, &s_info);\n" . " }\n"); @@ -970,7 +970,7 @@ sub GenerateHeader # Custom defineGetter function push(@headerContent, " virtual void defineGetter(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSObject* getterFunction, unsigned attributes);\n") if $dataNode->extendedAttributes->{"CustomPrototypeDefineGetter"}; - push(@headerContent, " ${className}Prototype(JSC::JSGlobalObject* globalObject, NonNullPassRefPtr<JSC::Structure> structure) : JSC::JSObjectWithGlobalObject(globalObject, structure) { }\n"); + push(@headerContent, " ${className}Prototype(JSC::JSGlobalData& globalData, JSC::JSGlobalObject* globalObject, JSC::Structure* structure) : JSC::JSObjectWithGlobalObject(globalData, globalObject, structure) { }\n"); # structure flags push(@headerContent, "protected:\n"); @@ -1304,7 +1304,7 @@ sub GenerateImplementation push(@implContent, "static const HashTable* get${className}PrototypeTable(ExecState* exec)\n"); push(@implContent, "{\n"); push(@implContent, " return getHashTableForGlobalData(exec->globalData(), &${className}PrototypeTable);\n"); - push(@implContent, "}\n"); + push(@implContent, "}\n\n"); push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleClassName}Prototype\", &JSC::JSObjectWithGlobalObject::s_info, 0, get${className}PrototypeTable };\n\n"); } else { push(@implContent, "const ClassInfo ${className}Prototype::s_info = { \"${visibleClassName}Prototype\", &JSC::JSObjectWithGlobalObject::s_info, &${className}PrototypeTable, 0 };\n\n"); @@ -1379,7 +1379,7 @@ sub GenerateImplementation push(@implContent, "static const HashTable* get${className}Table(ExecState* exec)\n"); push(@implContent, "{\n"); push(@implContent, " return getHashTableForGlobalData(exec->globalData(), &${className}Table);\n"); - push(@implContent, "}\n"); + push(@implContent, "}\n\n"); } push(@implContent, "const ClassInfo $className" . "::s_info = { \"${visibleClassName}\", &" . $parentClassName . "::s_info, "); @@ -1407,14 +1407,14 @@ sub GenerateImplementation # Constructor if ($interfaceName eq "DOMWindow") { AddIncludesForType("JSDOMWindowShell"); - push(@implContent, "${className}::$className(NonNullPassRefPtr<Structure> structure, PassRefPtr<$implType> impl, JSDOMWindowShell* shell)\n"); - push(@implContent, " : $parentClassName(structure, impl, shell)\n"); + push(@implContent, "${className}::$className(JSGlobalData& globalData, Structure* structure, PassRefPtr<$implType> impl, JSDOMWindowShell* shell)\n"); + push(@implContent, " : $parentClassName(globalData, structure, impl, shell)\n"); } elsif ($dataNode->extendedAttributes->{"IsWorkerContext"}) { AddIncludesForType($interfaceName); - push(@implContent, "${className}::$className(NonNullPassRefPtr<Structure> structure, PassRefPtr<$implType> impl)\n"); - push(@implContent, " : $parentClassName(structure, impl)\n"); + push(@implContent, "${className}::$className(JSGlobalData& globalData, Structure* structure, PassRefPtr<$implType> impl)\n"); + push(@implContent, " : $parentClassName(globalData, structure, impl)\n"); } else { - push(@implContent, "${className}::$className(NonNullPassRefPtr<Structure> structure, JSDOMGlobalObject* globalObject, PassRefPtr<$implType> impl)\n"); + push(@implContent, "${className}::$className(Structure* structure, JSDOMGlobalObject* globalObject, PassRefPtr<$implType> impl)\n"); if ($hasParent) { push(@implContent, " : $parentClassName(structure, globalObject, impl)\n"); } else { @@ -1442,9 +1442,9 @@ sub GenerateImplementation push(@implContent, "JSObject* ${className}::createPrototype(ExecState* exec, JSGlobalObject* globalObject)\n"); push(@implContent, "{\n"); if ($hasParent && $parentClassName ne "JSC::DOMNodeFilter") { - push(@implContent, " return new (exec) ${className}Prototype(globalObject, ${className}Prototype::createStructure(exec->globalData(), ${parentClassName}Prototype::self(exec, globalObject)));\n"); + push(@implContent, " return new (exec) ${className}Prototype(exec->globalData(), globalObject, ${className}Prototype::createStructure(exec->globalData(), ${parentClassName}Prototype::self(exec, globalObject)));\n"); } else { - push(@implContent, " return new (exec) ${className}Prototype(globalObject, ${className}Prototype::createStructure(globalObject->globalData(), globalObject->objectPrototype()));\n"); + push(@implContent, " return new (exec) ${className}Prototype(exec->globalData(), globalObject, ${className}Prototype::createStructure(globalObject->globalData(), globalObject->objectPrototype()));\n"); } push(@implContent, "}\n\n"); } @@ -1540,7 +1540,7 @@ sub GenerateImplementation my $constructorType = $codeGenerator->StripModule($attribute->signature->type); $constructorType =~ s/Constructor$//; # Constructor attribute is only used by DOMWindow.idl, so it's correct to pass castedThis as the global object - # Once DOMObjects have a back-pointer to the globalObject we can pass castedThis->globalObject() + # Once JSDOMWrappers have a back-pointer to the globalObject we can pass castedThis->globalObject() push(@implContent, " return JS" . $constructorType . "::getConstructor(exec, castedThis);\n"); } elsif (!@{$attribute->getterExceptions}) { push(@implContent, " UNUSED_PARAM(exec);\n"); @@ -1590,7 +1590,7 @@ sub GenerateImplementation push(@implContent, " return result;\n"); } - push(@implContent, "}\n"); + push(@implContent, "}\n\n"); push(@implContent, "#endif\n") if $attributeConditionalString; @@ -1610,8 +1610,7 @@ sub GenerateImplementation } push(@implContent, " return ${className}::getConstructor(exec, domObject->globalObject());\n"); - push(@implContent, "}\n"); - push(@implContent, "\n"); + push(@implContent, "}\n\n"); } } @@ -1769,7 +1768,7 @@ sub GenerateImplementation } } - push(@implContent, "}\n"); + push(@implContent, "}\n\n"); push(@implContent, "#endif\n") if $attributeConditionalString; @@ -1799,8 +1798,7 @@ sub GenerateImplementation } else { push(@implContent, " static_cast<$className*>(thisObject)->putDirect(exec->globalData(), Identifier(exec, \"$name\"), value);\n"); } - push(@implContent, "}\n"); - push(@implContent, "\n"); + push(@implContent, "}\n\n"); } } } @@ -2095,7 +2093,7 @@ sub GenerateImplementation } else { push(@implContent, " return toJS(exec, thisObj->globalObject(), static_cast<$implClassName*>(thisObj->impl())->item(index));\n"); } - push(@implContent, "}\n"); + push(@implContent, "}\n\n"); if ($interfaceName eq "HTMLCollection" or $interfaceName eq "HTMLAllCollection") { $implIncludes{"JSNode.h"} = 1; $implIncludes{"Node.h"} = 1; @@ -2106,7 +2104,7 @@ sub GenerateImplementation push(@implContent, "\nJSValue ${className}::getByIndex(ExecState*, unsigned index)\n"); push(@implContent, "{\n"); push(@implContent, " return jsNumber(static_cast<$implClassName*>(impl())->item(index));\n"); - push(@implContent, "}\n"); + push(@implContent, "}\n\n"); if ($interfaceName eq "HTMLCollection" or $interfaceName eq "HTMLAllCollection") { $implIncludes{"JSNode.h"} = 1; $implIncludes{"Node.h"} = 1; @@ -2115,17 +2113,17 @@ sub GenerateImplementation if ((!$hasParent or $dataNode->extendedAttributes->{"GenerateToJS"}) and !$dataNode->extendedAttributes->{"CustomToJS"}) { if ($svgPropertyType) { - push(@implContent, "JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, $implType* object)\n"); + push(@implContent, "JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, $implType* impl)\n"); } else { - push(@implContent, "JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, $implType* object)\n"); + push(@implContent, "JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, $implType* impl)\n"); } push(@implContent, "{\n"); if ($svgPropertyType) { - push(@implContent, " return getDOMObjectWrapper<$className, $implType>(exec, globalObject, object);\n"); + push(@implContent, " return wrap<$className, $implType>(exec, globalObject, impl);\n"); } else { - push(@implContent, " return getDOMObjectWrapper<$className>(exec, globalObject, object);\n"); + push(@implContent, " return wrap<$className>(exec, globalObject, impl);\n"); } - push(@implContent, "}\n"); + push(@implContent, "}\n\n"); } if ((!$hasParent or $dataNode->extendedAttributes->{"GenerateNativeConverter"}) and !$dataNode->extendedAttributes->{"CustomNativeConverter"}) { @@ -2466,6 +2464,11 @@ sub JSValueToNative return "exec->globalData(), $value"; } + if ($type eq "NodeFilter") { + $implIncludes{"JS$type.h"} = 1; + return "to$type(exec->globalData(), $value)"; + } + if ($type eq "MediaQueryListListener") { $implIncludes{"MediaQueryListListener.h"} = 1; return "MediaQueryListListener::create(ScriptValue(exec->globalData(), " . $value ."))"; @@ -2514,7 +2517,6 @@ sub NativeToJSValue } if ($codeGenerator->IsPrimitiveType($type) or $type eq "DOMTimeStamp") { - $implIncludes{"<runtime/JSNumberCell.h>"} = 1; return "jsNumber($value)"; } @@ -2873,7 +2875,7 @@ sub GenerateConstructorDeclaration push(@$outputArray, " virtual bool getOwnPropertyDescriptor(JSC::ExecState*, const JSC::Identifier&, JSC::PropertyDescriptor&);\n"); push(@$outputArray, " static const JSC::ClassInfo s_info;\n"); - push(@$outputArray, " static PassRefPtr<JSC::Structure> createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype)\n"); + push(@$outputArray, " static JSC::Structure* createStructure(JSC::JSGlobalData& globalData, JSC::JSValue prototype)\n"); push(@$outputArray, " {\n"); push(@$outputArray, " return JSC::Structure::create(globalData, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), AnonymousSlotCount, &s_info);\n"); push(@$outputArray, " }\n"); @@ -2920,12 +2922,12 @@ sub GenerateConstructorDefinition push(@$outputArray, "bool ${constructorClassName}::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)\n"); push(@$outputArray, "{\n"); - push(@$outputArray, " return getStaticValueSlot<${constructorClassName}, DOMObject>(exec, &${constructorClassName}Table, this, propertyName, slot);\n"); + push(@$outputArray, " return getStaticValueSlot<${constructorClassName}, JSDOMWrapper>(exec, &${constructorClassName}Table, this, propertyName, slot);\n"); push(@$outputArray, "}\n\n"); push(@$outputArray, "bool ${constructorClassName}::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)\n"); push(@$outputArray, "{\n"); - push(@$outputArray, " return getStaticValueDescriptor<${constructorClassName}, DOMObject>(exec, &${constructorClassName}Table, this, propertyName, descriptor);\n"); + push(@$outputArray, " return getStaticValueDescriptor<${constructorClassName}, JSDOMWrapper>(exec, &${constructorClassName}Table, this, propertyName, descriptor);\n"); push(@$outputArray, "}\n\n"); if ($canConstruct) { diff --git a/Source/WebCore/bindings/scripts/CodeGeneratorV8.pm b/Source/WebCore/bindings/scripts/CodeGeneratorV8.pm index 6fc0b9a..22051bf 100644 --- a/Source/WebCore/bindings/scripts/CodeGeneratorV8.pm +++ b/Source/WebCore/bindings/scripts/CodeGeneratorV8.pm @@ -448,9 +448,7 @@ sub GetInternalFields push(@customInternalFields, "eventListenerCacheIndex"); } - if (IsSubType($dataNode, "Document")) { - push(@customInternalFields, "implementationIndex"); - } elsif ($name eq "DOMWindow") { + if ($name eq "DOMWindow") { push(@customInternalFields, "enteredIsolatedWorldIndex"); } return @customInternalFields; @@ -2348,6 +2346,7 @@ sub GenerateCallbackImplementation push(@implFixedHeader, GenerateImplementationContentHeader($dataNode)); $implIncludes{"ScriptExecutionContext.h"} = 1; + $implIncludes{"V8Binding.h"} = 1; $implIncludes{"V8CustomVoidCallback.h"} = 1; $implIncludes{"V8Proxy.h"} = 1; @@ -2553,6 +2552,7 @@ sub HasCustomToV8Implementation { return 0 if $interfaceName eq "AbstractWorker"; return 0 if $interfaceName eq "CanvasRenderingContext"; return 0 if $interfaceName eq "SVGElementInstance"; + return 0 if $interfaceName eq "NodeList"; # For everything else, do what JSC does. return $dataNode->extendedAttributes->{"CustomToJS"}; diff --git a/Source/WebCore/bindings/scripts/test/V8/V8TestCallback.cpp b/Source/WebCore/bindings/scripts/test/V8/V8TestCallback.cpp index c17f73d..b0a4f69 100644 --- a/Source/WebCore/bindings/scripts/test/V8/V8TestCallback.cpp +++ b/Source/WebCore/bindings/scripts/test/V8/V8TestCallback.cpp @@ -24,6 +24,7 @@ #if ENABLE(DATABASE) #include "ScriptExecutionContext.h" +#include "V8Binding.h" #include "V8Class1.h" #include "V8Class2.h" #include "V8CustomVoidCallback.h" diff --git a/Source/WebCore/bindings/v8/DebuggerScript.js b/Source/WebCore/bindings/v8/DebuggerScript.js index fe6e8ab..c6540d7 100644 --- a/Source/WebCore/bindings/v8/DebuggerScript.js +++ b/Source/WebCore/bindings/v8/DebuggerScript.js @@ -38,11 +38,6 @@ DebuggerScript.PauseOnExceptionsState = { PauseOnUncaughtExceptions: 2 }; -DebuggerScript.ScriptWorldType = { - MainWorld : 0, - ExtensionsWorld : 1 -}; - DebuggerScript._pauseOnExceptionsState = DebuggerScript.PauseOnExceptionsState.DontPauseOnExceptions; Debug.clearBreakOnException(); Debug.clearBreakOnUncaughtException(); @@ -52,6 +47,21 @@ DebuggerScript.getAfterCompileScript = function(eventData) return DebuggerScript._formatScript(eventData.script_.script_); } +DebuggerScript.getWorkerScripts = function() +{ + var result = []; + var scripts = Debug.scripts(); + for (var i = 0; i < scripts.length; ++i) { + var script = scripts[i]; + // Workers don't share same V8 heap now so there is no need to complicate stuff with + // the context id like we do to discriminate between scripts from different pages. + // However we need to filter out v8 native scripts. + if (script.context_data && script.context_data === "worker") + result.push(DebuggerScript._formatScript(script)); + } + return result; +} + DebuggerScript.getScripts = function(contextData) { var result = []; @@ -76,24 +86,19 @@ DebuggerScript.getScripts = function(contextData) DebuggerScript._formatScript = function(script) { - var scriptWorldType = DebuggerScript.ScriptWorldType.MainWorld; - if (script.context_data && script.context_data.indexOf("injected") == 0) - scriptWorldType = DebuggerScript.ScriptWorldType.ExtensionsWorld; return { id: script.id, name: script.nameOrSourceURL(), source: script.source, lineOffset: script.line_offset, columnOffset: script.column_offset, - scriptWorldType: scriptWorldType + isContentScript: !!script.context_data && script.context_data.indexOf("injected") == 0 }; } DebuggerScript.setBreakpoint = function(execState, args) { - var breakId = Debug.setScriptBreakPointById(args.scriptId, args.lineNumber, args.columnNumber, args.condition); - if (!args.enabled) - Debug.disableScriptBreakPoint(breakId); + var breakId = Debug.setScriptBreakPointById(args.sourceID, args.lineNumber, args.columnNumber, args.condition); var locations = Debug.findBreakPointActualLocations(breakId); if (!locations.length) @@ -252,7 +257,6 @@ DebuggerScript._frameMirrorToJSCallFrame = function(frameMirror, callerFrame) "line": location.line, "column": location.column, "functionName": functionName, - "type": "function", "thisObject": thisObject, "scopeChain": scopeChain, "scopeType": scopeType, diff --git a/Source/WebCore/bindings/v8/ScriptDebugServer.cpp b/Source/WebCore/bindings/v8/ScriptDebugServer.cpp index 5758639..a0e14f3 100644 --- a/Source/WebCore/bindings/v8/ScriptDebugServer.cpp +++ b/Source/WebCore/bindings/v8/ScriptDebugServer.cpp @@ -67,11 +67,10 @@ String ScriptDebugServer::setBreakpoint(const String& sourceID, const ScriptBrea v8::Context::Scope contextScope(debuggerContext); v8::Local<v8::Object> args = v8::Object::New(); - args->Set(v8::String::New("scriptId"), v8String(sourceID)); + args->Set(v8::String::New("sourceID"), v8String(sourceID)); args->Set(v8::String::New("lineNumber"), v8::Integer::New(scriptBreakpoint.lineNumber)); args->Set(v8::String::New("columnNumber"), v8::Integer::New(scriptBreakpoint.columnNumber)); args->Set(v8::String::New("condition"), v8String(scriptBreakpoint.condition)); - args->Set(v8::String::New("enabled"), v8::Boolean::New(scriptBreakpoint.enabled)); v8::Handle<v8::Function> setBreakpointFunction = v8::Local<v8::Function>::Cast(m_debuggerScript.get()->Get(v8::String::New("setBreakpoint"))); v8::Handle<v8::Value> breakpointId = v8::Debug::Call(setBreakpointFunction, args); @@ -212,7 +211,7 @@ void ScriptDebugServer::stepOutOfFunction() continueProgram(); } -bool ScriptDebugServer::editScriptSource(const String& sourceID, const String& newContent, String& newSourceOrErrorMessage) +bool ScriptDebugServer::editScriptSource(const String& sourceID, const String& newContent, String* error) { ensureDebuggerScriptCompiled(); v8::HandleScope scope; @@ -230,11 +229,12 @@ bool ScriptDebugServer::editScriptSource(const String& sourceID, const String& n if (tryCatch.HasCaught()) { v8::Local<v8::Message> message = tryCatch.Message(); if (!message.IsEmpty()) - newSourceOrErrorMessage = toWebCoreStringWithNullOrUndefinedCheck(message->Get()); + *error = toWebCoreStringWithNullOrUndefinedCheck(message->Get()); + else + *error = "Unknown error."; return false; } ASSERT(!result.IsEmpty()); - newSourceOrErrorMessage = toWebCoreStringWithNullOrUndefinedCheck(result); // Call stack may have changed after if the edited function was on the stack. if (m_currentCallFrame) @@ -351,7 +351,7 @@ void ScriptDebugServer::dispatchDidParseSource(ScriptDebugListener* listener, v8 toWebCoreStringWithNullOrUndefinedCheck(object->Get(v8::String::New("source"))), object->Get(v8::String::New("lineOffset"))->ToInteger()->Value(), object->Get(v8::String::New("columnOffset"))->ToInteger()->Value(), - static_cast<ScriptWorldType>(object->Get(v8::String::New("scriptWorldType"))->Int32Value())); + object->Get(v8::String::New("isContentScript"))->ToBoolean()->Value()); } void ScriptDebugServer::ensureDebuggerScriptCompiled() diff --git a/Source/WebCore/bindings/v8/ScriptDebugServer.h b/Source/WebCore/bindings/v8/ScriptDebugServer.h index 15004ea..93d897c 100644 --- a/Source/WebCore/bindings/v8/ScriptDebugServer.h +++ b/Source/WebCore/bindings/v8/ScriptDebugServer.h @@ -72,7 +72,7 @@ public: void stepOverStatement(); void stepOutOfFunction(); - bool editScriptSource(const String& sourceID, const String& newContent, String& newSourceOrErrorMessage); + bool editScriptSource(const String& sourceID, const String& newContent, String* error); void recompileAllJSFunctionsSoon() { } void recompileAllJSFunctions(Timer<ScriptDebugServer>* = 0) { } diff --git a/Source/WebCore/bindings/v8/ScriptState.cpp b/Source/WebCore/bindings/v8/ScriptState.cpp index fac1d26..600a92a 100644 --- a/Source/WebCore/bindings/v8/ScriptState.cpp +++ b/Source/WebCore/bindings/v8/ScriptState.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Google Inc. All rights reserved. + * Copyright (C) 2009, 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 @@ -37,6 +37,10 @@ #include "ScriptController.h" #include "V8HiddenPropertyName.h" +#include "WorkerContext.h" +#include "WorkerContextExecutionProxy.h" +#include "WorkerScriptController.h" + #include <v8.h> #include <wtf/Assertions.h> @@ -111,4 +115,17 @@ ScriptState* scriptStateFromPage(DOMWrapperWorld*, Page* page) return mainWorldScriptState(page->mainFrame()); } +#if ENABLE(WORKERS) +ScriptState* scriptStateFromWorkerContext(WorkerContext* workerContext) +{ + WorkerContextExecutionProxy* proxy = workerContext->script()->proxy(); + if (!proxy) + return 0; + + v8::HandleScope handleScope; + v8::Local<v8::Context> context = proxy->context(); + return ScriptState::forContext(context); +} +#endif + } diff --git a/Source/WebCore/bindings/v8/ScriptState.h b/Source/WebCore/bindings/v8/ScriptState.h index 0fecee8..c7dbbb2 100644 --- a/Source/WebCore/bindings/v8/ScriptState.h +++ b/Source/WebCore/bindings/v8/ScriptState.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009 Google Inc. All rights reserved. + * Copyright (C) 2008, 2009, 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 @@ -41,6 +41,7 @@ class DOMWrapperWorld; class Frame; class Node; class Page; +class WorkerContext; class ScriptState { WTF_MAKE_NONCOPYABLE(ScriptState); @@ -108,6 +109,10 @@ ScriptState* mainWorldScriptState(Frame*); ScriptState* scriptStateFromNode(DOMWrapperWorld*, Node*); ScriptState* scriptStateFromPage(DOMWrapperWorld*, Page*); +#if ENABLE(WORKERS) +ScriptState* scriptStateFromWorkerContext(WorkerContext*); +#endif + inline DOMWrapperWorld* debuggerWorld() { return mainThreadNormalWorld(); } inline DOMWrapperWorld* pluginWorld() { return mainThreadNormalWorld(); } diff --git a/Source/WebCore/bindings/v8/ScriptValue.cpp b/Source/WebCore/bindings/v8/ScriptValue.cpp index ebe9ccc..3487d39 100644 --- a/Source/WebCore/bindings/v8/ScriptValue.cpp +++ b/Source/WebCore/bindings/v8/ScriptValue.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009 Google Inc. All rights reserved. + * Copyright (C) 2008, 2009, 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 @@ -64,7 +64,12 @@ bool ScriptValue::getString(String& result) const String ScriptValue::toString(ScriptState*) const { - return toWebCoreString(m_value); + v8::TryCatch block; + v8::Handle<v8::String> s = m_value->ToString(); + // Handle the case where an exception is thrown as part of invoking toString on the object. + if (block.HasCaught()) + return String(); + return v8StringToWebCoreString<String>(s, DoNotExternalize); } #if ENABLE(INSPECTOR) diff --git a/Source/WebCore/bindings/v8/V8AbstractEventListener.cpp b/Source/WebCore/bindings/v8/V8AbstractEventListener.cpp index 6dc49fa..f1102c2 100644 --- a/Source/WebCore/bindings/v8/V8AbstractEventListener.cpp +++ b/Source/WebCore/bindings/v8/V8AbstractEventListener.cpp @@ -72,6 +72,10 @@ V8AbstractEventListener::~V8AbstractEventListener() void V8AbstractEventListener::handleEvent(ScriptExecutionContext* context, Event* event) { + // Don't reenter V8 if execution was terminated in this instance of V8. + if (context->isJSExecutionForbidden()) + return; + ASSERT(event); // The callback function on XMLHttpRequest can clear the event listener and destroys 'this' object. Keep a local reference to it. @@ -150,8 +154,12 @@ void V8AbstractEventListener::invokeEventHandler(ScriptExecutionContext* context returnValue = callListenerFunction(context, jsEvent, event); if (tryCatch.HasCaught()) event->target()->uncaughtExceptionInEventHandler(); - if (!tryCatch.CanContinue()) + + if (!tryCatch.CanContinue()) { // Result of TerminateExecution(). + if (context->isWorkerContext()) + static_cast<WorkerContext*>(context)->script()->forbidExecution(); return; + } tryCatch.Reset(); // Restore the old event. This must be done for all exit paths through this method. diff --git a/Source/WebCore/bindings/v8/V8DOMWrapper.cpp b/Source/WebCore/bindings/v8/V8DOMWrapper.cpp index b439274..bef28a2 100644 --- a/Source/WebCore/bindings/v8/V8DOMWrapper.cpp +++ b/Source/WebCore/bindings/v8/V8DOMWrapper.cpp @@ -84,6 +84,7 @@ #endif #if ENABLE(WEB_AUDIO) +#include "V8AudioContext.h" #include "V8JavaScriptAudioNode.h" #endif @@ -444,6 +445,8 @@ v8::Handle<v8::Value> V8DOMWrapper::convertEventTargetToV8Object(EventTarget* ta #if ENABLE(WEB_AUDIO) if (JavaScriptAudioNode* jsAudioNode = target->toJavaScriptAudioNode()) return toV8(jsAudioNode); + if (AudioContext* audioContext = target->toAudioContext()) + return toV8(audioContext); #endif ASSERT(0); diff --git a/Source/WebCore/bindings/v8/V8GCController.cpp b/Source/WebCore/bindings/v8/V8GCController.cpp index 82c9ca4..c9e9dfd 100644 --- a/Source/WebCore/bindings/v8/V8GCController.cpp +++ b/Source/WebCore/bindings/v8/V8GCController.cpp @@ -359,6 +359,24 @@ public: GroupId groupId = calculateGroupId(cssStyleDeclaration); m_grouper.append(GrouperItem(groupId, wrapper)); + // Keep alive "dirty" primitive values (i.e. the ones that + // have user-added properties) by creating implicit + // references between the style declaration and the values + // in it. + if (cssStyleDeclaration->isMutableStyleDeclaration()) { + CSSMutableStyleDeclaration* cssMutableStyleDeclaration = static_cast<CSSMutableStyleDeclaration*>(cssStyleDeclaration); + Vector<v8::Persistent<v8::Value> > values; + values.reserveCapacity(cssMutableStyleDeclaration->length()); + CSSMutableStyleDeclaration::const_iterator end = cssMutableStyleDeclaration->end(); + for (CSSMutableStyleDeclaration::const_iterator it = cssMutableStyleDeclaration->begin(); it != end; ++it) { + v8::Persistent<v8::Object> value = store->domObjectMap().get(it->value()); + if (!value.IsEmpty() && value->IsDirty()) + values.append(value); + } + if (!values.isEmpty()) + v8::V8::AddImplicitReferences(wrapper, values.data(), values.size()); + } + } else if (typeInfo->isSubclass(&V8CSSRuleList::info)) { CSSRuleList* cssRuleList = static_cast<CSSRuleList*>(object); GroupId groupId(cssRuleList); diff --git a/Source/WebCore/bindings/v8/V8Utilities.cpp b/Source/WebCore/bindings/v8/V8Utilities.cpp index eebe6b5..b631359 100644 --- a/Source/WebCore/bindings/v8/V8Utilities.cpp +++ b/Source/WebCore/bindings/v8/V8Utilities.cpp @@ -127,4 +127,9 @@ ScriptExecutionContext* getScriptExecutionContext() return 0; } +void throwTypeMismatchException() +{ + V8Proxy::throwError(V8Proxy::GeneralError, "TYPE_MISMATCH_ERR: DOM Exception 17"); +} + } // namespace WebCore diff --git a/Source/WebCore/bindings/v8/V8Utilities.h b/Source/WebCore/bindings/v8/V8Utilities.h index 1892bb7..4a44f3c 100644 --- a/Source/WebCore/bindings/v8/V8Utilities.h +++ b/Source/WebCore/bindings/v8/V8Utilities.h @@ -55,6 +55,36 @@ namespace WebCore { ScriptExecutionContext* getScriptExecutionContext(); + void throwTypeMismatchException(); + + enum CallbackAllowedValueFlag { + CallbackAllowUndefined = 1, + CallbackAllowNull = 1 << 1 + }; + + typedef unsigned CallbackAllowedValueFlags; + + // 'FunctionOnly' is assumed for the created callback. + template <typename V8CallbackType> + PassRefPtr<V8CallbackType> createFunctionOnlyCallback(v8::Local<v8::Value> value, bool& succeeded, CallbackAllowedValueFlags acceptedValues = 0) + { + succeeded = true; + + if (value->IsUndefined() && (acceptedValues & CallbackAllowUndefined)) + return 0; + + if (value->IsNull() && (acceptedValues & CallbackAllowNull)) + return 0; + + if (!value->IsFunction()) { + succeeded = false; + throwTypeMismatchException(); + return 0; + } + + return V8CallbackType::create(value, getScriptExecutionContext()); + } + class AllowAllocation { public: inline AllowAllocation() diff --git a/Source/WebCore/bindings/v8/WorkerContextExecutionProxy.cpp b/Source/WebCore/bindings/v8/WorkerContextExecutionProxy.cpp index eb7252b..42259d5 100644 --- a/Source/WebCore/bindings/v8/WorkerContextExecutionProxy.cpp +++ b/Source/WebCore/bindings/v8/WorkerContextExecutionProxy.cpp @@ -150,6 +150,9 @@ bool WorkerContextExecutionProxy::initContextIfNeeded() v8::Context::Scope scope(context); + // Set DebugId for the new context. + context->SetData(v8::String::New("worker")); + // Create a new JS object and use it as the prototype for the shadow global object. WrapperTypeInfo* contextType = &V8DedicatedWorkerContext::info; #if ENABLE(SHARED_WORKERS) @@ -200,8 +203,10 @@ ScriptValue WorkerContextExecutionProxy::evaluate(const String& script, const St v8::Handle<v8::Script> compiledScript = V8Proxy::compileScript(scriptString, fileName, scriptStartPosition); v8::Local<v8::Value> result = runScript(compiledScript); - if (!exceptionCatcher.CanContinue()) + if (!exceptionCatcher.CanContinue()) { + m_workerContext->script()->forbidExecution(); return ScriptValue(); + } if (exceptionCatcher.HasCaught()) { v8::Local<v8::Message> message = exceptionCatcher.Message(); diff --git a/Source/WebCore/bindings/v8/WorkerScriptController.cpp b/Source/WebCore/bindings/v8/WorkerScriptController.cpp index 42e02e6..214da4e 100644 --- a/Source/WebCore/bindings/v8/WorkerScriptController.cpp +++ b/Source/WebCore/bindings/v8/WorkerScriptController.cpp @@ -68,11 +68,8 @@ ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode) ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, ScriptValue* exception) { - { - MutexLocker lock(m_sharedDataMutex); - if (m_executionForbidden) - return ScriptValue(); - } + if (isExecutionForbidden()) + return ScriptValue(); WorkerContextExecutionState state; ScriptValue result = m_proxy->evaluate(sourceCode.source(), sourceCode.url().string(), WTF::toZeroBasedTextPosition(sourceCode.startPosition()), &state); @@ -86,13 +83,21 @@ ScriptValue WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, return result; } -void WorkerScriptController::forbidExecution(ForbidExecutionOption option) +void WorkerScriptController::scheduleExecutionTermination() +{ + v8::V8::TerminateExecution(); +} + +void WorkerScriptController::forbidExecution() { - // This function may be called from another thread. - MutexLocker lock(m_sharedDataMutex); + ASSERT(m_workerContext->isContextThread()); m_executionForbidden = true; - if (option == TerminateRunningScript) - v8::V8::TerminateExecution(); +} + +bool WorkerScriptController::isExecutionForbidden() const +{ + ASSERT(m_workerContext->isContextThread()); + return m_executionForbidden; } void WorkerScriptController::setException(ScriptValue exception) diff --git a/Source/WebCore/bindings/v8/WorkerScriptController.h b/Source/WebCore/bindings/v8/WorkerScriptController.h index 5e3159f..cc4b7c4 100644 --- a/Source/WebCore/bindings/v8/WorkerScriptController.h +++ b/Source/WebCore/bindings/v8/WorkerScriptController.h @@ -48,7 +48,7 @@ namespace WebCore { WorkerScriptController(WorkerContext*); ~WorkerScriptController(); - WorkerContextExecutionProxy* proxy() { return m_executionForbidden ? 0 : m_proxy.get(); } + WorkerContextExecutionProxy* proxy() { return m_proxy.get(); } WorkerContext* workerContext() { return m_workerContext; } ScriptValue evaluate(const ScriptSourceCode&); @@ -56,9 +56,17 @@ namespace WebCore { void setException(ScriptValue); - enum ForbidExecutionOption { TerminateRunningScript, LetRunningScriptFinish }; - void forbidExecution(ForbidExecutionOption); - bool isExecutionForbidden() const { return m_executionForbidden; } + // Async request to terminate a future JS execution. Eventually causes termination + // exception raised during JS execution, if the worker thread happens to run JS. + // After JS execution was terminated in this way, the Worker thread has to use + // forbidExecution()/isExecutionForbidden() to guard against reentry into JS. + // Can be called from any thread. + void scheduleExecutionTermination(); + + // Called on Worker thread when JS exits with termination exception caused by forbidExecution() request, + // or by Worker thread termination code to prevent future entry into JS. + void forbidExecution(); + bool isExecutionForbidden() const; // Returns WorkerScriptController for the currently executing context. 0 will be returned if the current executing context is not the worker context. static WorkerScriptController* controllerForContext(); @@ -66,8 +74,6 @@ namespace WebCore { private: WorkerContext* m_workerContext; OwnPtr<WorkerContextExecutionProxy> m_proxy; - - Mutex m_sharedDataMutex; bool m_executionForbidden; }; diff --git a/Source/WebCore/bindings/v8/WorkerScriptDebugServer.cpp b/Source/WebCore/bindings/v8/WorkerScriptDebugServer.cpp index 5e2acd2..1887cea 100755 --- a/Source/WebCore/bindings/v8/WorkerScriptDebugServer.cpp +++ b/Source/WebCore/bindings/v8/WorkerScriptDebugServer.cpp @@ -33,21 +33,118 @@ #if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(WORKERS) +#include "ScriptDebugListener.h" +#include "V8DOMWrapper.h" +#include "V8DedicatedWorkerContext.h" +#include "V8SharedWorkerContext.h" #include "WorkerContext.h" +#include "WorkerContextExecutionProxy.h" +#include "WorkerThread.h" +#include <v8.h> +#include <wtf/MessageQueue.h> namespace WebCore { +static WorkerContext* retrieveWorkerContext(v8::Handle<v8::Context> context) +{ + v8::Handle<v8::Object> global = context->Global(); + ASSERT(!global.IsEmpty()); + + v8::Handle<v8::Object> prototype = v8::Handle<v8::Object>::Cast(global->GetPrototype()); + ASSERT(!prototype.IsEmpty()); + + prototype = v8::Handle<v8::Object>::Cast(prototype->GetPrototype()); + ASSERT(!prototype.IsEmpty()); + + WrapperTypeInfo* typeInfo = V8DOMWrapper::domWrapperType(prototype); + if (&V8DedicatedWorkerContext::info == typeInfo) + return V8DedicatedWorkerContext::toNative(prototype); + if (&V8SharedWorkerContext::info == typeInfo) + return V8SharedWorkerContext::toNative(prototype); + ASSERT_NOT_REACHED(); + return 0; +} + WorkerScriptDebugServer::WorkerScriptDebugServer() : ScriptDebugServer() + , m_pausedWorkerContext(0) +{ +} + +void WorkerScriptDebugServer::addListener(ScriptDebugListener* listener, WorkerContext* workerContext) +{ + v8::HandleScope scope; + v8::Local<v8::Context> debuggerContext = v8::Debug::GetDebugContext(); + v8::Context::Scope contextScope(debuggerContext); + + if (!m_listenersMap.size()) { + // FIXME: synchronize access to this code. + ensureDebuggerScriptCompiled(); + ASSERT(!m_debuggerScript.get()->IsUndefined()); + v8::Debug::SetDebugEventListener2(&WorkerScriptDebugServer::v8DebugEventCallback, v8::External::New(this)); + } + m_listenersMap.set(workerContext, listener); + + WorkerContextExecutionProxy* proxy = workerContext->script()->proxy(); + if (!proxy) + return; + v8::Handle<v8::Context> context = proxy->context(); + + v8::Handle<v8::Function> getScriptsFunction = v8::Local<v8::Function>::Cast(m_debuggerScript.get()->Get(v8::String::New("getWorkerScripts"))); + v8::Handle<v8::Value> argv[] = { v8::Handle<v8::Value>() }; + v8::Handle<v8::Value> value = getScriptsFunction->Call(m_debuggerScript.get(), 0, 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 WorkerScriptDebugServer::removeListener(ScriptDebugListener* listener, WorkerContext* workerContext) { + if (!m_listenersMap.contains(workerContext)) + return; + + if (m_pausedWorkerContext == workerContext) + continueProgram(); + + m_listenersMap.remove(workerContext); + + if (m_listenersMap.isEmpty()) + v8::Debug::SetDebugEventListener2(0); } -void WorkerScriptDebugServer::addListener(ScriptDebugListener*, WorkerContext*) +ScriptDebugListener* WorkerScriptDebugServer::getDebugListenerForContext(v8::Handle<v8::Context> context) { + WorkerContext* workerContext = retrieveWorkerContext(context); + if (!workerContext) + return 0; + return m_listenersMap.get(workerContext); +} + +void WorkerScriptDebugServer::runMessageLoopOnPause(v8::Handle<v8::Context> context) +{ + WorkerContext* workerContext = retrieveWorkerContext(context); + WorkerThread* workerThread = workerContext->thread(); + + m_pausedWorkerContext = workerContext; + + MessageQueueWaitResult result; + do { + result = workerThread->runLoop().runInMode(workerContext, "debugger"); + // Keep waiting until execution is resumed. + } while (result == MessageQueueMessageReceived && isPaused()); + m_pausedWorkerContext = 0; + + // The listener may have been removed in the nested loop. + if (ScriptDebugListener* listener = m_listenersMap.get(workerContext)) + listener->didContinue(); } -void WorkerScriptDebugServer::removeListener(ScriptDebugListener*, WorkerContext*) +void WorkerScriptDebugServer::quitMessageLoopOnPause() { + // FIXME: do exit nested loop when listener is removed on pause. } } // namespace WebCore diff --git a/Source/WebCore/bindings/v8/WorkerScriptDebugServer.h b/Source/WebCore/bindings/v8/WorkerScriptDebugServer.h index fdc47ac..6264c68 100755 --- a/Source/WebCore/bindings/v8/WorkerScriptDebugServer.h +++ b/Source/WebCore/bindings/v8/WorkerScriptDebugServer.h @@ -49,9 +49,13 @@ public: void removeListener(ScriptDebugListener*, WorkerContext*); private: - virtual ScriptDebugListener* getDebugListenerForContext(v8::Handle<v8::Context>) { return 0; } - virtual void runMessageLoopOnPause(v8::Handle<v8::Context>) { } - virtual void quitMessageLoopOnPause() { } + virtual ScriptDebugListener* getDebugListenerForContext(v8::Handle<v8::Context>); + virtual void runMessageLoopOnPause(v8::Handle<v8::Context>); + virtual void quitMessageLoopOnPause(); + + typedef HashMap<WorkerContext*, ScriptDebugListener*> ListenersMap; + ListenersMap m_listenersMap; + WorkerContext* m_pausedWorkerContext; }; } // namespace WebCore diff --git a/Source/WebCore/bindings/v8/custom/V8AudioContextCustom.cpp b/Source/WebCore/bindings/v8/custom/V8AudioContextCustom.cpp index 419cd60..f2f8dc0 100644 --- a/Source/WebCore/bindings/v8/custom/V8AudioContextCustom.cpp +++ b/Source/WebCore/bindings/v8/custom/V8AudioContextCustom.cpp @@ -51,7 +51,34 @@ v8::Handle<v8::Value> V8AudioContext::constructorCallback(const v8::Arguments& a if (!document) return throwError("AudioContext constructor associated document is unavailable", V8Proxy::ReferenceError); - RefPtr<AudioContext> audioContext = AudioContext::create(document); + RefPtr<AudioContext> audioContext; + + if (!args.Length()) { + // Constructor for default AudioContext which talks to audio hardware. + audioContext = AudioContext::create(document); + } else { + // Constructor for offline (render-target) AudioContext which renders into an AudioBuffer. + // new AudioContext(in unsigned long numberOfChannels, in unsigned long numberOfFrames, in float sampleRate); + if (args.Length() < 3) + return throwError("Not enough arguments", V8Proxy::SyntaxError); + + bool ok = false; + + unsigned numberOfChannels = toInt32(args[0], ok); + if (!ok) + return throwError("Invalid number of channels", V8Proxy::SyntaxError); + + unsigned numberOfFrames = toInt32(args[1], ok); + if (!ok) + return throwError("Invalid number of frames", V8Proxy::SyntaxError); + + float sampleRate = toFloat(args[2]); + + audioContext = AudioContext::createOfflineContext(document, numberOfChannels, numberOfFrames, sampleRate); + } + + if (!audioContext.get()) + return throwError("Error creating AudioContext", V8Proxy::SyntaxError); // Transform the holder into a wrapper object for the audio context. V8DOMWrapper::setDOMWrapper(args.Holder(), &info, audioContext.get()); diff --git a/Source/WebCore/bindings/v8/custom/V8CSSStyleDeclarationCustom.cpp b/Source/WebCore/bindings/v8/custom/V8CSSStyleDeclarationCustom.cpp index 850ae14..097924b 100644 --- a/Source/WebCore/bindings/v8/custom/V8CSSStyleDeclarationCustom.cpp +++ b/Source/WebCore/bindings/v8/custom/V8CSSStyleDeclarationCustom.cpp @@ -40,6 +40,8 @@ #include "V8Binding.h" #include "V8Proxy.h" +#include <wtf/text/StringBuilder.h> +#include <wtf/text/StringConcatenate.h> #include <wtf/ASCIICType.h> #include <wtf/PassRefPtr.h> #include <wtf/RefPtr.h> @@ -107,8 +109,8 @@ static CSSPropertyInfo* cssPropertyInfo(v8::Handle<v8::String>v8PropertyName) if (!length) return 0; - Vector<UChar> name; - name.reserveCapacity(length); + StringBuilder builder; + builder.reserveCapacity(length); unsigned i = 0; @@ -123,23 +125,21 @@ static CSSPropertyInfo* cssPropertyInfo(v8::Handle<v8::String>v8PropertyName) } else if (hasCSSPropertyNamePrefix(propertyName, "webkit") || hasCSSPropertyNamePrefix(propertyName, "khtml") || hasCSSPropertyNamePrefix(propertyName, "apple")) - name.append('-'); + builder.append('-'); else if (WTF::isASCIIUpper(propertyName[0])) return 0; - name.append(WTF::toASCIILower(propertyName[i++])); + builder.append(WTF::toASCIILower(propertyName[i++])); for (; i < length; ++i) { UChar c = propertyName[i]; if (!WTF::isASCIIUpper(c)) - name.append(c); - else { - name.append('-'); - name.append(WTF::toASCIILower(c)); - } + builder.append(c); + else + builder.append(makeString('-', toASCIILower(c))); } - String propName = String::adopt(name); + String propName = builder.toString(); int propertyID = cssPropertyID(propName); if (propertyID) { propInfo = new CSSPropertyInfo(); diff --git a/Source/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp b/Source/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp index 85ae322..43d5a15 100644 --- a/Source/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp +++ b/Source/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp @@ -32,6 +32,7 @@ #include "V8DOMWindow.h" #include "Chrome.h" +#include "ContentSecurityPolicy.h" #include "DOMTimer.h" #include "DOMWindow.h" #include "ExceptionCode.h" @@ -131,6 +132,8 @@ v8::Handle<v8::Value> WindowSetTimeoutImpl(const v8::Arguments& args, bool singl id = DOMTimer::install(scriptContext, action, timeout, singleShot); } else { + if (imp->document() && !imp->document()->contentSecurityPolicy()->allowEval()) + return v8::Integer::New(0); id = DOMTimer::install(scriptContext, new ScheduledAction(V8Proxy::context(imp->frame()), functionString), timeout, singleShot); } diff --git a/Source/WebCore/bindings/v8/custom/V8DirectoryEntryCustom.cpp b/Source/WebCore/bindings/v8/custom/V8DirectoryEntryCustom.cpp index a44131a..0889451 100644 --- a/Source/WebCore/bindings/v8/custom/V8DirectoryEntryCustom.cpp +++ b/Source/WebCore/bindings/v8/custom/V8DirectoryEntryCustom.cpp @@ -39,7 +39,7 @@ #include "V8BindingMacros.h" #include "V8EntryCallback.h" #include "V8ErrorCallback.h" -#include "V8Flags.h" +#include "V8WebKitFlags.h" #include "V8Proxy.h" #include <wtf/RefCounted.h> #include <wtf/RefPtr.h> @@ -55,10 +55,10 @@ v8::Handle<v8::Value> V8DirectoryEntry::getDirectoryCallback(const v8::Arguments imp->getDirectory(path); return v8::Handle<v8::Value>(); } - RefPtr<Flags> flags; - if (!isUndefinedOrNull(args[1]) && args[1]->IsObject() && !V8Flags::HasInstance(args[1])) { + RefPtr<WebKitFlags> flags; + if (!isUndefinedOrNull(args[1]) && args[1]->IsObject() && !V8WebKitFlags::HasInstance(args[1])) { EXCEPTION_BLOCK(v8::Handle<v8::Object>, object, v8::Handle<v8::Object>::Cast(args[1])); - flags = Flags::create(); + flags = WebKitFlags::create(); v8::Local<v8::Value> v8Create = object->Get(v8::String::New("create")); if (!v8Create.IsEmpty() && !isUndefinedOrNull(v8Create)) { EXCEPTION_BLOCK(bool, isCreate, v8Create->BooleanValue()); @@ -70,7 +70,7 @@ v8::Handle<v8::Value> V8DirectoryEntry::getDirectoryCallback(const v8::Arguments flags->setExclusive(isExclusive); } } else { - EXCEPTION_BLOCK(Flags*, tmp_flags, V8Flags::HasInstance(args[1]) ? V8Flags::toNative(v8::Handle<v8::Object>::Cast(args[1])) : 0); + EXCEPTION_BLOCK(WebKitFlags*, tmp_flags, V8WebKitFlags::HasInstance(args[1]) ? V8WebKitFlags::toNative(v8::Handle<v8::Object>::Cast(args[1])) : 0); flags = tmp_flags; } RefPtr<EntryCallback> successCallback; @@ -98,10 +98,10 @@ v8::Handle<v8::Value> V8DirectoryEntry::getFileCallback(const v8::Arguments& arg imp->getFile(path); return v8::Handle<v8::Value>(); } - RefPtr<Flags> flags; - if (!isUndefinedOrNull(args[1]) && args[1]->IsObject() && !V8Flags::HasInstance(args[1])) { + RefPtr<WebKitFlags> flags; + if (!isUndefinedOrNull(args[1]) && args[1]->IsObject() && !V8WebKitFlags::HasInstance(args[1])) { EXCEPTION_BLOCK(v8::Handle<v8::Object>, object, v8::Handle<v8::Object>::Cast(args[1])); - flags = Flags::create(); + flags = WebKitFlags::create(); v8::Local<v8::Value> v8Create = object->Get(v8::String::New("create")); if (!v8Create.IsEmpty() && !isUndefinedOrNull(v8Create)) { EXCEPTION_BLOCK(bool, isCreate, v8Create->BooleanValue()); @@ -113,7 +113,7 @@ v8::Handle<v8::Value> V8DirectoryEntry::getFileCallback(const v8::Arguments& arg flags->setExclusive(isExclusive); } } else { - EXCEPTION_BLOCK(Flags*, tmp_flags, V8Flags::HasInstance(args[1]) ? V8Flags::toNative(v8::Handle<v8::Object>::Cast(args[1])) : 0); + EXCEPTION_BLOCK(WebKitFlags*, tmp_flags, V8WebKitFlags::HasInstance(args[1]) ? V8WebKitFlags::toNative(v8::Handle<v8::Object>::Cast(args[1])) : 0); flags = tmp_flags; } RefPtr<EntryCallback> successCallback; diff --git a/Source/WebCore/bindings/v8/custom/V8DirectoryEntrySyncCustom.cpp b/Source/WebCore/bindings/v8/custom/V8DirectoryEntrySyncCustom.cpp index 90b3d13..cd38ca4 100644 --- a/Source/WebCore/bindings/v8/custom/V8DirectoryEntrySyncCustom.cpp +++ b/Source/WebCore/bindings/v8/custom/V8DirectoryEntrySyncCustom.cpp @@ -40,7 +40,7 @@ #include "V8EntryCallback.h" #include "V8ErrorCallback.h" #include "V8FileEntrySync.h" -#include "V8Flags.h" +#include "V8WebKitFlags.h" #include "V8Proxy.h" #include <wtf/RefCounted.h> #include <wtf/RefPtr.h> @@ -62,13 +62,13 @@ static bool extractBooleanValue(const v8::Handle<v8::Object>& object, const char return false; } -static PassRefPtr<Flags> getFlags(const v8::Local<v8::Value>& arg, ExceptionCode& ec) +static PassRefPtr<WebKitFlags> getFlags(const v8::Local<v8::Value>& arg, ExceptionCode& ec) { ec = 0; if (isUndefinedOrNull(arg) || !arg->IsObject()) return 0; - if (V8Flags::HasInstance(arg)) - return V8Flags::toNative(v8::Handle<v8::Object>::Cast(arg)); + if (V8WebKitFlags::HasInstance(arg)) + return V8WebKitFlags::toNative(v8::Handle<v8::Object>::Cast(arg)); v8::Handle<v8::Object> object; { @@ -87,7 +87,7 @@ static PassRefPtr<Flags> getFlags(const v8::Local<v8::Value>& arg, ExceptionCode if (ec) return 0; - RefPtr<Flags> flags = Flags::create(); + RefPtr<WebKitFlags> flags = WebKitFlags::create(); flags->setCreate(isCreate); flags->setExclusive(isExclusive); @@ -100,7 +100,7 @@ v8::Handle<v8::Value> V8DirectoryEntrySync::getDirectoryCallback(const v8::Argum DirectoryEntrySync* imp = V8DirectoryEntrySync::toNative(args.Holder()); ExceptionCode ec = 0; STRING_TO_V8PARAMETER_EXCEPTION_BLOCK(V8Parameter<>, path, args[0]); - RefPtr<Flags> flags = getFlags(args[1], ec); + RefPtr<WebKitFlags> flags = getFlags(args[1], ec); if (UNLIKELY(ec)) { V8Proxy::setDOMException(ec); return v8::Handle<v8::Value>(); @@ -119,7 +119,7 @@ v8::Handle<v8::Value> V8DirectoryEntrySync::getFileCallback(const v8::Arguments& DirectoryEntrySync* imp = V8DirectoryEntrySync::toNative(args.Holder()); ExceptionCode ec = 0; STRING_TO_V8PARAMETER_EXCEPTION_BLOCK(V8Parameter<>, path, args[0]); - RefPtr<Flags> flags = getFlags(args[1], ec); + RefPtr<WebKitFlags> flags = getFlags(args[1], ec); if (UNLIKELY(ec)) { V8Proxy::setDOMException(ec); return v8::Handle<v8::Value>(); diff --git a/Source/WebCore/bindings/v8/custom/V8DocumentCustom.cpp b/Source/WebCore/bindings/v8/custom/V8DocumentCustom.cpp index c435863..7cad58e 100644 --- a/Source/WebCore/bindings/v8/custom/V8DocumentCustom.cpp +++ b/Source/WebCore/bindings/v8/custom/V8DocumentCustom.cpp @@ -118,34 +118,6 @@ v8::Handle<v8::Value> V8Document::getCSSCanvasContextCallback(const v8::Argument return v8::Undefined(); } - -// DOMImplementation is a singleton in WebCore. If we use our normal -// mapping from DOM objects to V8 wrappers, the same wrapper will be -// shared for all frames in the same process. This is a major -// security problem. Therefore, we generate a DOMImplementation -// wrapper per document and store it in an internal field of the -// document. Since the DOMImplementation object is a singleton, we do -// not have to do anything to keep the DOMImplementation object alive -// for the lifetime of the wrapper. -v8::Handle<v8::Value> V8Document::implementationAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) -{ - ASSERT(info.Holder()->InternalFieldCount() >= internalFieldCount); - - // Check if the internal field already contains a wrapper. - v8::Local<v8::Value> implementation = info.Holder()->GetInternalField(V8Document::implementationIndex); - if (!implementation->IsUndefined()) - return implementation; - - // Generate a wrapper. - Document* document = V8Document::toNative(info.Holder()); - v8::Handle<v8::Value> wrapper = toV8(document->implementation()); - - // Store the wrapper in the internal field. - info.Holder()->SetInternalField(implementationIndex, wrapper); - - return wrapper; -} - v8::Handle<v8::Value> toV8(Document* impl, bool forceNewObject) { if (!impl) diff --git a/Source/WebCore/bindings/v8/custom/V8EventCustom.cpp b/Source/WebCore/bindings/v8/custom/V8EventCustom.cpp index abb7d4c..7e12034 100644 --- a/Source/WebCore/bindings/v8/custom/V8EventCustom.cpp +++ b/Source/WebCore/bindings/v8/custom/V8EventCustom.cpp @@ -70,6 +70,7 @@ #if ENABLE(WEB_AUDIO) #include "V8AudioProcessingEvent.h" +#include "V8OfflineAudioCompletionEvent.h" #endif namespace WebCore { @@ -169,6 +170,8 @@ v8::Handle<v8::Value> toV8(Event* impl) #if ENABLE(WEB_AUDIO) if (impl->isAudioProcessingEvent()) return toV8(static_cast<AudioProcessingEvent*>(impl)); + if (impl->isOfflineAudioCompletionEvent()) + return toV8(static_cast<OfflineAudioCompletionEvent*>(impl)); #endif #if ENABLE(INPUT_SPEECH) if (impl->isSpeechInputEvent()) diff --git a/Source/WebCore/bindings/v8/custom/V8GeolocationCustom.cpp b/Source/WebCore/bindings/v8/custom/V8GeolocationCustom.cpp index 54bd11c..91389d8 100644 --- a/Source/WebCore/bindings/v8/custom/V8GeolocationCustom.cpp +++ b/Source/WebCore/bindings/v8/custom/V8GeolocationCustom.cpp @@ -33,52 +33,13 @@ #include "V8Binding.h" #include "V8CustomPositionCallback.h" #include "V8CustomPositionErrorCallback.h" -#include "V8Proxy.h" +#include "V8Utilities.h" using namespace std; using namespace WTF; namespace WebCore { -static const char typeMismatchError[] = "TYPE_MISMATCH_ERR: DOM Exception 17"; - -static void throwTypeMismatchException() -{ - V8Proxy::throwError(V8Proxy::GeneralError, typeMismatchError); -} - -static PassRefPtr<PositionCallback> createPositionCallback(v8::Local<v8::Value> value, bool& succeeded) -{ - succeeded = true; - - // The spec specifies 'FunctionOnly' for this object. - if (!value->IsFunction()) { - succeeded = false; - throwTypeMismatchException(); - return 0; - } - - return V8CustomPositionCallback::create(value, getScriptExecutionContext()); -} - -static PassRefPtr<PositionErrorCallback> createPositionErrorCallback(v8::Local<v8::Value> value, bool& succeeded) -{ - succeeded = true; - - // Argument is optional (hence undefined is allowed), and null is allowed. - if (isUndefinedOrNull(value)) - return 0; - - // The spec specifies 'FunctionOnly' for this object. - if (!value->IsFunction()) { - succeeded = false; - throwTypeMismatchException(); - return 0; - } - - return V8CustomPositionErrorCallback::create(value, getScriptExecutionContext()); -} - static PassRefPtr<PositionOptions> createPositionOptions(v8::Local<v8::Value> value, bool& succeeded) { succeeded = true; @@ -172,12 +133,13 @@ v8::Handle<v8::Value> V8Geolocation::getCurrentPositionCallback(const v8::Argume bool succeeded = false; - RefPtr<PositionCallback> positionCallback = createPositionCallback(args[0], succeeded); + RefPtr<PositionCallback> positionCallback = createFunctionOnlyCallback<V8CustomPositionCallback>(args[0], succeeded); if (!succeeded) return v8::Undefined(); ASSERT(positionCallback); - RefPtr<PositionErrorCallback> positionErrorCallback = createPositionErrorCallback(args[1], succeeded); + // Argument is optional (hence undefined is allowed), and null is allowed. + RefPtr<PositionErrorCallback> positionErrorCallback = createFunctionOnlyCallback<V8CustomPositionErrorCallback>(args[1], succeeded, CallbackAllowUndefined | CallbackAllowNull); if (!succeeded) return v8::Undefined(); @@ -197,12 +159,13 @@ v8::Handle<v8::Value> V8Geolocation::watchPositionCallback(const v8::Arguments& bool succeeded = false; - RefPtr<PositionCallback> positionCallback = createPositionCallback(args[0], succeeded); + RefPtr<PositionCallback> positionCallback = createFunctionOnlyCallback<V8CustomPositionCallback>(args[0], succeeded); if (!succeeded) return v8::Undefined(); ASSERT(positionCallback); - RefPtr<PositionErrorCallback> positionErrorCallback = createPositionErrorCallback(args[1], succeeded); + // Argument is optional (hence undefined is allowed), and null is allowed. + RefPtr<PositionErrorCallback> positionErrorCallback = createFunctionOnlyCallback<V8CustomPositionErrorCallback>(args[1], succeeded, CallbackAllowUndefined | CallbackAllowNull); if (!succeeded) return v8::Undefined(); diff --git a/Source/WebCore/bindings/v8/custom/V8InjectedScriptManager.cpp b/Source/WebCore/bindings/v8/custom/V8InjectedScriptManager.cpp index f4006b8..8bb4281 100644 --- a/Source/WebCore/bindings/v8/custom/V8InjectedScriptManager.cpp +++ b/Source/WebCore/bindings/v8/custom/V8InjectedScriptManager.cpp @@ -139,13 +139,13 @@ InjectedScript InjectedScriptManager::injectedScriptFor(ScriptState* inspectedSc 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))); + return InjectedScript(ScriptObject(inspectedScriptState, v8::Local<v8::Object>::Cast(val)), m_inspectedStateAccessCheck); - if (!canAccessInspectedWindow(inspectedScriptState)) + if (!m_inspectedStateAccessCheck(inspectedScriptState)) return InjectedScript(); pair<long, ScriptObject> injectedScript = injectScript(injectedScriptSource(), inspectedScriptState); - InjectedScript result(injectedScript.second); + InjectedScript result(injectedScript.second, m_inspectedStateAccessCheck); m_idToInjectedScript.set(injectedScript.first, result); global->SetHiddenValue(key, injectedScript.second.v8Object()); return result; diff --git a/Source/WebCore/bindings/v8/custom/V8NavigatorCustom.cpp b/Source/WebCore/bindings/v8/custom/V8NavigatorCustom.cpp index e5a6909..16e8cfe 100644 --- a/Source/WebCore/bindings/v8/custom/V8NavigatorCustom.cpp +++ b/Source/WebCore/bindings/v8/custom/V8NavigatorCustom.cpp @@ -1,4 +1,5 @@ /* +<<<<<<< HEAD * Copyright (C) 2010 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,11 +27,35 @@ * 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. +======= + * 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: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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 APPLE INC. AND ITS 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 APPLE INC. OR ITS 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. +>>>>>>> WebKit.org at r84325 */ #include "config.h" #include "V8Navigator.h" +<<<<<<< HEAD #if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED) #include "ExceptionCode.h" @@ -77,9 +102,49 @@ v8::Handle<v8::Value> V8Navigator::isApplicationInstalledCallback(const v8::Argu if (!navigator->isApplicationInstalled(toWebCoreString(args[0]), callback.release())) return throwError(INVALID_STATE_ERR); +======= +#if ENABLE(MEDIA_STREAM) + +#include "Navigator.h" +#include "V8Binding.h" +#include "V8NavigatorUserMediaErrorCallback.h" +#include "V8NavigatorUserMediaSuccessCallback.h" +#include "V8Utilities.h" + +using namespace WTF; + +namespace WebCore { + +v8::Handle<v8::Value> V8Navigator::webkitGetUserMediaCallback(const v8::Arguments& args) +{ + INC_STATS("DOM.Navigator.webkitGetUserMedia()"); + + v8::TryCatch exceptionCatcher; + String options = toWebCoreString(args[0]); + if (exceptionCatcher.HasCaught()) + return throwError(exceptionCatcher.Exception()); + + bool succeeded = false; + + RefPtr<NavigatorUserMediaSuccessCallback> successCallback = createFunctionOnlyCallback<V8NavigatorUserMediaSuccessCallback>(args[1], succeeded); + if (!succeeded) + return v8::Undefined(); + + // Argument is optional, hence undefined is allowed. + RefPtr<NavigatorUserMediaErrorCallback> errorCallback = createFunctionOnlyCallback<V8NavigatorUserMediaErrorCallback>(args[2], succeeded, CallbackAllowUndefined); + if (!succeeded) + return v8::Undefined(); + + Navigator* navigator = V8Navigator::toNative(args.Holder()); + navigator->webkitGetUserMedia(options, successCallback.release(), errorCallback.release()); +>>>>>>> WebKit.org at r84325 return v8::Undefined(); } } // namespace WebCore +<<<<<<< HEAD #endif // PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED) +======= +#endif // ENABLE(MEDIA_STREAM) +>>>>>>> WebKit.org at r84325 |