diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/bindings/js | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/bindings/js')
301 files changed, 18384 insertions, 12704 deletions
diff --git a/Source/WebCore/bindings/js/ArrayValue.cpp b/Source/WebCore/bindings/js/ArrayValue.cpp deleted file mode 100644 index e810f435e..000000000 --- a/Source/WebCore/bindings/js/ArrayValue.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2012 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 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 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 "ArrayValue.h" - -#include "Dictionary.h" -#include <runtime/JSArray.h> - -using namespace JSC; - -namespace WebCore { - -ArrayValue::ArrayValue() - : m_exec(0) -{ -} - -ArrayValue::ArrayValue(JSC::ExecState* exec, JSC::JSValue value) - : m_exec(exec) -{ - if (!value.isUndefinedOrNull() && isJSArray(value)) - m_value = value; -} - -ArrayValue& ArrayValue::operator=(const ArrayValue& other) -{ - m_exec = other.m_exec; - m_value = other.m_value; - return *this; -} - -bool ArrayValue::isUndefinedOrNull() const -{ - return m_value.isEmpty() || m_value.isUndefinedOrNull(); -} - -bool ArrayValue::length(size_t& length) const -{ - if (isUndefinedOrNull()) - return false; - - JSArray* array = asArray(m_value); - length = array->length(); - return true; -} - -bool ArrayValue::get(size_t index, Dictionary& value) const -{ - if (isUndefinedOrNull()) - return false; - - JSValue indexedValue = asArray(m_value)->getIndex(m_exec, index); - if (indexedValue.isUndefinedOrNull() || !indexedValue.isObject()) - return false; - - value = Dictionary(m_exec, indexedValue); - return true; -} - -} // namespace WebCore diff --git a/Source/WebCore/bindings/js/ArrayValue.h b/Source/WebCore/bindings/js/ArrayValue.h deleted file mode 100644 index 084f8c3cf..000000000 --- a/Source/WebCore/bindings/js/ArrayValue.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2012 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 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 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 ArrayValue_h -#define ArrayValue_h - -#include <interpreter/CallFrame.h> - -namespace WebCore { - -class Dictionary; - -class ArrayValue { -public: - ArrayValue(); - ArrayValue(JSC::ExecState*, JSC::JSValue); - - ArrayValue& operator=(const ArrayValue&); - - bool isUndefinedOrNull() const; - - bool length(size_t&) const; - bool get(size_t index, Dictionary&) const; - -private: - JSC::ExecState* m_exec; - JSC::JSValue m_value; -}; - -} - -#endif // ArrayValue_h diff --git a/Source/WebCore/bindings/js/BufferSource.h b/Source/WebCore/bindings/js/BufferSource.h new file mode 100644 index 000000000..01e458418 --- /dev/null +++ b/Source/WebCore/bindings/js/BufferSource.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2016 Igalia S.L. + * + * 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. + */ + +#pragma once + +#include <runtime/ArrayBuffer.h> +#include <runtime/ArrayBufferView.h> +#include <wtf/RefPtr.h> +#include <wtf/Variant.h> + +namespace WebCore { + +class BufferSource { +public: + using VariantType = WTF::Variant<RefPtr<JSC::ArrayBufferView>, RefPtr<JSC::ArrayBuffer>>; + + BufferSource() { } + BufferSource(VariantType&& variant) + : m_variant(WTFMove(variant)) + { } + + const VariantType& variant() const { return m_variant; } + + const uint8_t* data() const + { + return WTF::visit([](auto& buffer) -> const uint8_t* { + return static_cast<const uint8_t*>(buffer->data()); + }, m_variant); + } + + size_t length() const + { + return WTF::visit([](auto& buffer) -> size_t { + return buffer->byteLength(); + }, m_variant); + } + +private: + VariantType m_variant; +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/CachedModuleScriptLoader.cpp b/Source/WebCore/bindings/js/CachedModuleScriptLoader.cpp new file mode 100644 index 000000000..f15a4642e --- /dev/null +++ b/Source/WebCore/bindings/js/CachedModuleScriptLoader.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2015-2016 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 "CachedModuleScriptLoader.h" + +#include "CachedScript.h" +#include "CachedScriptFetcher.h" +#include "DOMWrapperWorld.h" +#include "Frame.h" +#include "JSDOMBinding.h" +#include "ResourceLoaderOptions.h" +#include "ScriptController.h" +#include "ScriptModuleLoader.h" +#include "ScriptSourceCode.h" + +namespace WebCore { + +Ref<CachedModuleScriptLoader> CachedModuleScriptLoader::create(CachedModuleScriptLoaderClient& client, DeferredPromise& promise, CachedScriptFetcher& scriptFetcher) +{ + return adoptRef(*new CachedModuleScriptLoader(client, promise, scriptFetcher)); +} + +CachedModuleScriptLoader::CachedModuleScriptLoader(CachedModuleScriptLoaderClient& client, DeferredPromise& promise, CachedScriptFetcher& scriptFetcher) + : m_client(&client) + , m_promise(&promise) + , m_scriptFetcher(scriptFetcher) +{ +} + +CachedModuleScriptLoader::~CachedModuleScriptLoader() +{ + if (m_cachedScript) { + m_cachedScript->removeClient(*this); + m_cachedScript = nullptr; + } +} + +bool CachedModuleScriptLoader::load(Document& document, const URL& sourceURL) +{ + ASSERT(!m_cachedScript); + m_cachedScript = m_scriptFetcher->requestModuleScript(document, sourceURL); + if (!m_cachedScript) + return false; + + // If the content is already cached, this immediately calls notifyFinished. + m_cachedScript->addClient(*this); + return true; +} + +void CachedModuleScriptLoader::notifyFinished(CachedResource& resource) +{ + ASSERT_UNUSED(resource, &resource == m_cachedScript); + ASSERT(m_cachedScript); + ASSERT(m_promise); + + Ref<CachedModuleScriptLoader> protectedThis(*this); + if (m_client) + m_client->notifyFinished(*this, WTFMove(m_promise)); + + // Remove the client after calling notifyFinished to keep the data buffer in + // CachedResource alive while notifyFinished processes the resource. + m_cachedScript->removeClient(*this); + m_cachedScript = nullptr; +} + +} diff --git a/Source/WebCore/bindings/js/CachedModuleScriptLoader.h b/Source/WebCore/bindings/js/CachedModuleScriptLoader.h new file mode 100644 index 000000000..04923f4dc --- /dev/null +++ b/Source/WebCore/bindings/js/CachedModuleScriptLoader.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015, 2016 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. + */ + +#pragma once + +#include "CachedResourceClient.h" +#include "CachedResourceHandle.h" +#include <wtf/Ref.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class CachedModuleScriptLoaderClient; +class CachedScript; +class CachedScriptFetcher; +class DeferredPromise; +class Document; +class JSDOMGlobalObject; +class URL; + +class CachedModuleScriptLoader final : public RefCounted<CachedModuleScriptLoader>, private CachedResourceClient { +public: + static Ref<CachedModuleScriptLoader> create(CachedModuleScriptLoaderClient&, DeferredPromise&, CachedScriptFetcher&); + + virtual ~CachedModuleScriptLoader(); + + bool load(Document&, const URL& sourceURL); + + CachedScriptFetcher& scriptFetcher() { return m_scriptFetcher.get(); } + CachedScript* cachedScript() { return m_cachedScript.get(); } + + void clearClient() + { + ASSERT(m_client); + m_client = nullptr; + } + +private: + CachedModuleScriptLoader(CachedModuleScriptLoaderClient&, DeferredPromise&, CachedScriptFetcher&); + + void notifyFinished(CachedResource&) final; + + CachedModuleScriptLoaderClient* m_client { nullptr }; + RefPtr<DeferredPromise> m_promise; + Ref<CachedScriptFetcher> m_scriptFetcher; + CachedResourceHandle<CachedScript> m_cachedScript; +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/CachedModuleScriptLoaderClient.h b/Source/WebCore/bindings/js/CachedModuleScriptLoaderClient.h new file mode 100644 index 000000000..6ccdbccca --- /dev/null +++ b/Source/WebCore/bindings/js/CachedModuleScriptLoaderClient.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2016 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. ``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 + * 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. + */ + +#pragma once + +#include "JSDOMPromise.h" + +namespace WebCore { + +class CachedModuleScriptLoader; + +class CachedModuleScriptLoaderClient { +public: + virtual ~CachedModuleScriptLoaderClient() { } + + virtual void notifyFinished(CachedModuleScriptLoader&, RefPtr<DeferredPromise>) = 0; +}; + +} diff --git a/Source/WebCore/bindings/js/CachedScriptFetcher.cpp b/Source/WebCore/bindings/js/CachedScriptFetcher.cpp new file mode 100644 index 000000000..e54f78513 --- /dev/null +++ b/Source/WebCore/bindings/js/CachedScriptFetcher.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2017 Yusuke Suzuki <utatane.tea@gmail.com> + * + * 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. ``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 + * 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 "CachedScriptFetcher.h" + +#include "CachedResourceLoader.h" +#include "CachedScript.h" +#include "ContentSecurityPolicy.h" +#include "Document.h" +#include "Settings.h" + +namespace WebCore { + +Ref<CachedScriptFetcher> CachedScriptFetcher::create(const String& charset) +{ + return adoptRef(*new CachedScriptFetcher(charset)); +} + +CachedResourceHandle<CachedScript> CachedScriptFetcher::requestModuleScript(Document& document, const URL& sourceURL) const +{ + return requestScriptWithCache(document, sourceURL, String()); +} + +CachedResourceHandle<CachedScript> CachedScriptFetcher::requestScriptWithCache(Document& document, const URL& sourceURL, const String& crossOriginMode) const +{ + if (!document.settings().isScriptEnabled()) + return nullptr; + + ASSERT(document.contentSecurityPolicy()); + bool hasKnownNonce = document.contentSecurityPolicy()->allowScriptWithNonce(m_nonce, m_isInUserAgentShadowTree); + ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions(); + options.contentSecurityPolicyImposition = hasKnownNonce ? ContentSecurityPolicyImposition::SkipPolicyCheck : ContentSecurityPolicyImposition::DoPolicyCheck; + + CachedResourceRequest request(ResourceRequest(sourceURL), options); + request.setAsPotentiallyCrossOrigin(crossOriginMode, document); + request.upgradeInsecureRequestIfNeeded(document); + + request.setCharset(m_charset); + if (!m_initiatorName.isNull()) + request.setInitiator(m_initiatorName); + + return document.cachedResourceLoader().requestScript(WTFMove(request)); +} + +} diff --git a/Source/WebCore/bindings/js/CachedScriptFetcher.h b/Source/WebCore/bindings/js/CachedScriptFetcher.h new file mode 100644 index 000000000..a1a82ce81 --- /dev/null +++ b/Source/WebCore/bindings/js/CachedScriptFetcher.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2017 Yusuke Suzuki <utatane.tea@gmail.com> + * + * 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. + */ + +#pragma once + +#include "CachedResourceHandle.h" +#include <runtime/ScriptFetcher.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class CachedScript; +class Document; +class URL; + +class CachedScriptFetcher : public JSC::ScriptFetcher { +public: + virtual CachedResourceHandle<CachedScript> requestModuleScript(Document&, const URL& sourceURL) const; + + static Ref<CachedScriptFetcher> create(const String& charset); + +protected: + CachedScriptFetcher(const String& nonce, const String& charset, const AtomicString& initiatorName, bool isInUserAgentShadowTree) + : m_nonce(nonce) + , m_charset(charset) + , m_initiatorName(initiatorName) + , m_isInUserAgentShadowTree(isInUserAgentShadowTree) + { + } + + CachedScriptFetcher(const String& charset) + : m_charset(charset) + { + } + + CachedResourceHandle<CachedScript> requestScriptWithCache(Document&, const URL& sourceURL, const String& crossOriginMode) const; + +private: + String m_nonce; + String m_charset; + AtomicString m_initiatorName; + bool m_isInUserAgentShadowTree { false }; +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/CachedScriptSourceProvider.h b/Source/WebCore/bindings/js/CachedScriptSourceProvider.h index b95fdc8ee..47494e7a6 100644 --- a/Source/WebCore/bindings/js/CachedScriptSourceProvider.h +++ b/Source/WebCore/bindings/js/CachedScriptSourceProvider.h @@ -23,12 +23,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef CachedScriptSourceProvider_h -#define CachedScriptSourceProvider_h +#pragma once #include "CachedResourceClient.h" #include "CachedResourceHandle.h" #include "CachedScript.h" +#include "CachedScriptFetcher.h" #include <parser/SourceCode.h> #include <parser/SourceProvider.h> @@ -37,31 +37,25 @@ namespace WebCore { class CachedScriptSourceProvider : public JSC::SourceProvider, public CachedResourceClient { WTF_MAKE_FAST_ALLOCATED; public: - static PassRefPtr<CachedScriptSourceProvider> create(CachedScript* cachedScript) { return adoptRef(new CachedScriptSourceProvider(cachedScript)); } + static Ref<CachedScriptSourceProvider> create(CachedScript* cachedScript, JSC::SourceProviderSourceType sourceType, Ref<CachedScriptFetcher>&& scriptFetcher) { return adoptRef(*new CachedScriptSourceProvider(cachedScript, sourceType, WTFMove(scriptFetcher))); } virtual ~CachedScriptSourceProvider() { - m_cachedScript->removeClient(this); + m_cachedScript->removeClient(*this); } - const String& source() const { return m_cachedScript->script(); } + unsigned hash() const override { return m_cachedScript->scriptHash(); } + StringView source() const override { return m_cachedScript->script(); } private: - CachedScriptSourceProvider(CachedScript* cachedScript) - : SourceProvider(cachedScript->response().url(), TextPosition::minimumPosition()) + CachedScriptSourceProvider(CachedScript* cachedScript, JSC::SourceProviderSourceType sourceType, Ref<CachedScriptFetcher>&& scriptFetcher) + : SourceProvider(JSC::SourceOrigin { cachedScript->response().url(), WTFMove(scriptFetcher) }, cachedScript->response().url(), TextPosition(), sourceType) , m_cachedScript(cachedScript) { - m_cachedScript->addClient(this); + m_cachedScript->addClient(*this); } CachedResourceHandle<CachedScript> m_cachedScript; }; -inline JSC::SourceCode makeSource(CachedScript* cachedScript) -{ - return JSC::SourceCode(CachedScriptSourceProvider::create(cachedScript)); -} - } // namespace WebCore - -#endif // CachedScriptSourceProvider_h diff --git a/Source/WebCore/bindings/js/CallbackFunction.cpp b/Source/WebCore/bindings/js/CallbackFunction.cpp deleted file mode 100644 index 145d0556b..000000000 --- a/Source/WebCore/bindings/js/CallbackFunction.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 deleted file mode 100644 index 2562ce97a..000000000 --- a/Source/WebCore/bindings/js/CallbackFunction.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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/CommonVM.cpp b/Source/WebCore/bindings/js/CommonVM.cpp new file mode 100644 index 000000000..0187e19c9 --- /dev/null +++ b/Source/WebCore/bindings/js/CommonVM.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2016 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. ``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 + * 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 "CommonVM.h" + +#include "ScriptController.h" +#include "Settings.h" +#include "WebCoreJSClientData.h" +#include <heap/HeapInlines.h> +#include "heap/MachineStackMarker.h" +#include <runtime/VM.h> +#include <wtf/MainThread.h> +#include <wtf/text/AtomicString.h> + +#if PLATFORM(IOS) +#include "WebCoreThreadInternal.h" +#endif + +using namespace JSC; + +namespace WebCore { + +VM* g_commonVMOrNull; + +VM& commonVMSlow() +{ + ASSERT(isMainThread()); + ASSERT(!g_commonVMOrNull); + + ScriptController::initializeThreading(); + g_commonVMOrNull = &VM::createLeaked(LargeHeap).leakRef(); + g_commonVMOrNull->heap.acquireAccess(); // At any time, we may do things that affect the GC. +#if !PLATFORM(IOS) + g_commonVMOrNull->setExclusiveThread(std::this_thread::get_id()); +#else + g_commonVMOrNull->heap.setRunLoop(WebThreadRunLoop()); + g_commonVMOrNull->heap.machineThreads().addCurrentThread(); +#endif + + g_commonVMOrNull->setGlobalConstRedeclarationShouldThrow(Settings::globalConstRedeclarationShouldThrow()); + + JSVMClientData::initNormalWorld(g_commonVMOrNull); + + return *g_commonVMOrNull; +} + +void addImpureProperty(const AtomicString& propertyName) +{ + commonVM().addImpureProperty(propertyName); +} + +} // namespace WebCore + diff --git a/Source/WebCore/bindings/js/JSTrackEventCustom.cpp b/Source/WebCore/bindings/js/CommonVM.h index 3142cb1e5..0505168cb 100644 --- a/Source/WebCore/bindings/js/JSTrackEventCustom.cpp +++ b/Source/WebCore/bindings/js/CommonVM.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,28 +23,28 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "config.h" +#pragma once -#if ENABLE(VIDEO_TRACK) +#include <wtf/Forward.h> -#include "JSTrackEvent.h" +namespace JSC { +class VM; +} -#include "JSTrackCustom.h" -#include "TrackBase.h" +namespace WebCore { -using namespace JSC; +WEBCORE_EXPORT extern JSC::VM* g_commonVMOrNull; -namespace WebCore { +WEBCORE_EXPORT JSC::VM& commonVMSlow(); -JSValue JSTrackEvent::track(ExecState* exec) const +inline JSC::VM& commonVM() { - TrackBase* track = impl().track(); - if (!track) - return jsNull(); - - return toJS(exec, globalObject(), track); + if (JSC::VM* result = g_commonVMOrNull) + return *result; + return commonVMSlow(); } +void addImpureProperty(const AtomicString&); + } // namespace WebCore -#endif diff --git a/Source/WebCore/bindings/js/DOMObjectHashTableMap.h b/Source/WebCore/bindings/js/DOMObjectHashTableMap.h deleted file mode 100644 index 13bf207b0..000000000 --- a/Source/WebCore/bindings/js/DOMObjectHashTableMap.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Apple Inc. All rights reserved. - * Copyright (C) 2007 Samuel Weinig <sam@webkit.org> - * Copyright (C) 2009 Google, Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef DOMObjectHashTableMap_h -#define DOMObjectHashTableMap_h - -#include <runtime/Lookup.h> -#include <wtf/HashMap.h> - -namespace JSC { - class VM; -} - -namespace WebCore { - -// Map from static HashTable instances to per-GlobalData ones. -class DOMObjectHashTableMap { -public: - static DOMObjectHashTableMap& mapFor(JSC::VM&); - - ~DOMObjectHashTableMap() - { - for (HashMap<const JSC::HashTable*, JSC::HashTable>::iterator iter = m_map.begin(); iter != m_map.end(); ++iter) - iter->value.deleteTable(); - } - - const JSC::HashTable& get(const JSC::HashTable& staticTable) - { - HashMap<const JSC::HashTable*, JSC::HashTable>::iterator iter = m_map.find(&staticTable); - if (iter != m_map.end()) - return iter->value; - return m_map.set(&staticTable, staticTable.copy()).iterator->value; - } - -private: - HashMap<const JSC::HashTable*, JSC::HashTable> m_map; -}; - -} // namespace WebCore - -#endif // DOMObjectHashTableMap_h diff --git a/Source/WebCore/bindings/js/DOMRequestState.h b/Source/WebCore/bindings/js/DOMRequestState.h deleted file mode 100644 index 3453f5b53..000000000 --- a/Source/WebCore/bindings/js/DOMRequestState.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2012 Michael Pruett <michael@68k.org> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef DOMRequestState_h -#define DOMRequestState_h - -#include "DOMWrapperWorld.h" -#include "Document.h" -#include "ScriptState.h" -#include "WorkerGlobalScope.h" - -#include <JavaScriptCore/APIShims.h> - -namespace WebCore { - -class ScriptExecutionContext; - -class DOMRequestState { -public: - explicit DOMRequestState(ScriptExecutionContext* scriptExecutionContext) - : m_scriptExecutionContext(scriptExecutionContext) - , m_exec(0) - { - if (m_scriptExecutionContext->isDocument()) { - Document* document = toDocument(m_scriptExecutionContext); - m_exec = execStateFromPage(mainThreadNormalWorld(), document->page()); - } else { - WorkerGlobalScope* workerGlobalScope = static_cast<WorkerGlobalScope*>(m_scriptExecutionContext); - m_exec = execStateFromWorkerGlobalScope(workerGlobalScope); - } - } - - void clear() - { - m_scriptExecutionContext = 0; - m_exec = 0; - } - - class Scope { - public: - explicit Scope(DOMRequestState& state) - : m_entryShim(state.exec()) - { - } - private: - JSC::APIEntryShim m_entryShim; - }; - - JSC::ExecState* exec() - { - return m_exec; - } - -private: - ScriptExecutionContext* m_scriptExecutionContext; - JSC::ExecState* m_exec; -}; - -} -#endif diff --git a/Source/WebCore/bindings/js/DOMWrapperWorld.cpp b/Source/WebCore/bindings/js/DOMWrapperWorld.cpp index c25efe24d..1187bc11e 100644 --- a/Source/WebCore/bindings/js/DOMWrapperWorld.cpp +++ b/Source/WebCore/bindings/js/DOMWrapperWorld.cpp @@ -21,6 +21,7 @@ #include "config.h" #include "DOMWrapperWorld.h" +#include "CommonVM.h" #include "JSDOMWindow.h" #include "ScriptController.h" #include "WebCoreJSClientData.h" @@ -30,20 +31,20 @@ using namespace JSC; namespace WebCore { -DOMWrapperWorld::DOMWrapperWorld(JSC::VM* vm, bool isNormal) +DOMWrapperWorld::DOMWrapperWorld(JSC::VM& vm, bool isNormal) : m_vm(vm) , m_isNormal(isNormal) { - VM::ClientData* clientData = m_vm->clientData; + VM::ClientData* clientData = m_vm.clientData; ASSERT(clientData); - static_cast<WebCoreJSClientData*>(clientData)->rememberWorld(*this); + static_cast<JSVMClientData*>(clientData)->rememberWorld(*this); } DOMWrapperWorld::~DOMWrapperWorld() { - VM::ClientData* clientData = m_vm->clientData; + VM::ClientData* clientData = m_vm.clientData; ASSERT(clientData); - static_cast<WebCoreJSClientData*>(clientData)->forgetWorld(*this); + static_cast<JSVMClientData*>(clientData)->forgetWorld(*this); // These items are created lazily. while (!m_scriptControllersWithWindowShells.isEmpty()) @@ -53,7 +54,6 @@ DOMWrapperWorld::~DOMWrapperWorld() void DOMWrapperWorld::clearWrappers() { m_wrappers.clear(); - m_stringCache.clear(); // These items are created lazily. while (!m_scriptControllersWithWindowShells.isEmpty()) @@ -64,13 +64,13 @@ DOMWrapperWorld& normalWorld(JSC::VM& vm) { VM::ClientData* clientData = vm.clientData; ASSERT(clientData); - return static_cast<WebCoreJSClientData*>(clientData)->normalWorld(); + return static_cast<JSVMClientData*>(clientData)->normalWorld(); } DOMWrapperWorld& mainThreadNormalWorld() { ASSERT(isMainThread()); - static DOMWrapperWorld& cachedNormalWorld = normalWorld(*JSDOMWindow::commonVM()); + static DOMWrapperWorld& cachedNormalWorld = normalWorld(commonVM()); return cachedNormalWorld; } diff --git a/Source/WebCore/bindings/js/DOMWrapperWorld.h b/Source/WebCore/bindings/js/DOMWrapperWorld.h index ac770129a..6eaec1000 100644 --- a/Source/WebCore/bindings/js/DOMWrapperWorld.h +++ b/Source/WebCore/bindings/js/DOMWrapperWorld.h @@ -19,56 +19,55 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef DOMWrapperWorld_h -#define DOMWrapperWorld_h +#pragma once #include "JSDOMGlobalObject.h" -#include <runtime/WeakGCMap.h> #include <wtf/Forward.h> namespace WebCore { -class CSSValue; -class JSDOMWrapper; +class DeprecatedCSSOMValue; class ScriptController; typedef HashMap<void*, JSC::Weak<JSC::JSObject>> DOMObjectWrapperMap; -typedef JSC::WeakGCMap<StringImpl*, JSC::JSString, PtrHash<StringImpl*>> JSStringCache; class DOMWrapperWorld : public RefCounted<DOMWrapperWorld> { public: - static PassRefPtr<DOMWrapperWorld> create(JSC::VM* vm, bool isNormal = false) + static Ref<DOMWrapperWorld> create(JSC::VM& vm, bool isNormal = false) { - return adoptRef(new DOMWrapperWorld(vm, isNormal)); + return adoptRef(*new DOMWrapperWorld(vm, isNormal)); } - ~DOMWrapperWorld(); + WEBCORE_EXPORT ~DOMWrapperWorld(); // Free as much memory held onto by this world as possible. - void clearWrappers(); + WEBCORE_EXPORT void clearWrappers(); void didCreateWindowShell(ScriptController* scriptController) { m_scriptControllersWithWindowShells.add(scriptController); } void didDestroyWindowShell(ScriptController* scriptController) { m_scriptControllersWithWindowShells.remove(scriptController); } + void setShadowRootIsAlwaysOpen() { m_shadowRootIsAlwaysOpen = true; } + bool shadowRootIsAlwaysOpen() const { return m_shadowRootIsAlwaysOpen; } + // FIXME: can we make this private? DOMObjectWrapperMap m_wrappers; - JSStringCache m_stringCache; - HashMap<CSSValue*, void*> m_cssValueRoots; + HashMap<DeprecatedCSSOMValue*, void*> m_deprecatedCSSOMValueRoots; bool isNormal() const { return m_isNormal; } - JSC::VM* vm() const { return m_vm; } + JSC::VM& vm() const { return m_vm; } protected: - DOMWrapperWorld(JSC::VM*, bool isNormal); + DOMWrapperWorld(JSC::VM&, bool isNormal); private: - JSC::VM* m_vm; + JSC::VM& m_vm; HashSet<ScriptController*> m_scriptControllersWithWindowShells; bool m_isNormal; + bool m_shadowRootIsAlwaysOpen { false }; }; DOMWrapperWorld& normalWorld(JSC::VM&); -DOMWrapperWorld& mainThreadNormalWorld(); +WEBCORE_EXPORT DOMWrapperWorld& mainThreadNormalWorld(); inline DOMWrapperWorld& debuggerWorld() { return mainThreadNormalWorld(); } inline DOMWrapperWorld& pluginWorld() { return mainThreadNormalWorld(); } @@ -77,6 +76,9 @@ inline DOMWrapperWorld& currentWorld(JSC::ExecState* exec) return JSC::jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())->world(); } +inline DOMWrapperWorld& worldForDOMObject(JSC::JSObject* object) +{ + return JSC::jsCast<JSDOMGlobalObject*>(object->globalObject())->world(); +} + } // namespace WebCore - -#endif // DOMWrapperWorld_h diff --git a/Source/WebCore/bindings/js/Dictionary.cpp b/Source/WebCore/bindings/js/Dictionary.cpp deleted file mode 100644 index 39ac466fa..000000000 --- a/Source/WebCore/bindings/js/Dictionary.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2012 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 COMPUTER, INC. ``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 COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "Dictionary.h" - -#if ENABLE(NOTIFICATIONS) -#include "JSNotification.h" -#include "Notification.h" -#endif - -using namespace JSC; - -namespace WebCore { - -Dictionary::Dictionary() - : m_dictionary(0, 0) -{ -} - -Dictionary::Dictionary(JSC::ExecState* exec, JSC::JSValue value) - : m_dictionary(exec, value.isObject() ? value.getObject() : 0) -{ -} - - -#if ENABLE(NOTIFICATIONS) -template<> -JSObject* Dictionary::asJSObject<Notification>(Notification* object) const -{ - return asObject(toJS(m_dictionary.execState(), jsCast<JSDOMGlobalObject*>(m_dictionary.execState()->lexicalGlobalObject()), object)); -} -#endif - -bool Dictionary::getOwnPropertiesAsStringHashMap(HashMap<String, String>& map) const -{ - if (!m_dictionary.isValid()) - return false; - - JSObject* object = m_dictionary.initializerObject(); - ExecState* exec = m_dictionary.execState(); - - PropertyNameArray propertyNames(exec); - JSObject::getOwnPropertyNames(object, exec, propertyNames, ExcludeDontEnumProperties); - for (PropertyNameArray::const_iterator it = propertyNames.begin(); it != propertyNames.end(); ++it) { - String stringKey = it->string(); - if (stringKey.isEmpty()) - continue; - JSValue value = object->get(exec, *it); - if (exec->hadException()) - continue; - String stringValue = value.toString(exec)->value(exec); - if (!exec->hadException()) - map.set(stringKey, stringValue); - } - - return true; -} - -bool Dictionary::getOwnPropertyNames(Vector<String>& names) const -{ - if (!m_dictionary.isValid()) - return false; - - JSObject* object = m_dictionary.initializerObject(); - ExecState* exec = m_dictionary.execState(); - - PropertyNameArray propertyNames(exec); - JSObject::getOwnPropertyNames(object, exec, propertyNames, ExcludeDontEnumProperties); - for (PropertyNameArray::const_iterator it = propertyNames.begin(); it != propertyNames.end(); ++it) { - String stringKey = it->string(); - if (!stringKey.isEmpty()) - names.append(stringKey); - } - - return true; -} - -bool Dictionary::getWithUndefinedOrNullCheck(const String& propertyName, String& value) const -{ - return m_dictionary.getWithUndefinedOrNullCheck(propertyName, value); -} - -}; diff --git a/Source/WebCore/bindings/js/Dictionary.h b/Source/WebCore/bindings/js/Dictionary.h deleted file mode 100644 index fd4bee579..000000000 --- a/Source/WebCore/bindings/js/Dictionary.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * Copyright (C) 2012 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 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 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 Dictionary_h -#define Dictionary_h - -#include "JSDictionary.h" -#include "JSEventListener.h" -#include "NotImplemented.h" -#include <bindings/ScriptValue.h> -#include <wtf/HashMap.h> -#include <wtf/text/CString.h> -#include <wtf/text/WTFString.h> - -namespace JSC { -class JSValue; -} - -namespace WebCore { -class EventListener; - -class Dictionary { -public: - Dictionary(); - Dictionary(JSC::ExecState*, JSC::JSValue); - - // Returns true if a value was found for the provided property. - template <typename Result> - bool get(const char* propertyName, Result&) const; - template <typename Result> - bool get(const String& propertyName, Result&) const; - - template <typename T> - PassRefPtr<EventListener> getEventListener(const char* propertyName, T* target) const; - template <typename T> - PassRefPtr<EventListener> getEventListener(const String& propertyName, T* target) const; - - bool isObject() const { return m_dictionary.isValid(); } - bool isUndefinedOrNull() const { return !m_dictionary.isValid(); } - bool getOwnPropertiesAsStringHashMap(HashMap<String, String>&) const; - bool getOwnPropertyNames(Vector<String>&) const; - bool getWithUndefinedOrNullCheck(const String& propertyName, String& value) const; - -private: - template <typename T> - JSC::JSObject* asJSObject(T*) const; - - JSDictionary m_dictionary; -}; - -template <typename Result> -bool Dictionary::get(const char* propertyName, Result& result) const -{ - if (!m_dictionary.isValid()) - return false; - - return m_dictionary.get(propertyName, result); -} - -template <typename Result> -bool Dictionary::get(const String& propertyName, Result& result) const -{ - return get(propertyName.utf8().data(), result); -} - -template <typename T> -PassRefPtr<EventListener> Dictionary::getEventListener(const char* propertyName, T* target) const -{ - if (!m_dictionary.isValid()) - return 0; - - Deprecated::ScriptValue eventListener; - if (!m_dictionary.tryGetProperty(propertyName, eventListener)) - return 0; - if (eventListener.hasNoValue()) - return 0; - if (!eventListener.isObject()) - return 0; - - return JSEventListener::create(asObject(eventListener.jsValue()), asJSObject(target), true, currentWorld(m_dictionary.execState())); -} - -template <typename T> -PassRefPtr<EventListener> Dictionary::getEventListener(const String& propertyName, T* target) const -{ - return getEventListener(propertyName.utf8().data(), target); -} - -} - -#endif // Dictionary_h diff --git a/Source/WebCore/bindings/js/GCController.cpp b/Source/WebCore/bindings/js/GCController.cpp index ba70d4a06..6f9fca67f 100644 --- a/Source/WebCore/bindings/js/GCController.cpp +++ b/Source/WebCore/bindings/js/GCController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2014, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,11 +26,13 @@ #include "config.h" #include "GCController.h" -#include "JSDOMWindow.h" +#include "CommonVM.h" #include <runtime/VM.h> #include <runtime/JSLock.h> #include <heap/Heap.h> #include <wtf/StdLibExtras.h> +#include <wtf/FastMalloc.h> +#include <wtf/NeverDestroyed.h> using namespace JSC; @@ -38,57 +40,63 @@ namespace WebCore { static void collect(void*) { - JSLockHolder lock(JSDOMWindow::commonVM()); - JSDOMWindow::commonVM()->heap.collectAllGarbage(); + JSLockHolder lock(commonVM()); + commonVM().heap.collectAllGarbage(); } -GCController& gcController() +GCController& GCController::singleton() { - DEFINE_STATIC_LOCAL(GCController, staticGCController, ()); - return staticGCController; + static NeverDestroyed<GCController> controller; + return controller; } GCController::GCController() -#if !USE(CF) - : m_GCTimer(this, &GCController::gcTimerFired) -#endif + : m_GCTimer(*this, &GCController::gcTimerFired) { } void GCController::garbageCollectSoon() { - // We only use reportAbandonedObjectGraph on systems with CoreFoundation - // since it uses a runloop-based timer that is currently only available on - // systems with CoreFoundation. If and when the notion of a run loop is pushed - // down into WTF so that more platforms can take advantage of it, we will be - // able to use reportAbandonedObjectGraph on more platforms. -#if USE(CF) - JSLockHolder lock(JSDOMWindow::commonVM()); - JSDOMWindow::commonVM()->heap.reportAbandonedObjectGraph(); + // We only use reportAbandonedObjectGraph for systems for which there's an implementation + // of the garbage collector timers in JavaScriptCore. We wouldn't need this if JavaScriptCore + // used a timer implementation from WTF like RunLoop::Timer. +#if USE(CF) || USE(GLIB) + JSLockHolder lock(commonVM()); + commonVM().heap.reportAbandonedObjectGraph(); #else + garbageCollectOnNextRunLoop(); +#endif +} + +void GCController::garbageCollectOnNextRunLoop() +{ if (!m_GCTimer.isActive()) m_GCTimer.startOneShot(0); -#endif } -#if !USE(CF) -void GCController::gcTimerFired(Timer<GCController>*) +void GCController::gcTimerFired() { - collect(0); + collect(nullptr); } -#endif void GCController::garbageCollectNow() { - JSLockHolder lock(JSDOMWindow::commonVM()); -#if PLATFORM(IOS) - // If JavaScript was never run in this process, there's no need to call GC which will - // end up creating a VM unnecessarily. - if (!JSDOMWindow::commonVMExists()) - return; + JSLockHolder lock(commonVM()); + if (!commonVM().heap.isCurrentThreadBusy()) { + commonVM().heap.collectAllGarbage(); + WTF::releaseFastMallocFreeMemory(); + } +} + +void GCController::garbageCollectNowIfNotDoneRecently() +{ +#if USE(CF) || USE(GLIB) + JSLockHolder lock(commonVM()); + if (!commonVM().heap.isCurrentThreadBusy()) + commonVM().heap.collectAllGarbageIfNotDoneRecently(); +#else + garbageCollectSoon(); #endif - if (!JSDOMWindow::commonVM()->heap.isBusy()) - JSDOMWindow::commonVM()->heap.collectAllGarbage(); } void GCController::garbageCollectOnAlternateThreadForDebugging(bool waitUntilDone) @@ -103,37 +111,21 @@ void GCController::garbageCollectOnAlternateThreadForDebugging(bool waitUntilDon detachThread(threadID); } -void GCController::releaseExecutableMemory() +void GCController::setJavaScriptGarbageCollectorTimerEnabled(bool enable) { - JSLockHolder lock(JSDOMWindow::commonVM()); - -#if PLATFORM(IOS) - // If JavaScript was never run in this process, there's no need to call GC which will - // end up creating a VM unnecessarily. - if (!JSDOMWindow::commonVMExists()) - return; -#endif - - // We shouldn't have any javascript running on our stack when this function is called. The - // following line asserts that. - ASSERT(!JSDOMWindow::commonVM()->entryScope); - - // But be safe in release builds just in case... - if (JSDOMWindow::commonVM()->entryScope) - return; - - JSDOMWindow::commonVM()->releaseExecutableMemory(); + commonVM().heap.setGarbageCollectionTimerEnabled(enable); } -void GCController::setJavaScriptGarbageCollectorTimerEnabled(bool enable) +void GCController::deleteAllCode(DeleteAllCodeEffort effort) { - JSDOMWindow::commonVM()->heap.setGarbageCollectionTimerEnabled(enable); + JSLockHolder lock(commonVM()); + commonVM().deleteAllCode(effort); } -void GCController::discardAllCompiledCode() +void GCController::deleteAllLinkedCode(DeleteAllCodeEffort effort) { - JSLockHolder lock(JSDOMWindow::commonVM()); - JSDOMWindow::commonVM()->discardAllCode(); + JSLockHolder lock(commonVM()); + commonVM().deleteAllLinkedCode(effort); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/GCController.h b/Source/WebCore/bindings/js/GCController.h index 7db5c3058..b948c3968 100644 --- a/Source/WebCore/bindings/js/GCController.h +++ b/Source/WebCore/bindings/js/GCController.h @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,43 +23,36 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef GCController_h -#define GCController_h +#pragma once -#if USE(CF) -#include <wtf/FastMalloc.h> +#include <heap/DeleteAllCodeEffort.h> +#include <wtf/Forward.h> #include <wtf/Noncopyable.h> -#else #include "Timer.h" -#endif namespace WebCore { - class GCController { - WTF_MAKE_NONCOPYABLE(GCController); WTF_MAKE_FAST_ALLOCATED; - friend GCController& gcController(); +class GCController { + WTF_MAKE_NONCOPYABLE(GCController); + friend class WTF::NeverDestroyed<GCController>; +public: + WEBCORE_EXPORT static GCController& singleton(); - public: - void garbageCollectSoon(); - void garbageCollectNow(); // It's better to call garbageCollectSoon, unless you have a specific reason not to. + WEBCORE_EXPORT void garbageCollectSoon(); + WEBCORE_EXPORT void garbageCollectNow(); // It's better to call garbageCollectSoon, unless you have a specific reason not to. + WEBCORE_EXPORT void garbageCollectNowIfNotDoneRecently(); + void garbageCollectOnNextRunLoop(); - void garbageCollectOnAlternateThreadForDebugging(bool waitUntilDone); // Used for stress testing. - void releaseExecutableMemory(); - void setJavaScriptGarbageCollectorTimerEnabled(bool); - void discardAllCompiledCode(); + WEBCORE_EXPORT void garbageCollectOnAlternateThreadForDebugging(bool waitUntilDone); // Used for stress testing. + WEBCORE_EXPORT void setJavaScriptGarbageCollectorTimerEnabled(bool); + WEBCORE_EXPORT void deleteAllCode(JSC::DeleteAllCodeEffort); + WEBCORE_EXPORT void deleteAllLinkedCode(JSC::DeleteAllCodeEffort); - private: - GCController(); // Use gcController() instead +private: + GCController(); // Use singleton() instead. -#if !USE(CF) - void gcTimerFired(Timer<GCController>*); - Timer<GCController> m_GCTimer; -#endif - }; - - // Function to obtain the global GC controller. - GCController& gcController() PURE_FUNCTION; + void gcTimerFired(); + Timer m_GCTimer; +}; } // namespace WebCore - -#endif // GCController_h diff --git a/Source/WebCore/bindings/js/IDBBindingUtilities.cpp b/Source/WebCore/bindings/js/IDBBindingUtilities.cpp index 7a77db444..8fee1e297 100644 --- a/Source/WebCore/bindings/js/IDBBindingUtilities.cpp +++ b/Source/WebCore/bindings/js/IDBBindingUtilities.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2010 Google Inc. All rights reserved. * Copyright (C) 2012 Michael Pruett <michael@68k.org> + * Copyright (C) 2014, 2015, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,14 +28,25 @@ #include "config.h" #if ENABLE(INDEXED_DATABASE) + #include "IDBBindingUtilities.h" -#include "DOMRequestState.h" +#include "IDBIndexInfo.h" #include "IDBKey.h" +#include "IDBKeyData.h" #include "IDBKeyPath.h" +#include "IDBValue.h" +#include "IndexKey.h" +#include "JSDOMBinding.h" +#include "JSDOMConvert.h" +#include "JSDOMStringList.h" #include "Logging.h" +#include "MessagePort.h" +#include "ScriptExecutionContext.h" +#include "SerializedScriptValue.h" #include "SharedBuffer.h" - +#include "ThreadSafeDataBuffer.h" +#include <runtime/ArrayBuffer.h> #include <runtime/DateInstance.h> #include <runtime/ObjectConstructor.h> @@ -42,18 +54,18 @@ using namespace JSC; namespace WebCore { -static bool get(ExecState* exec, JSValue object, const String& keyPathElement, JSValue& result) +static bool get(ExecState& exec, JSValue object, const String& keyPathElement, JSValue& result) { if (object.isString() && keyPathElement == "length") { - result = jsNumber(object.toString(exec)->length()); + result = jsNumber(asString(object)->length()); return true; } if (!object.isObject()) return false; - Identifier identifier(&exec->vm(), keyPathElement.utf8().data()); - if (!asObject(object)->hasProperty(exec, identifier)) + Identifier identifier = Identifier::fromString(&exec.vm(), keyPathElement); + if (!asObject(object)->hasProperty(&exec, identifier)) return false; - result = asObject(object)->get(exec, identifier); + result = asObject(object)->get(&exec, identifier); return true; } @@ -63,43 +75,64 @@ static bool canSet(JSValue object, const String& keyPathElement) return object.isObject(); } -static bool set(ExecState* exec, JSValue& object, const String& keyPathElement, JSValue jsValue) +static bool set(ExecState& exec, JSValue& object, const String& keyPathElement, JSValue jsValue) { if (!canSet(object, keyPathElement)) return false; - Identifier identifier(&exec->vm(), keyPathElement.utf8().data()); - asObject(object)->putDirect(exec->vm(), identifier, jsValue); + Identifier identifier = Identifier::fromString(&exec.vm(), keyPathElement); + asObject(object)->putDirect(exec.vm(), identifier, jsValue); return true; } -static JSValue idbKeyToJSValue(ExecState* exec, JSDOMGlobalObject* globalObject, IDBKey* key) +JSValue toJS(ExecState& state, JSGlobalObject& globalObject, IDBKey* key) { if (!key) { - // This should be undefined, not null. + // This must be undefined, not null. // Spec: http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBKeyRange return jsUndefined(); } + VM& vm = state.vm(); + Locker<JSLock> locker(vm.apiLock()); + auto scope = DECLARE_THROW_SCOPE(vm); + switch (key->type()) { - case IDBKey::ArrayType: - { - const IDBKey::KeyArray& inArray = key->array(); - size_t size = inArray.size(); - JSArray* outArray = constructEmptyArray(exec, 0, globalObject, size); - for (size_t i = 0; i < size; ++i) { - IDBKey* arrayKey = inArray.at(i).get(); - outArray->putDirectIndex(exec, i, idbKeyToJSValue(exec, globalObject, arrayKey)); - } - return JSValue(outArray); + case KeyType::Array: { + auto& inArray = key->array(); + unsigned size = inArray.size(); + auto outArray = constructEmptyArray(&state, 0, &globalObject, size); + RETURN_IF_EXCEPTION(scope, JSValue()); + for (size_t i = 0; i < size; ++i) { + outArray->putDirectIndex(&state, i, toJS(state, globalObject, inArray.at(i).get())); + RETURN_IF_EXCEPTION(scope, JSValue()); + } + return outArray; + } + case KeyType::Binary: { + auto* data = key->binary().data(); + if (!data) { + ASSERT_NOT_REACHED(); + return jsNull(); } - case IDBKey::StringType: - return jsStringWithCache(exec, key->string()); - case IDBKey::DateType: - return jsDateOrNull(exec, key->date()); - case IDBKey::NumberType: + + auto arrayBuffer = ArrayBuffer::create(data->data(), data->size()); + Structure* structure = globalObject.arrayBufferStructure(arrayBuffer->sharingMode()); + if (!structure) + return jsNull(); + + return JSArrayBuffer::create(state.vm(), structure, WTFMove(arrayBuffer)); + } + case KeyType::String: + return jsStringWithCache(&state, key->string()); + case KeyType::Date: + // FIXME: This should probably be toJS<IDLDate>(...) as per: + // http://w3c.github.io/IndexedDB/#request-convert-a-key-to-a-value + return toJS<IDLNullable<IDLDate>>(state, key->date()); + case KeyType::Number: return jsNumber(key->number()); - case IDBKey::MinType: - case IDBKey::InvalidType: + case KeyType::Min: + case KeyType::Max: + case KeyType::Invalid: ASSERT_NOT_REACHED(); return jsUndefined(); } @@ -110,29 +143,38 @@ static JSValue idbKeyToJSValue(ExecState* exec, JSDOMGlobalObject* globalObject, static const size_t maximumDepth = 2000; -static PassRefPtr<IDBKey> createIDBKeyFromValue(ExecState* exec, JSValue value, Vector<JSArray*>& stack) +static RefPtr<IDBKey> createIDBKeyFromValue(ExecState& exec, JSValue value, Vector<JSArray*>& stack) { - if (value.isNumber() && !std::isnan(value.toNumber(exec))) - return IDBKey::createNumber(value.toNumber(exec)); + VM& vm = exec.vm(); + if (value.isNumber() && !std::isnan(value.toNumber(&exec))) + return IDBKey::createNumber(value.toNumber(&exec)); + if (value.isString()) - return IDBKey::createString(value.toString(exec)->value(exec)); - if (value.inherits(DateInstance::info()) && !std::isnan(valueToDate(exec, value))) - return IDBKey::createDate(valueToDate(exec, value)); + return IDBKey::createString(asString(value)->value(&exec)); + + if (value.inherits(vm, DateInstance::info())) { + auto dateValue = valueToDate(exec, value); + if (!std::isnan(dateValue)) + return IDBKey::createDate(dateValue); + } + if (value.isObject()) { JSObject* object = asObject(value); - if (isJSArray(object) || object->inherits(JSArray::info())) { + if (isJSArray(object) || object->inherits(vm, JSArray::info())) { JSArray* array = asArray(object); size_t length = array->length(); if (stack.contains(array)) - return 0; + return nullptr; + if (stack.size() >= maximumDepth) - return 0; + return nullptr; + stack.append(array); - IDBKey::KeyArray subkeys; + Vector<RefPtr<IDBKey>> subkeys; for (size_t i = 0; i < length; i++) { - JSValue item = array->getIndex(exec, i); + JSValue item = array->getIndex(&exec, i); RefPtr<IDBKey> subkey = createIDBKeyFromValue(exec, item, stack); if (!subkey) subkeys.append(IDBKey::createInvalid()); @@ -143,30 +185,26 @@ static PassRefPtr<IDBKey> createIDBKeyFromValue(ExecState* exec, JSValue value, stack.removeLast(); return IDBKey::createArray(subkeys); } + + if (auto* arrayBuffer = jsDynamicCast<JSArrayBuffer*>(vm, value)) + return IDBKey::createBinary(*arrayBuffer); + + if (auto* arrayBufferView = jsDynamicCast<JSArrayBufferView*>(vm, value)) + return IDBKey::createBinary(*arrayBufferView); } - return 0; + return nullptr; } -static PassRefPtr<IDBKey> createIDBKeyFromValue(ExecState* exec, JSValue value) +static Ref<IDBKey> createIDBKeyFromValue(ExecState& exec, JSValue value) { Vector<JSArray*> stack; RefPtr<IDBKey> key = createIDBKeyFromValue(exec, value, stack); if (key) - return key; + return *key; return IDBKey::createInvalid(); } -IDBKeyPath idbKeyPathFromValue(ExecState* exec, JSValue keyPathValue) -{ - IDBKeyPath keyPath; - if (isJSArray(keyPathValue)) - keyPath = IDBKeyPath(toNativeArray<String>(exec, keyPathValue)); - else - keyPath = IDBKeyPath(keyPathValue.toString(exec)->value(exec)); - return keyPath; -} - -static JSValue getNthValueOnKeyPath(ExecState* exec, JSValue rootValue, const Vector<String>& keyPathElements, size_t index) +static JSValue getNthValueOnKeyPath(ExecState& exec, JSValue rootValue, const Vector<String>& keyPathElements, size_t index) { JSValue currentValue(rootValue); ASSERT(index <= keyPathElements.size()); @@ -178,21 +216,21 @@ static JSValue getNthValueOnKeyPath(ExecState* exec, JSValue rootValue, const Ve return currentValue; } -static PassRefPtr<IDBKey> createIDBKeyFromScriptValueAndKeyPath(ExecState* exec, const Deprecated::ScriptValue& value, const String& keyPath) +static RefPtr<IDBKey> internalCreateIDBKeyFromScriptValueAndKeyPath(ExecState& exec, const JSValue& value, const String& keyPath) { Vector<String> keyPathElements; IDBKeyPathParseError error; IDBParseKeyPath(keyPath, keyPathElements, error); - ASSERT(error == IDBKeyPathParseErrorNone); + ASSERT(error == IDBKeyPathParseError::None); - JSValue jsValue = value.jsValue(); + JSValue jsValue = value; jsValue = getNthValueOnKeyPath(exec, jsValue, keyPathElements, keyPathElements.size()); if (jsValue.isUndefined()) - return 0; + return nullptr; return createIDBKeyFromValue(exec, jsValue); } -static JSValue ensureNthValueOnKeyPath(ExecState* exec, JSValue rootValue, const Vector<String>& keyPathElements, size_t index) +static JSValue ensureNthValueOnKeyPath(ExecState& exec, JSValue rootValue, const Vector<String>& keyPathElements, size_t index) { JSValue currentValue(rootValue); @@ -201,7 +239,7 @@ static JSValue ensureNthValueOnKeyPath(ExecState* exec, JSValue rootValue, const JSValue parentValue(currentValue); const String& keyPathElement = keyPathElements[i]; if (!get(exec, parentValue, keyPathElement, currentValue)) { - JSObject* object = constructEmptyObject(exec); + JSObject* object = constructEmptyObject(&exec); if (!set(exec, parentValue, keyPathElement, JSValue(object))) return jsUndefined(); currentValue = JSValue(object); @@ -211,7 +249,7 @@ static JSValue ensureNthValueOnKeyPath(ExecState* exec, JSValue rootValue, const return currentValue; } -static bool canInjectNthValueOnKeyPath(ExecState* exec, JSValue rootValue, const Vector<String>& keyPathElements, size_t index) +static bool canInjectNthValueOnKeyPath(ExecState& exec, JSValue rootValue, const Vector<String>& keyPathElements, size_t index) { if (!rootValue.isObject()) return false; @@ -228,105 +266,151 @@ static bool canInjectNthValueOnKeyPath(ExecState* exec, JSValue rootValue, const return true; } -bool injectIDBKeyIntoScriptValue(DOMRequestState* requestState, PassRefPtr<IDBKey> key, Deprecated::ScriptValue& value, const IDBKeyPath& keyPath) +bool injectIDBKeyIntoScriptValue(ExecState& exec, const IDBKeyData& keyData, JSValue value, const IDBKeyPath& keyPath) { - LOG(StorageAPI, "injectIDBKeyIntoScriptValue"); + LOG(IndexedDB, "injectIDBKeyIntoScriptValue"); - ASSERT(keyPath.type() == IDBKeyPath::StringType); + ASSERT(WTF::holds_alternative<String>(keyPath)); Vector<String> keyPathElements; IDBKeyPathParseError error; - IDBParseKeyPath(keyPath.string(), keyPathElements, error); - ASSERT(error == IDBKeyPathParseErrorNone); + IDBParseKeyPath(WTF::get<String>(keyPath), keyPathElements, error); + ASSERT(error == IDBKeyPathParseError::None); if (keyPathElements.isEmpty()) return false; - ExecState* exec = requestState->exec(); - - JSValue parent = ensureNthValueOnKeyPath(exec, value.jsValue(), keyPathElements, keyPathElements.size() - 1); + JSValue parent = ensureNthValueOnKeyPath(exec, value, keyPathElements, keyPathElements.size() - 1); if (parent.isUndefined()) return false; - if (!set(exec, parent, keyPathElements.last(), idbKeyToJSValue(exec, jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), key.get()))) + auto key = keyData.maybeCreateIDBKey(); + if (!key) + return false; + + if (!set(exec, parent, keyPathElements.last(), toJS(exec, *exec.lexicalGlobalObject(), key.get()))) return false; return true; } -PassRefPtr<IDBKey> createIDBKeyFromScriptValueAndKeyPath(DOMRequestState* requestState, const Deprecated::ScriptValue& value, const IDBKeyPath& keyPath) -{ - LOG(StorageAPI, "createIDBKeyFromScriptValueAndKeyPath"); - ASSERT(!keyPath.isNull()); - ExecState* exec = requestState->exec(); - - if (keyPath.type() == IDBKeyPath::ArrayType) { - IDBKey::KeyArray result; - const Vector<String>& array = keyPath.array(); - for (size_t i = 0; i < array.size(); i++) { - RefPtr<IDBKey> key = createIDBKeyFromScriptValueAndKeyPath(exec, value, array[i]); +RefPtr<IDBKey> maybeCreateIDBKeyFromScriptValueAndKeyPath(ExecState& exec, const JSValue& value, const IDBKeyPath& keyPath) +{ + if (WTF::holds_alternative<Vector<String>>(keyPath)) { + auto& array = WTF::get<Vector<String>>(keyPath); + Vector<RefPtr<IDBKey>> result; + result.reserveInitialCapacity(array.size()); + for (auto& string : array) { + RefPtr<IDBKey> key = internalCreateIDBKeyFromScriptValueAndKeyPath(exec, value, string); if (!key) - return 0; - result.append(key); + return nullptr; + result.uncheckedAppend(WTFMove(key)); } - return IDBKey::createArray(result); + return IDBKey::createArray(WTFMove(result)); } - ASSERT(keyPath.type() == IDBKeyPath::StringType); - return createIDBKeyFromScriptValueAndKeyPath(exec, value, keyPath.string()); + return internalCreateIDBKeyFromScriptValueAndKeyPath(exec, value, WTF::get<String>(keyPath)); } -bool canInjectIDBKeyIntoScriptValue(DOMRequestState* requestState, const Deprecated::ScriptValue& scriptValue, const IDBKeyPath& keyPath) +bool canInjectIDBKeyIntoScriptValue(ExecState& exec, const JSValue& scriptValue, const IDBKeyPath& keyPath) { LOG(StorageAPI, "canInjectIDBKeyIntoScriptValue"); - ASSERT(keyPath.type() == IDBKeyPath::StringType); + ASSERT(WTF::holds_alternative<String>(keyPath)); Vector<String> keyPathElements; IDBKeyPathParseError error; - IDBParseKeyPath(keyPath.string(), keyPathElements, error); - ASSERT(error == IDBKeyPathParseErrorNone); + IDBParseKeyPath(WTF::get<String>(keyPath), keyPathElements, error); + ASSERT(error == IDBKeyPathParseError::None); if (!keyPathElements.size()) return false; - JSC::ExecState* exec = requestState->exec(); - return canInjectNthValueOnKeyPath(exec, scriptValue.jsValue(), keyPathElements, keyPathElements.size() - 1); + return canInjectNthValueOnKeyPath(exec, scriptValue, keyPathElements, keyPathElements.size() - 1); +} + +static JSValue deserializeIDBValueToJSValue(ExecState& state, JSC::JSGlobalObject& globalObject, const IDBValue& value) +{ + // FIXME: I think it's peculiar to use undefined to mean "null data" and null to mean "empty data". + // But I am not changing this at the moment because at least some callers are specifically checking isUndefined. + + if (!value.data().data()) + return jsUndefined(); + + auto& data = *value.data().data(); + if (data.isEmpty()) + return jsNull(); + + auto serializedValue = SerializedScriptValue::createFromWireBytes(Vector<uint8_t>(data)); + + state.vm().apiLock().lock(); + Vector<RefPtr<MessagePort>> messagePorts; + JSValue result = serializedValue->deserialize(state, &globalObject, messagePorts, value.blobURLs(), value.blobFilePaths(), SerializationErrorMode::NonThrowing); + state.vm().apiLock().unlock(); + + return result; } -Deprecated::ScriptValue deserializeIDBValue(DOMRequestState* requestState, PassRefPtr<SerializedScriptValue> prpValue) +JSValue deserializeIDBValueToJSValue(ExecState& state, const IDBValue& value) { - ExecState* exec = requestState->exec(); - RefPtr<SerializedScriptValue> serializedValue = prpValue; - if (serializedValue) - return SerializedScriptValue::deserialize(exec, serializedValue.get(), NonThrowing); - return Deprecated::ScriptValue(exec->vm(), jsNull()); + return deserializeIDBValueToJSValue(state, *state.lexicalGlobalObject(), value); } -Deprecated::ScriptValue deserializeIDBValueBuffer(DOMRequestState* requestState, PassRefPtr<SharedBuffer> prpBuffer) +JSC::JSValue toJS(JSC::ExecState* state, JSDOMGlobalObject* globalObject, const IDBValue& value) { - ExecState* exec = requestState->exec(); - RefPtr<SharedBuffer> buffer = prpBuffer; - if (buffer) { - // FIXME: The extra copy here can be eliminated by allowing SerializedScriptValue to take a raw const char* or const uint8_t*. - Vector<uint8_t> value; - value.append(buffer->data(), buffer->size()); - RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::createFromWireBytes(value); - return SerializedScriptValue::deserialize(exec, serializedValue.get(), NonThrowing); - } - return Deprecated::ScriptValue(exec->vm(), jsNull()); + ASSERT(state); + return deserializeIDBValueToJSValue(*state, *globalObject, value); } -Deprecated::ScriptValue idbKeyToScriptValue(DOMRequestState* requestState, PassRefPtr<IDBKey> key) +Ref<IDBKey> scriptValueToIDBKey(ExecState& exec, const JSValue& scriptValue) { - ExecState* exec = requestState->exec(); - return Deprecated::ScriptValue(exec->vm(), idbKeyToJSValue(exec, jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()), key.get())); + return createIDBKeyFromValue(exec, scriptValue); } -PassRefPtr<IDBKey> scriptValueToIDBKey(DOMRequestState* requestState, const Deprecated::ScriptValue& scriptValue) +JSC::JSValue toJS(JSC::ExecState* state, JSDOMGlobalObject* globalObject, const IDBKeyData& keyData) { - ExecState* exec = requestState->exec(); - return createIDBKeyFromValue(exec, scriptValue.jsValue()); + ASSERT(state); + ASSERT(globalObject); + + return toJS(*state, *globalObject, keyData.maybeCreateIDBKey().get()); +} + +static Vector<IDBKeyData> createKeyPathArray(ExecState& exec, JSValue value, const IDBIndexInfo& info) +{ + auto visitor = WTF::makeVisitor([&](const String& string) -> Vector<IDBKeyData> { + auto idbKey = internalCreateIDBKeyFromScriptValueAndKeyPath(exec, value, string); + if (!idbKey) + return { }; + + Vector<IDBKeyData> keys; + if (info.multiEntry() && idbKey->type() == IndexedDB::Array) { + for (auto& key : idbKey->array()) + keys.append(key.get()); + } else + keys.append(idbKey.get()); + return keys; + }, [&](const Vector<String>& vector) -> Vector<IDBKeyData> { + Vector<IDBKeyData> keys; + for (auto& entry : vector) { + auto key = internalCreateIDBKeyFromScriptValueAndKeyPath(exec, value, entry); + if (!key || !key->isValid()) + return { }; + keys.append(key.get()); + } + return keys; + }); + + return WTF::visit(visitor, info.keyPath()); +} + +void generateIndexKeyForValue(ExecState& exec, const IDBIndexInfo& info, JSValue value, IndexKey& outKey) +{ + auto keyDatas = createKeyPathArray(exec, value, info); + + if (keyDatas.isEmpty()) + return; + + outKey = IndexKey(WTFMove(keyDatas)); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/IDBBindingUtilities.h b/Source/WebCore/bindings/js/IDBBindingUtilities.h index f012aef2d..c491fee7f 100644 --- a/Source/WebCore/bindings/js/IDBBindingUtilities.h +++ b/Source/WebCore/bindings/js/IDBBindingUtilities.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2014, 2015, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,34 +24,41 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef IDBBindingUtilities_h -#define IDBBindingUtilities_h +#pragma once #if ENABLE(INDEXED_DATABASE) -#include "Dictionary.h" -#include <bindings/ScriptValue.h> +#include "IDBKeyPath.h" #include <wtf/Forward.h> +namespace JSC { +class ExecState; +class JSGlobalObject; +class JSValue; +} + namespace WebCore { -class DOMRequestState; +class IDBIndexInfo; class IDBKey; -class IDBKeyPath; -class SharedBuffer; +class IDBKeyData; +class IDBValue; +class IndexKey; +class JSDOMGlobalObject; + +RefPtr<IDBKey> maybeCreateIDBKeyFromScriptValueAndKeyPath(JSC::ExecState&, const JSC::JSValue&, const IDBKeyPath&); +bool canInjectIDBKeyIntoScriptValue(JSC::ExecState&, const JSC::JSValue&, const IDBKeyPath&); +bool injectIDBKeyIntoScriptValue(JSC::ExecState&, const IDBKeyData&, JSC::JSValue, const IDBKeyPath&); -IDBKeyPath idbKeyPathFromValue(JSC::ExecState*, JSC::JSValue); +void generateIndexKeyForValue(JSC::ExecState&, const IDBIndexInfo&, JSC::JSValue, IndexKey& outKey); -bool injectIDBKeyIntoScriptValue(DOMRequestState*, PassRefPtr<IDBKey>, Deprecated::ScriptValue&, const IDBKeyPath&); -PassRefPtr<IDBKey> createIDBKeyFromScriptValueAndKeyPath(DOMRequestState*, const Deprecated::ScriptValue&, const IDBKeyPath&); -bool canInjectIDBKeyIntoScriptValue(DOMRequestState*, const Deprecated::ScriptValue&, const IDBKeyPath&); -Deprecated::ScriptValue deserializeIDBValue(DOMRequestState*, PassRefPtr<SerializedScriptValue>); -Deprecated::ScriptValue deserializeIDBValueBuffer(DOMRequestState*, PassRefPtr<SharedBuffer>); -Deprecated::ScriptValue idbKeyToScriptValue(DOMRequestState*, PassRefPtr<IDBKey>); -PassRefPtr<IDBKey> scriptValueToIDBKey(DOMRequestState*, const Deprecated::ScriptValue&); +Ref<IDBKey> scriptValueToIDBKey(JSC::ExecState&, const JSC::JSValue&); + +JSC::JSValue deserializeIDBValueToJSValue(JSC::ExecState&, const IDBValue&); +JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, const IDBValue&); +JSC::JSValue toJS(JSC::ExecState&, JSC::JSGlobalObject&, IDBKey*); +JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, const IDBKeyData&); } #endif // ENABLE(INDEXED_DATABASE) - -#endif // IDBBindingUtilities_h diff --git a/Source/WebCore/bindings/js/JSAnimationTimelineCustom.cpp b/Source/WebCore/bindings/js/JSAnimationTimelineCustom.cpp new file mode 100644 index 000000000..47df4e7e7 --- /dev/null +++ b/Source/WebCore/bindings/js/JSAnimationTimelineCustom.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) Canon Inc. 2016 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted, provided that the following conditions + * are required to be 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. + * 3. Neither the name of Canon Inc. nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CANON 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 CANON INC. AND 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" + +#if ENABLE(WEB_ANIMATIONS) +#include "JSAnimationTimeline.h" + +#include "DocumentTimeline.h" +#include "JSDOMBinding.h" +#include "JSDocumentTimeline.h" + +using namespace JSC; + +namespace WebCore { + +JSValue toJSNewlyCreated(ExecState*, JSDOMGlobalObject* globalObject, Ref<AnimationTimeline>&& value) +{ + if (value->isDocumentTimeline()) + return createWrapper<DocumentTimeline>(globalObject, WTFMove(value)); + return createWrapper<AnimationTimeline>(globalObject, WTFMove(value)); +} + +JSValue toJS(ExecState* state, JSDOMGlobalObject* globalObject, AnimationTimeline& value) +{ + return wrap(state, globalObject, value); +} + +} // namespace WebCore + +#endif // ENABLE(WEB_ANIMATIONS) diff --git a/Source/WebCore/bindings/js/JSAttrCustom.cpp b/Source/WebCore/bindings/js/JSAttrCustom.cpp index 07e1689a2..d45cf6d2c 100644 --- a/Source/WebCore/bindings/js/JSAttrCustom.cpp +++ b/Source/WebCore/bindings/js/JSAttrCustom.cpp @@ -10,7 +10,7 @@ * 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -29,28 +29,14 @@ #include "config.h" #include "JSAttr.h" -#include "Document.h" #include "Element.h" -#include "HTMLNames.h" - -using namespace JSC; namespace WebCore { -using namespace HTMLNames; - -void JSAttr::visitChildren(JSCell* cell, SlotVisitor& visitor) +void JSAttr::visitAdditionalChildren(JSC::SlotVisitor& visitor) { - JSAttr* thisObject = jsCast<JSAttr*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); - - Base::visitChildren(thisObject, visitor); - Element* element = thisObject->impl().ownerElement(); - if (!element) - return; - visitor.addOpaqueRoot(root(element)); + if (Element* element = wrapped().ownerElement()) + visitor.addOpaqueRoot(root(element)); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSAudioBufferSourceNodeCustom.cpp b/Source/WebCore/bindings/js/JSAudioBufferSourceNodeCustom.cpp deleted file mode 100644 index 853576ab7..000000000 --- a/Source/WebCore/bindings/js/JSAudioBufferSourceNodeCustom.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2010, Google Inc. All rights reserved. - * Copyright (C) 2012 Samsung Electronics - * - * 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" - -#if ENABLE(WEB_AUDIO) - -#include "JSAudioBufferSourceNode.h" - -#include "AudioBuffer.h" -#include "AudioBufferSourceNode.h" -#include "JSAudioBuffer.h" -#include <runtime/Error.h> - -using namespace JSC; - -namespace WebCore { - -void JSAudioBufferSourceNode::setBuffer(ExecState* exec, JSValue value) -{ - AudioBuffer* buffer = toAudioBuffer(value); - if (!buffer) { - exec->vm().throwException(exec, createTypeError(exec, "Value is not of type AudioBuffer")); - return; - } - - if (!impl().setBuffer(buffer)) - exec->vm().throwException(exec, createTypeError(exec, "AudioBuffer unsupported number of channels")); -} - -} // namespace WebCore - -#endif // ENABLE(WEB_AUDIO) diff --git a/Source/WebCore/bindings/js/JSAudioContextCustom.cpp b/Source/WebCore/bindings/js/JSAudioContextCustom.cpp deleted file mode 100644 index e195ddf11..000000000 --- a/Source/WebCore/bindings/js/JSAudioContextCustom.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2010, 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. - */ - -#include "config.h" - -#if ENABLE(WEB_AUDIO) - -#include "AudioContext.h" - -#include "AudioBuffer.h" -#include "Document.h" -#include "JSAudioBuffer.h" -#include "JSAudioContext.h" -#include "JSOfflineAudioContext.h" -#include "OfflineAudioContext.h" -#include <runtime/ArrayBuffer.h> -#include <runtime/Error.h> -#include <runtime/JSArrayBuffer.h> - -using namespace JSC; - -namespace WebCore { - -EncodedJSValue JSC_HOST_CALL JSAudioContextConstructor::constructJSAudioContext(ExecState* exec) -{ - JSAudioContextConstructor* jsConstructor = jsCast<JSAudioContextConstructor*>(exec->callee()); - if (!jsConstructor) - return throwVMError(exec, createReferenceError(exec, "AudioContext constructor callee is unavailable")); - - ScriptExecutionContext* scriptExecutionContext = jsConstructor->scriptExecutionContext(); - if (!scriptExecutionContext) - return throwVMError(exec, createReferenceError(exec, "AudioContext constructor script execution context is unavailable")); - - if (!scriptExecutionContext->isDocument()) - return throwVMError(exec, createReferenceError(exec, "AudioContext constructor called in a script execution context which is not a document")); - - Document& document = toDocument(*scriptExecutionContext); - - RefPtr<AudioContext> audioContext; - - if (!exec->argumentCount()) { - // Constructor for default AudioContext which talks to audio hardware. - ExceptionCode ec = 0; - audioContext = AudioContext::create(document, ec); - if (ec) { - setDOMException(exec, ec); - return JSValue::encode(JSValue()); - } - if (!audioContext.get()) - return throwVMError(exec, createSyntaxError(exec, "audio resources unavailable for AudioContext construction")); - } else { -#if ENABLE(LEGACY_WEB_AUDIO) - // Constructor for offline (render-target) AudioContext which renders into an AudioBuffer. - // new AudioContext(in unsigned long numberOfChannels, in unsigned long numberOfFrames, in float sampleRate); - document.addConsoleMessage(JSMessageSource, WarningMessageLevel, - "Deprecated AudioContext constructor: use OfflineAudioContext instead"); - - if (exec->argumentCount() < 3) - return throwVMError(exec, createNotEnoughArgumentsError(exec)); - - int32_t numberOfChannels = exec->argument(0).toInt32(exec); - int32_t numberOfFrames = exec->argument(1).toInt32(exec); - float sampleRate = exec->argument(2).toFloat(exec); - - if (numberOfChannels <= 0 || numberOfChannels > 10) - return throwVMError(exec, createSyntaxError(exec, "Invalid number of channels")); - - if (numberOfFrames <= 0) - return throwVMError(exec, createSyntaxError(exec, "Invalid number of frames")); - - if (sampleRate <= 0) - return throwVMError(exec, createSyntaxError(exec, "Invalid sample rate")); - - - ExceptionCode ec = 0; - audioContext = OfflineAudioContext::create(document, numberOfChannels, numberOfFrames, sampleRate, ec); - if (ec) { - setDOMException(exec, ec); - return throwVMError(exec, createSyntaxError(exec, "Error creating OfflineAudioContext")); - } -#else - return throwVMError(exec, createSyntaxError(exec, "Illegal AudioContext constructor")); -#endif - } - - if (!audioContext.get()) - return throwVMError(exec, createReferenceError(exec, "Error creating AudioContext")); - - return JSValue::encode(CREATE_DOM_WRAPPER(exec, jsConstructor->globalObject(), AudioContext, audioContext.get())); -} - -} // namespace WebCore - -#endif // ENABLE(WEB_AUDIO) diff --git a/Source/WebCore/bindings/js/JSAudioTrackCustom.cpp b/Source/WebCore/bindings/js/JSAudioTrackCustom.cpp index ebbd46b5e..732341e50 100644 --- a/Source/WebCore/bindings/js/JSAudioTrackCustom.cpp +++ b/Source/WebCore/bindings/js/JSAudioTrackCustom.cpp @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -35,43 +35,38 @@ using namespace JSC; namespace WebCore { -void JSAudioTrack::visitChildren(JSCell* cell, SlotVisitor& visitor) +void JSAudioTrack::visitAdditionalChildren(SlotVisitor& visitor) { - JSAudioTrack* jsAudioTrack = jsCast<JSAudioTrack*>(cell); - ASSERT_GC_OBJECT_INHERITS(jsAudioTrack, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(jsAudioTrack->structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(jsAudioTrack, visitor); - - AudioTrack& audioTrack = jsAudioTrack->impl(); - visitor.addOpaqueRoot(root(&audioTrack)); + visitor.addOpaqueRoot(root(&wrapped())); } -void JSAudioTrack::setKind(ExecState* exec, JSValue value) +void JSAudioTrack::setKind(ExecState& state, JSValue value) { - UNUSED_PARAM(exec); #if ENABLE(MEDIA_SOURCE) - const String& nativeValue(value.isEmpty() ? String() : value.toString(exec)->value(exec)); - if (exec->hadException()) - return; - impl().setKind(nativeValue); + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto string = value.toWTFString(&state); + RETURN_IF_EXCEPTION(scope, void()); + wrapped().setKind(string); #else + UNUSED_PARAM(state); UNUSED_PARAM(value); - return; #endif } -void JSAudioTrack::setLanguage(ExecState* exec, JSValue value) +void JSAudioTrack::setLanguage(ExecState& state, JSValue value) { - UNUSED_PARAM(exec); #if ENABLE(MEDIA_SOURCE) - const String& nativeValue(value.isEmpty() ? String() : value.toString(exec)->value(exec)); - if (exec->hadException()) - return; - impl().setLanguage(nativeValue); + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto string = value.toWTFString(&state); + RETURN_IF_EXCEPTION(scope, void()); + wrapped().setLanguage(string); #else + UNUSED_PARAM(state); UNUSED_PARAM(value); - return; #endif } diff --git a/Source/WebCore/bindings/js/JSAudioTrackListCustom.cpp b/Source/WebCore/bindings/js/JSAudioTrackListCustom.cpp index 23fd0b916..6fd1a5040 100644 --- a/Source/WebCore/bindings/js/JSAudioTrackListCustom.cpp +++ b/Source/WebCore/bindings/js/JSAudioTrackListCustom.cpp @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,6 +26,7 @@ #include "config.h" #if ENABLE(VIDEO_TRACK) + #include "JSAudioTrackList.h" #include "Element.h" @@ -35,17 +36,9 @@ using namespace JSC; namespace WebCore { -void JSAudioTrackList::visitChildren(JSCell* cell, SlotVisitor& visitor) +void JSAudioTrackList::visitAdditionalChildren(SlotVisitor& visitor) { - JSAudioTrackList* jsAudioTrackList = jsCast<JSAudioTrackList*>(cell); - ASSERT_GC_OBJECT_INHERITS(jsAudioTrackList, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(jsAudioTrackList->structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(jsAudioTrackList, visitor); - - AudioTrackList& audioTrackList = jsAudioTrackList->impl(); - visitor.addOpaqueRoot(root(audioTrackList.element())); - audioTrackList.visitJSEventListeners(visitor); + visitor.addOpaqueRoot(root(wrapped().element())); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSBindingsAllInOne.cpp b/Source/WebCore/bindings/js/JSBindingsAllInOne.cpp new file mode 100644 index 000000000..4d379309a --- /dev/null +++ b/Source/WebCore/bindings/js/JSBindingsAllInOne.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2009, 2010 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. ``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 + * 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. + */ + +// This all-in-one cpp file cuts down on template bloat to allow us to build our Windows release build. + +#include "CachedModuleScriptLoader.cpp" +#include "DOMWrapperWorld.cpp" +#include "GCController.cpp" +#include "JSAnimationTimelineCustom.cpp" +#include "JSAttrCustom.cpp" +#include "JSAudioTrackCustom.cpp" +#include "JSAudioTrackListCustom.cpp" +#include "JSBlobCustom.cpp" +#include "JSCSSRuleCustom.cpp" +#include "JSCSSRuleListCustom.cpp" +#include "JSCSSStyleDeclarationCustom.cpp" +#include "JSCSSValueCustom.cpp" +#include "JSCallbackData.cpp" +#include "JSCanvasRenderingContext2DCustom.cpp" +#include "JSCommandLineAPIHostCustom.cpp" +#include "JSCryptoCustom.cpp" +#include "JSCustomEventCustom.cpp" +#include "JSSQLStatementErrorCallbackCustom.cpp" +#include "JSCustomXPathNSResolver.cpp" +#include "JSDOMBindingSecurity.cpp" +#include "JSDOMBuiltinConstructorBase.cpp" +#include "JSDOMConstructorBase.cpp" +#include "JSDOMConstructorWithDocument.cpp" +#include "JSDOMExceptionHandling.cpp" +#include "JSDOMGlobalObject.cpp" +#include "JSDOMGlobalObjectTask.cpp" +#include "JSDOMPromise.cpp" +#include "JSDOMStringMapCustom.cpp" +#include "JSDOMWindowBase.cpp" +#include "JSDOMWindowCustom.cpp" +#include "JSDOMWindowProperties.cpp" +#include "JSDOMWindowShell.cpp" +#include "JSDOMWrapper.cpp" +#include "JSDOMWrapperCache.cpp" +#include "JSDocumentCustom.cpp" +#include "JSDocumentFragmentCustom.cpp" +#include "JSElementCustom.cpp" +#include "JSErrorHandler.cpp" +#include "JSEventCustom.cpp" +#include "JSEventListener.cpp" +#include "JSEventTargetCustom.cpp" +#include "JSExceptionBase.cpp" +#include "JSHTMLAllCollectionCustom.cpp" +#include "JSHTMLAppletElementCustom.cpp" +#include "JSHTMLCanvasElementCustom.cpp" +#include "JSHTMLCollectionCustom.cpp" +#include "JSHTMLDocumentCustom.cpp" +#include "JSHTMLElementCustom.cpp" +#include "JSHTMLEmbedElementCustom.cpp" +#include "JSHTMLFormControlsCollectionCustom.cpp" +#include "JSHTMLFrameSetElementCustom.cpp" +#include "JSHTMLObjectElementCustom.cpp" +#include "JSHTMLOptionsCollectionCustom.cpp" +#include "JSHTMLSelectElementCustom.cpp" +#include "JSHTMLTemplateElementCustom.cpp" +#include "JSHistoryCustom.cpp" +#include "JSImageDataCustom.cpp" +#include "JSInspectorFrontendHostCustom.cpp" +#include "JSLazyEventListener.cpp" +#include "JSLocationCustom.cpp" +#include "JSMainThreadExecState.cpp" +#include "JSMessageChannelCustom.cpp" +#include "JSMessageEventCustom.cpp" +#include "JSMessagePortCustom.cpp" +#include "JSMutationCallback.cpp" +#include "JSMutationObserverCustom.cpp" +#include "JSNodeCustom.cpp" +#include "JSNodeFilterCustom.cpp" +#include "JSNodeIteratorCustom.cpp" +#include "JSNodeListCustom.cpp" +#include "JSPluginElementFunctions.cpp" +#include "JSPopStateEventCustom.cpp" +#include "JSReadableStreamPrivateConstructors.cpp" +#include "JSSVGPathSegCustom.cpp" +#include "JSStorageCustom.cpp" +#include "JSStyleSheetCustom.cpp" +#include "JSTextCustom.cpp" +#include "JSTextTrackCueCustom.cpp" +#include "JSTextTrackCustom.cpp" +#include "JSTextTrackListCustom.cpp" +#include "JSTrackCustom.cpp" +#include "JSTreeWalkerCustom.cpp" +#include "JSVideoTrackCustom.cpp" +#include "JSVideoTrackListCustom.cpp" +#include "JSWorkerCustom.cpp" +#include "JSWorkerGlobalScopeBase.cpp" +#include "JSWorkerGlobalScopeCustom.cpp" +#include "JSXMLDocumentCustom.cpp" +#include "JSXMLHttpRequestCustom.cpp" +#include "JSXPathNSResolverCustom.cpp" +#include "JSXPathResultCustom.cpp" +#include "ScheduledAction.cpp" +#include "ScriptCachedFrameData.cpp" +#include "ScriptController.cpp" +#include "ScriptGlobalObject.cpp" +#include "ScriptModuleLoader.cpp" +#include "ScriptState.cpp" +#include "SerializedScriptValue.cpp" +#include "WebCoreTypedArrayController.cpp" +#include "WorkerScriptController.cpp" diff --git a/Source/WebCore/bindings/js/JSBiquadFilterNodeCustom.cpp b/Source/WebCore/bindings/js/JSBiquadFilterNodeCustom.cpp deleted file mode 100644 index fe342b81b..000000000 --- a/Source/WebCore/bindings/js/JSBiquadFilterNodeCustom.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2012, 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. - */ - -#include "config.h" - -#if ENABLE(WEB_AUDIO) - -#include "JSBiquadFilterNode.h" - -#include "BiquadFilterNode.h" -#include "ExceptionCode.h" -#include <runtime/Error.h> - -using namespace JSC; - -namespace WebCore { - -void JSBiquadFilterNode::setType(ExecState* exec, JSValue value) -{ -#if ENABLE(LEGACY_WEB_AUDIO) - if (value.isNumber()) { - uint32_t type = value.toUInt32(exec); - if (!impl().setType(type)) - exec->vm().throwException(exec, createTypeError(exec, "Illegal BiquadFilterNode type")); - return; - } -#endif - - if (value.isString()) { - String type = value.toString(exec)->value(exec); - if (type == "lowpass" || type == "highpass" || type == "bandpass" || type == "lowshelf" || type == "highshelf" || type == "peaking" || type == "notch" || type == "allpass") { - impl().setType(type); - return; - } - } - - exec->vm().throwException(exec, createTypeError(exec, "Illegal BiquadFilterNode type")); -} - -} // namespace WebCore - -#endif // ENABLE(WEB_AUDIO) diff --git a/Source/WebCore/bindings/js/JSBlobCustom.cpp b/Source/WebCore/bindings/js/JSBlobCustom.cpp index bfcd4d192..649594010 100644 --- a/Source/WebCore/bindings/js/JSBlobCustom.cpp +++ b/Source/WebCore/bindings/js/JSBlobCustom.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2012 Google Inc. All rights reserved. + * Copyright (C) 2016 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 @@ -31,111 +32,23 @@ #include "config.h" #include "JSBlob.h" -#include "Blob.h" -#include "ExceptionCode.h" -#include "ExceptionCodePlaceholder.h" #include "JSDOMBinding.h" -#include "JSDictionary.h" #include "JSFile.h" -#include "WebKitBlobBuilder.h" -#include <runtime/Error.h> -#include <runtime/JSArray.h> -#include <runtime/JSArrayBuffer.h> -#include <runtime/JSArrayBufferView.h> -#include <wtf/Assertions.h> using namespace JSC; namespace WebCore { -JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, Blob* blob) +JSValue toJSNewlyCreated(JSC::ExecState*, JSDOMGlobalObject* globalObject, Ref<Blob>&& blob) { - if (!blob) - return jsNull(); - - if (blob->isFile()) - return wrap<JSFile>(exec, globalObject, static_cast<File*>(blob)); - - return wrap<JSBlob>(exec, globalObject, blob); + if (is<File>(blob)) + return createWrapper<File>(globalObject, WTFMove(blob)); + return createWrapper<Blob>(globalObject, WTFMove(blob)); } -EncodedJSValue JSC_HOST_CALL JSBlobConstructor::constructJSBlob(ExecState* exec) +JSValue toJS(ExecState* state, JSDOMGlobalObject* globalObject, Blob& blob) { - JSBlobConstructor* jsConstructor = jsCast<JSBlobConstructor*>(exec->callee()); - ScriptExecutionContext* context = jsConstructor->scriptExecutionContext(); - if (!context) - return throwVMError(exec, createReferenceError(exec, "Blob constructor associated document is unavailable")); - - if (!exec->argumentCount()) { - RefPtr<Blob> blob = Blob::create(); - return JSValue::encode(CREATE_DOM_WRAPPER(exec, jsConstructor->globalObject(), Blob, blob.get())); - } - - unsigned blobPartsLength = 0; - JSObject* blobParts = toJSSequence(exec, exec->argument(0), blobPartsLength); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - ASSERT(blobParts); - - String type; - String endings = ASCIILiteral("transparent"); - - if (exec->argumentCount() > 1) { - JSValue blobPropertyBagValue = exec->argument(1); - - if (!blobPropertyBagValue.isObject()) - return throwVMError(exec, createTypeError(exec, "Second argument of the constructor is not of type Object")); - - // Given the above test, this will always yield an object. - JSObject* blobPropertyBagObject = blobPropertyBagValue.toObject(exec); - - // Create the dictionary wrapper from the initializer object. - JSDictionary dictionary(exec, blobPropertyBagObject); - - // Attempt to get the endings property and validate it. - bool containsEndings = dictionary.get("endings", endings); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - if (containsEndings) { - if (endings != "transparent" && endings != "native") - return throwVMError(exec, createTypeError(exec, "The endings property must be either \"transparent\" or \"native\"")); - } - - // Attempt to get the type property. - dictionary.get("type", type); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - } - - ASSERT(endings == "transparent" || endings == "native"); - - BlobBuilder blobBuilder; - - for (unsigned i = 0; i < blobPartsLength; ++i) { - JSValue item = blobParts->get(exec, i); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - -#if ENABLE(BLOB) - if (ArrayBuffer* arrayBuffer = toArrayBuffer(item)) - blobBuilder.append(arrayBuffer); - else if (RefPtr<ArrayBufferView> arrayBufferView = toArrayBufferView(item)) - blobBuilder.append(arrayBufferView.release()); - else -#endif - if (Blob* blob = toBlob(item)) - blobBuilder.append(blob); - else { - String string = item.toString(exec)->value(exec); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - blobBuilder.append(string, endings); - } - } - - RefPtr<Blob> blob = blobBuilder.getBlob(type); - return JSValue::encode(CREATE_DOM_WRAPPER(exec, jsConstructor->globalObject(), Blob, blob.get())); + return wrap(state, globalObject, blob); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSCSSRuleCustom.cpp b/Source/WebCore/bindings/js/JSCSSRuleCustom.cpp index 3003a70eb..666757bf7 100644 --- a/Source/WebCore/bindings/js/JSCSSRuleCustom.cpp +++ b/Source/WebCore/bindings/js/JSCSSRuleCustom.cpp @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,29 +26,28 @@ #include "config.h" #include "JSCSSRule.h" -#include "CSSCharsetRule.h" #include "CSSFontFaceRule.h" #include "CSSImportRule.h" +#include "CSSKeyframeRule.h" +#include "CSSKeyframesRule.h" #include "CSSMediaRule.h" +#include "CSSNamespaceRule.h" #include "CSSPageRule.h" #include "CSSStyleRule.h" #include "CSSSupportsRule.h" -#include "JSCSSCharsetRule.h" #include "JSCSSFontFaceRule.h" -#include "JSCSSHostRule.h" #include "JSCSSImportRule.h" +#include "JSCSSKeyframeRule.h" +#include "JSCSSKeyframesRule.h" #include "JSCSSMediaRule.h" +#include "JSCSSNamespaceRule.h" #include "JSCSSPageRule.h" #include "JSCSSStyleRule.h" #include "JSCSSSupportsRule.h" #include "JSNode.h" #include "JSStyleSheetCustom.h" -#include "JSWebKitCSSKeyframeRule.h" -#include "JSWebKitCSSKeyframesRule.h" #include "JSWebKitCSSRegionRule.h" #include "JSWebKitCSSViewportRule.h" -#include "WebKitCSSKeyframeRule.h" -#include "WebKitCSSKeyframesRule.h" #include "WebKitCSSRegionRule.h" #include "WebKitCSSViewportRule.h" @@ -56,75 +55,48 @@ using namespace JSC; namespace WebCore { -void JSCSSRule::visitChildren(JSCell* cell, SlotVisitor& visitor) +void JSCSSRule::visitAdditionalChildren(SlotVisitor& visitor) { - JSCSSRule* thisObject = jsCast<JSCSSRule*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(thisObject, visitor); - visitor.addOpaqueRoot(root(&thisObject->impl())); + visitor.addOpaqueRoot(root(&wrapped())); } -JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, CSSRule* rule) +JSValue toJSNewlyCreated(ExecState*, JSDOMGlobalObject* globalObject, Ref<CSSRule>&& rule) { - if (!rule) - return jsNull(); - - JSObject* wrapper = getCachedWrapper(currentWorld(exec), rule); - if (wrapper) - return wrapper; - switch (rule->type()) { - case CSSRule::STYLE_RULE: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, CSSStyleRule, rule); - break; - case CSSRule::MEDIA_RULE: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, CSSMediaRule, rule); - break; - case CSSRule::FONT_FACE_RULE: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, CSSFontFaceRule, rule); - break; - case CSSRule::PAGE_RULE: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, CSSPageRule, rule); - break; - case CSSRule::IMPORT_RULE: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, CSSImportRule, rule); - break; - case CSSRule::CHARSET_RULE: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, CSSCharsetRule, rule); - break; - case CSSRule::WEBKIT_KEYFRAME_RULE: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, WebKitCSSKeyframeRule, rule); - break; - case CSSRule::WEBKIT_KEYFRAMES_RULE: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, WebKitCSSKeyframesRule, rule); - break; -#if ENABLE(CSS3_CONDITIONAL_RULES) - case CSSRule::SUPPORTS_RULE: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, CSSSupportsRule, rule); - break; -#endif + case CSSRule::STYLE_RULE: + return createWrapper<CSSStyleRule>(globalObject, WTFMove(rule)); + case CSSRule::MEDIA_RULE: + return createWrapper<CSSMediaRule>(globalObject, WTFMove(rule)); + case CSSRule::FONT_FACE_RULE: + return createWrapper<CSSFontFaceRule>(globalObject, WTFMove(rule)); + case CSSRule::PAGE_RULE: + return createWrapper<CSSPageRule>(globalObject, WTFMove(rule)); + case CSSRule::IMPORT_RULE: + return createWrapper<CSSImportRule>(globalObject, WTFMove(rule)); + case CSSRule::NAMESPACE_RULE: + return createWrapper<CSSNamespaceRule>(globalObject, WTFMove(rule)); + case CSSRule::KEYFRAME_RULE: + return createWrapper<CSSKeyframeRule>(globalObject, WTFMove(rule)); + case CSSRule::KEYFRAMES_RULE: + return createWrapper<CSSKeyframesRule>(globalObject, WTFMove(rule)); + case CSSRule::SUPPORTS_RULE: + return createWrapper<CSSSupportsRule>(globalObject, WTFMove(rule)); #if ENABLE(CSS_DEVICE_ADAPTATION) - case CSSRule::WEBKIT_VIEWPORT_RULE: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, WebKitCSSViewportRule, rule); - break; + case CSSRule::WEBKIT_VIEWPORT_RULE: + return createWrapper<WebKitCSSViewportRule>(globalObject, WTFMove(rule)); #endif #if ENABLE(CSS_REGIONS) - case CSSRule::WEBKIT_REGION_RULE: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, WebKitCSSRegionRule, rule); - break; + case CSSRule::WEBKIT_REGION_RULE: + return createWrapper<WebKitCSSRegionRule>(globalObject, WTFMove(rule)); #endif -#if ENABLE(SHADOW_DOM) - case CSSRule::HOST_RULE: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, CSSHostRule, rule); - break; -#endif - default: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, CSSRule, rule); + default: + return createWrapper<CSSRule>(globalObject, WTFMove(rule)); } +} - return wrapper; +JSValue toJS(ExecState* state, JSDOMGlobalObject* globalObject, CSSRule& object) +{ + return wrap(state, globalObject, object); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSCSSRuleCustom.h b/Source/WebCore/bindings/js/JSCSSRuleCustom.h index 720565840..e99a19e02 100644 --- a/Source/WebCore/bindings/js/JSCSSRuleCustom.h +++ b/Source/WebCore/bindings/js/JSCSSRuleCustom.h @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,8 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSCSSRuleCustom_h -#define JSCSSRuleCustom_h +#pragma once #include "CSSRule.h" #include "CSSStyleSheet.h" @@ -43,5 +42,3 @@ inline void* root(CSSRule* rule) } } // namespace WebCore - -#endif // JSCSSRuleCustom_h diff --git a/Source/WebCore/bindings/js/JSCSSRuleListCustom.cpp b/Source/WebCore/bindings/js/JSCSSRuleListCustom.cpp index d4c22a855..028444fe3 100644 --- a/Source/WebCore/bindings/js/JSCSSRuleListCustom.cpp +++ b/Source/WebCore/bindings/js/JSCSSRuleListCustom.cpp @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -38,12 +38,12 @@ namespace WebCore { bool JSCSSRuleListOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor) { - JSCSSRuleList* jsCSSRuleList = jsCast<JSCSSRuleList*>(handle.get().asCell()); + JSCSSRuleList* jsCSSRuleList = jsCast<JSCSSRuleList*>(handle.slot()->asCell()); if (!jsCSSRuleList->hasCustomProperties()) return false; - if (CSSStyleSheet* styleSheet = jsCSSRuleList->impl().styleSheet()) + if (CSSStyleSheet* styleSheet = jsCSSRuleList->wrapped().styleSheet()) return visitor.containsOpaqueRoot(root(styleSheet)); - if (CSSRule* cssRule = jsCSSRuleList->impl().item(0)) + if (CSSRule* cssRule = jsCSSRuleList->wrapped().item(0)) return visitor.containsOpaqueRoot(root(cssRule)); return false; } diff --git a/Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp b/Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp index e8190f2f1..4104a8952 100644 --- a/Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp +++ b/Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2009, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2007-2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,58 +26,54 @@ #include "config.h" #include "JSCSSStyleDeclarationCustom.h" -#include "CSSParser.h" -#include "CSSPrimitiveValue.h" #include "CSSPropertyNames.h" -#include "CSSValue.h" +#include "CSSPropertyParser.h" +#include "CSSRule.h" +#include "CSSStyleDeclaration.h" +#include "CSSStyleSheet.h" +#include "CustomElementReactionQueue.h" +#include "DeprecatedCSSOMPrimitiveValue.h" #include "HashTools.h" -#include "JSCSSValue.h" +#include "JSCSSStyleDeclaration.h" +#include "JSDeprecatedCSSOMValue.h" #include "JSNode.h" +#include "JSStyleSheetCustom.h" #include "RuntimeEnabledFeatures.h" #include "Settings.h" #include "StyleProperties.h" +#include "StyledElement.h" +#include <runtime/IdentifierInlines.h> #include <runtime/StringPrototype.h> #include <wtf/ASCIICType.h> #include <wtf/text/AtomicString.h> -#include <wtf/text/StringBuilder.h> #include <wtf/text/StringConcatenate.h> -#include <wtf/text/WTFString.h> using namespace JSC; -using namespace WTF; namespace WebCore { -void JSCSSStyleDeclaration::visitChildren(JSCell* cell, SlotVisitor& visitor) +void* root(CSSStyleDeclaration* style) { - JSCSSStyleDeclaration* thisObject = jsCast<JSCSSStyleDeclaration*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(thisObject, visitor); - visitor.addOpaqueRoot(root(&thisObject->impl())); + ASSERT(style); + if (auto* parentRule = style->parentRule()) + return root(parentRule); + if (auto* styleSheet = style->parentStyleSheet()) + return root(styleSheet); + if (auto* parentElement = style->parentElement()) + return root(parentElement); + return style; } -class CSSPropertyInfo { -public: - CSSPropertyID propertyID; - bool hadPixelOrPosPrefix; -}; - -enum PropertyNamePrefix +void JSCSSStyleDeclaration::visitAdditionalChildren(SlotVisitor& visitor) { - PropertyNamePrefixNone, - PropertyNamePrefixCSS, - PropertyNamePrefixPixel, - PropertyNamePrefixPos, -#if ENABLE(LEGACY_CSS_VENDOR_PREFIXES) - PropertyNamePrefixApple, -#endif - PropertyNamePrefixEpub, + visitor.addOpaqueRoot(root(&wrapped())); +} + +enum class PropertyNamePrefix { + None, Epub, CSS, Pixel, Pos, WebKit, #if ENABLE(LEGACY_CSS_VENDOR_PREFIXES) - PropertyNamePrefixKHTML, + Apple, KHTML, #endif - PropertyNamePrefixWebKit }; template<size_t prefixCStringLength> @@ -97,7 +93,7 @@ static inline bool matchesCSSPropertyNamePrefix(const StringImpl& propertyName, // The prefix within the property name must be followed by a capital letter. // Other characters in the prefix within the property name must be lowercase. - if (propertyName.length() < (prefixLength + 1)) + if (propertyName.length() < prefixLength + 1) return false; for (size_t i = offset; i < prefixLength; ++i) { @@ -107,10 +103,11 @@ static inline bool matchesCSSPropertyNamePrefix(const StringImpl& propertyName, if (!isASCIIUpper(propertyName[prefixLength])) return false; + return true; } -static PropertyNamePrefix getCSSPropertyNamePrefix(const StringImpl& propertyName) +static PropertyNamePrefix propertyNamePrefix(const StringImpl& propertyName) { ASSERT(propertyName.length()); @@ -120,37 +117,37 @@ static PropertyNamePrefix getCSSPropertyNamePrefix(const StringImpl& propertyNam #if ENABLE(LEGACY_CSS_VENDOR_PREFIXES) case 'a': if (RuntimeEnabledFeatures::sharedFeatures().legacyCSSVendorPrefixesEnabled() && matchesCSSPropertyNamePrefix(propertyName, "apple")) - return PropertyNamePrefixApple; + return PropertyNamePrefix::Apple; break; #endif case 'c': if (matchesCSSPropertyNamePrefix(propertyName, "css")) - return PropertyNamePrefixCSS; + return PropertyNamePrefix::CSS; break; #if ENABLE(LEGACY_CSS_VENDOR_PREFIXES) case 'k': if (RuntimeEnabledFeatures::sharedFeatures().legacyCSSVendorPrefixesEnabled() && matchesCSSPropertyNamePrefix(propertyName, "khtml")) - return PropertyNamePrefixKHTML; + return PropertyNamePrefix::KHTML; break; #endif case 'e': if (matchesCSSPropertyNamePrefix(propertyName, "epub")) - return PropertyNamePrefixEpub; + return PropertyNamePrefix::Epub; break; case 'p': if (matchesCSSPropertyNamePrefix(propertyName, "pos")) - return PropertyNamePrefixPos; + return PropertyNamePrefix::Pos; if (matchesCSSPropertyNamePrefix(propertyName, "pixel")) - return PropertyNamePrefixPixel; + return PropertyNamePrefix::Pixel; break; case 'w': if (matchesCSSPropertyNamePrefix(propertyName, "webkit")) - return PropertyNamePrefixWebKit; + return PropertyNamePrefix::WebKit; break; default: break; } - return PropertyNamePrefixNone; + return PropertyNamePrefix::None; } static inline void writeWebKitPrefix(char*& buffer) @@ -175,7 +172,12 @@ static inline void writeEpubPrefix(char*& buffer) *buffer++ = '-'; } -static CSSPropertyInfo cssPropertyIDForJSCSSPropertyName(PropertyName propertyName) +struct CSSPropertyInfo { + CSSPropertyID propertyID; + bool hadPixelOrPosPrefix; +}; + +static CSSPropertyInfo parseJavaScriptCSSPropertyName(PropertyName propertyName) { CSSPropertyInfo propertyInfo = {CSSPropertyInvalid, false}; bool hadPixelOrPosPrefix = false; @@ -188,9 +190,9 @@ static CSSPropertyInfo cssPropertyIDForJSCSSPropertyName(PropertyName propertyNa return propertyInfo; String stringForCache = String(propertyNameString); - typedef HashMap<String, CSSPropertyInfo> CSSPropertyInfoMap; - DEFINE_STATIC_LOCAL(CSSPropertyInfoMap, propertyInfoCache, ()); - propertyInfo = propertyInfoCache.get(stringForCache); + using CSSPropertyInfoMap = HashMap<String, CSSPropertyInfo>; + static NeverDestroyed<CSSPropertyInfoMap> propertyInfoCache; + propertyInfo = propertyInfoCache.get().get(stringForCache); if (propertyInfo.propertyID) return propertyInfo; @@ -203,35 +205,35 @@ static CSSPropertyInfo cssPropertyIDForJSCSSPropertyName(PropertyName propertyNa // Prefixes CSS, Pixel, Pos are ignored. // Prefixes Apple, KHTML and Webkit are transposed to "-webkit-". // The prefix "Epub" becomes "-epub-". - switch (getCSSPropertyNamePrefix(*propertyNameString)) { - case PropertyNamePrefixNone: + switch (propertyNamePrefix(*propertyNameString)) { + case PropertyNamePrefix::None: if (isASCIIUpper((*propertyNameString)[0])) return propertyInfo; break; - case PropertyNamePrefixCSS: + case PropertyNamePrefix::CSS: i += 3; break; - case PropertyNamePrefixPixel: + case PropertyNamePrefix::Pixel: i += 5; hadPixelOrPosPrefix = true; break; - case PropertyNamePrefixPos: + case PropertyNamePrefix::Pos: i += 3; hadPixelOrPosPrefix = true; break; #if ENABLE(LEGACY_CSS_VENDOR_PREFIXES) - case PropertyNamePrefixApple: - case PropertyNamePrefixKHTML: + case PropertyNamePrefix::Apple: + case PropertyNamePrefix::KHTML: ASSERT(RuntimeEnabledFeatures::sharedFeatures().legacyCSSVendorPrefixesEnabled()); writeWebKitPrefix(bufferPtr); i += 5; break; #endif - case PropertyNamePrefixEpub: + case PropertyNamePrefix::Epub: writeEpubPrefix(bufferPtr); i += 4; break; - case PropertyNamePrefixWebKit: + case PropertyNamePrefix::WebKit: writeWebKitPrefix(bufferPtr); i += 6; break; @@ -248,7 +250,7 @@ static CSSPropertyInfo cssPropertyIDForJSCSSPropertyName(PropertyName propertyNa for (; i < length; ++i) { UChar c = (*propertyNameString)[i]; - if (!c || c >= 0x7F) + if (!c || !isASCII(c)) return propertyInfo; // illegal character if (isASCIIUpper(c)) { size_t bufferSizeLeft = stringEnd - bufferPtr; @@ -256,7 +258,7 @@ static CSSPropertyInfo cssPropertyIDForJSCSSPropertyName(PropertyName propertyNa if (propertySizeLeft > bufferSizeLeft) return propertyInfo; *bufferPtr++ = '-'; - *bufferPtr++ = toASCIILower(c); + *bufferPtr++ = toASCIILowerUnchecked(c); } else *bufferPtr++ = c; ASSERT_WITH_SECURITY_IMPLICATION(bufferPtr < bufferEnd); @@ -269,142 +271,125 @@ static CSSPropertyInfo cssPropertyIDForJSCSSPropertyName(PropertyName propertyNa cssPropertyNameIOSAliasing(buffer, name, outputLength); #endif - const Property* hashTableEntry = findProperty(name, outputLength); - int propertyID = hashTableEntry ? hashTableEntry->id : 0; - if (propertyID) { + auto* hashTableEntry = findProperty(name, outputLength); + if (auto propertyID = hashTableEntry ? hashTableEntry->id : 0) { propertyInfo.hadPixelOrPosPrefix = hadPixelOrPosPrefix; propertyInfo.propertyID = static_cast<CSSPropertyID>(propertyID); - propertyInfoCache.add(stringForCache, propertyInfo); + propertyInfoCache.get().add(stringForCache, propertyInfo); } return propertyInfo; } -static inline JSValue getPropertyValueFallback(ExecState* exec, JSCSSStyleDeclaration* thisObj, unsigned index) -{ - // If the property is a shorthand property (such as "padding"), - // it can only be accessed using getPropertyValue. - return jsStringWithCache(exec, thisObj->impl().getPropertyValueInternal(static_cast<CSSPropertyID>(index))); -} - -static inline JSValue cssPropertyGetterPixelOrPosPrefix(ExecState* exec, JSCSSStyleDeclaration* thisObj, unsigned propertyID) +static inline JSValue stylePropertyGetter(ExecState& state, JSCSSStyleDeclaration& thisObject, CSSPropertyID propertyID, const RefPtr<CSSValue>& value) { - // Set up pixelOrPos boolean to handle the fact that - // pixelTop returns "CSS Top" as number value in unit pixels - // posTop returns "CSS top" as number value in unit pixels _if_ its a - // positioned element. if it is not a positioned element, return 0 - // from MSIE documentation FIXME: IMPLEMENT THAT (Dirk) - RefPtr<CSSValue> v = thisObj->impl().getPropertyCSSValueInternal(static_cast<CSSPropertyID>(propertyID)); - if (v) { - if (v->isPrimitiveValue()) - return jsNumber(static_pointer_cast<CSSPrimitiveValue>(v)->getFloatValue(CSSPrimitiveValue::CSS_PX)); - return jsStringOrNull(exec, v->cssText()); - } - - return getPropertyValueFallback(exec, thisObj, propertyID); + if (value) + return toJS<IDLNullable<IDLDOMString>>(state, value->cssText()); + // If the property is a shorthand property (such as "padding"), it can only be accessed using getPropertyValue. + return toJS<IDLDOMString>(state, thisObject.wrapped().getPropertyValueInternal(propertyID)); } -static EncodedJSValue cssPropertyGetterPixelOrPosPrefixCallback(ExecState* exec, EncodedJSValue, EncodedJSValue thisValue, unsigned propertyID) +static inline JSValue stylePropertyGetter(ExecState& state, JSCSSStyleDeclaration& thisObject, CSSPropertyID propertyID) { - JSCSSStyleDeclaration* thisObject = jsDynamicCast<JSCSSStyleDeclaration*>(JSValue::decode(thisValue)); - if (!thisObject) - return throwVMTypeError(exec); - return JSValue::encode(cssPropertyGetterPixelOrPosPrefix(exec, thisObject, propertyID)); + return stylePropertyGetter(state, thisObject, propertyID, thisObject.wrapped().getPropertyCSSValueInternal(propertyID)); } -static inline JSValue cssPropertyGetter(ExecState* exec, JSCSSStyleDeclaration* thisObj, unsigned propertyID) +static inline JSValue stylePropertyGetterPixelOrPosPrefix(ExecState& state, JSCSSStyleDeclaration& thisObject, CSSPropertyID propertyID) { - RefPtr<CSSValue> v = thisObj->impl().getPropertyCSSValueInternal(static_cast<CSSPropertyID>(propertyID)); - if (v) - return jsStringOrNull(exec, v->cssText()); - - return getPropertyValueFallback(exec, thisObj, propertyID); + // Call this version of the getter so that, e.g., pixelTop returns top as a number + // in pixel units and posTop should does the same _if_ this is a positioned element. + // FIXME: If not a positioned element, MSIE documentation says posTop should return 0; this rule is not implemented. + auto value = thisObject.wrapped().getPropertyCSSValueInternal(propertyID); + if (is<CSSPrimitiveValue>(value.get())) + return jsNumber(downcast<CSSPrimitiveValue>(*value).floatValue(CSSPrimitiveValue::CSS_PX)); + return stylePropertyGetter(state, thisObject, propertyID, value); } -static EncodedJSValue cssPropertyGetterCallback(ExecState* exec, EncodedJSValue, EncodedJSValue thisValue, unsigned propertyID) +static inline JSValue stylePropertyGetter(ExecState& state, JSCSSStyleDeclaration& thisObject, const CSSPropertyInfo& propertyInfo) { - JSCSSStyleDeclaration* thisObject = jsDynamicCast<JSCSSStyleDeclaration*>(JSValue::decode(thisValue)); - if (!thisObject) - return throwVMTypeError(exec); - return JSValue::encode(cssPropertyGetter(exec, thisObject, propertyID)); + if (propertyInfo.hadPixelOrPosPrefix) + return stylePropertyGetterPixelOrPosPrefix(state, thisObject, propertyInfo.propertyID); + return stylePropertyGetter(state, thisObject, propertyInfo.propertyID); } -bool JSCSSStyleDeclaration::getOwnPropertySlotDelegate(ExecState*, PropertyName propertyIdentifier, PropertySlot& slot) +bool JSCSSStyleDeclaration::getOwnPropertySlotDelegate(ExecState* state, PropertyName propertyName, PropertySlot& slot) { - CSSPropertyInfo propertyInfo = cssPropertyIDForJSCSSPropertyName(propertyIdentifier); + auto propertyInfo = parseJavaScriptCSSPropertyName(propertyName); if (!propertyInfo.propertyID) return false; - - if (propertyInfo.hadPixelOrPosPrefix) - slot.setCustomIndex(this, ReadOnly | DontDelete | DontEnum, static_cast<unsigned>(propertyInfo.propertyID), cssPropertyGetterPixelOrPosPrefixCallback); - else - slot.setCustomIndex(this, ReadOnly | DontDelete | DontEnum, static_cast<unsigned>(propertyInfo.propertyID), cssPropertyGetterCallback); + slot.setValue(this, DontDelete, stylePropertyGetter(*state, *this, propertyInfo)); return true; } -bool JSCSSStyleDeclaration::putDelegate(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot&) +bool JSCSSStyleDeclaration::putDelegate(ExecState* state, PropertyName propertyName, JSValue value, PutPropertySlot&, bool& putResult) { - CSSPropertyInfo propertyInfo = cssPropertyIDForJSCSSPropertyName(propertyName); + CustomElementReactionStack customElementReactionStack; + auto propertyInfo = parseJavaScriptCSSPropertyName(propertyName); if (!propertyInfo.propertyID) return false; - String propValue = valueToStringWithNullCheck(exec, value); + auto propertyValue = convert<IDLDOMString>(*state, value, StringConversionConfiguration::TreatNullAsEmptyString); if (propertyInfo.hadPixelOrPosPrefix) - propValue.append("px"); + propertyValue.append("px"); bool important = false; if (Settings::shouldRespectPriorityInCSSAttributeSetters()) { - size_t importantIndex = propValue.find("!important", 0, false); - if (importantIndex != notFound) { + auto importantIndex = propertyValue.findIgnoringASCIICase("!important"); + if (importantIndex && importantIndex != notFound) { important = true; - propValue = propValue.left(importantIndex - 1); + propertyValue = propertyValue.left(importantIndex - 1); } } - ExceptionCode ec = 0; - impl().setPropertyInternal(static_cast<CSSPropertyID>(propertyInfo.propertyID), propValue, important, ec); - setDOMException(exec, ec); + auto setPropertyInternalResult = wrapped().setPropertyInternal(propertyInfo.propertyID, propertyValue, important); + if (setPropertyInternalResult.hasException()) { + auto& vm = state->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + propagateException(*state, scope, setPropertyInternalResult.releaseException()); + return true; + } + putResult = setPropertyInternalResult.releaseReturnValue(); return true; } -JSValue JSCSSStyleDeclaration::getPropertyCSSValue(ExecState* exec) +JSValue JSCSSStyleDeclaration::getPropertyCSSValue(ExecState& state) { - const String& propertyName = exec->argument(0).toString(exec)->value(exec); - if (exec->hadException()) - return jsUndefined(); + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(state.argumentCount() < 1)) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); - RefPtr<CSSValue> cssValue = impl().getPropertyCSSValue(propertyName); - if (!cssValue) + auto propertyName = state.uncheckedArgument(0).toWTFString(&state); + RETURN_IF_EXCEPTION(scope, JSValue()); + + auto value = wrapped().getPropertyCSSValue(propertyName); + if (!value) return jsNull(); - currentWorld(exec).m_cssValueRoots.add(cssValue.get(), root(&impl())); // Balanced by JSCSSValueOwner::finalize(). - return toJS(exec, globalObject(), WTF::getPtr(cssValue)); + globalObject()->world().m_deprecatedCSSOMValueRoots.add(value.get(), root(&wrapped())); // Balanced by JSDeprecatedCSSOMValueOwner::finalize(). + return toJS(&state, globalObject(), *value); } -void JSCSSStyleDeclaration::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) +void JSCSSStyleDeclaration::getOwnPropertyNames(JSObject* object, ExecState* state, PropertyNameArray& propertyNames, EnumerationMode mode) { - JSCSSStyleDeclaration* thisObject = jsCast<JSCSSStyleDeclaration*>(object); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - - unsigned length = thisObject->impl().length(); - for (unsigned i = 0; i < length; ++i) - propertyNames.add(Identifier::from(exec, i)); - - static Identifier* propertyIdentifiers = 0; - if (!propertyIdentifiers) { - Vector<String, numCSSProperties> jsPropertyNames; - for (int id = firstCSSProperty; id < firstCSSProperty + numCSSProperties; ++id) - jsPropertyNames.append(getJSPropertyName(static_cast<CSSPropertyID>(id))); - std::sort(jsPropertyNames.begin(), jsPropertyNames.end(), WTF::codePointCompareLessThan); - - propertyIdentifiers = new Identifier[numCSSProperties]; + static const Identifier* const cssPropertyNames = [state] { + String names[numCSSProperties]; for (int i = 0; i < numCSSProperties; ++i) - propertyIdentifiers[i] = Identifier(exec, jsPropertyNames[i].impl()); - } + names[i] = getJSPropertyName(static_cast<CSSPropertyID>(firstCSSProperty + i)); + std::sort(&names[0], &names[numCSSProperties], WTF::codePointCompareLessThan); + auto* identifiers = new Identifier[numCSSProperties]; + for (int i = 0; i < numCSSProperties; ++i) + identifiers[i] = Identifier::fromString(state, names[i]); + return identifiers; + }(); + unsigned length = jsCast<JSCSSStyleDeclaration*>(object)->wrapped().length(); + for (unsigned i = 0; i < length; ++i) + propertyNames.add(Identifier::from(state, i)); for (int i = 0; i < numCSSProperties; ++i) - propertyNames.add(propertyIdentifiers[i]); + propertyNames.add(cssPropertyNames[i]); - Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode); + Base::getOwnPropertyNames(object, state, propertyNames, mode); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.h b/Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.h index 6ed1fec30..af2a9dce5 100644 --- a/Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.h +++ b/Source/WebCore/bindings/js/JSCSSStyleDeclarationCustom.h @@ -23,26 +23,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSCSSStyleDeclarationCustom_h -#define JSCSSStyleDeclarationCustom_h - -#include "CSSRule.h" -#include "CSSStyleDeclaration.h" -#include "CSSStyleSheet.h" -#include "JSCSSStyleDeclaration.h" -#include "JSStyleSheetCustom.h" +#pragma once namespace WebCore { -inline void* root(CSSStyleDeclaration* style) -{ - if (CSSRule* parentRule = style->parentRule()) - return root(parentRule); - if (CSSStyleSheet* styleSheet = style->parentStyleSheet()) - return root(styleSheet); - return style; -} +class CSSStyleDeclaration; -} +void* root(CSSStyleDeclaration*); -#endif // JSCSSStyleDeclarationCustom_h +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSCSSValueCustom.cpp b/Source/WebCore/bindings/js/JSCSSValueCustom.cpp index 050e4b8e3..13e23701d 100644 --- a/Source/WebCore/bindings/js/JSCSSValueCustom.cpp +++ b/Source/WebCore/bindings/js/JSCSSValueCustom.cpp @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -24,90 +24,50 @@ */ #include "config.h" -#include "JSCSSValue.h" -#include "CSSPrimitiveValue.h" -#include "CSSValueList.h" -#include "JSCSSPrimitiveValue.h" -#include "JSCSSValueList.h" +#include "DeprecatedCSSOMPrimitiveValue.h" +#include "DeprecatedCSSOMValueList.h" +#include "JSDeprecatedCSSOMPrimitiveValue.h" +#include "JSDeprecatedCSSOMValue.h" +#include "JSDeprecatedCSSOMValueList.h" #include "JSNode.h" -#include "JSWebKitCSSTransformValue.h" -#include "WebKitCSSTransformValue.h" - -#if ENABLE(CSS_FILTERS) -#include "JSWebKitCSSFilterValue.h" -#include "WebKitCSSFilterValue.h" -#endif - -#if ENABLE(SVG) -#include "JSSVGColor.h" -#include "JSSVGPaint.h" -#include "SVGColor.h" -#include "SVGPaint.h" -#endif using namespace JSC; namespace WebCore { -bool JSCSSValueOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void* context, SlotVisitor& visitor) +bool JSDeprecatedCSSOMValueOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void* context, SlotVisitor& visitor) { - JSCSSValue* jsCSSValue = jsCast<JSCSSValue*>(handle.get().asCell()); + JSDeprecatedCSSOMValue* jsCSSValue = jsCast<JSDeprecatedCSSOMValue*>(handle.slot()->asCell()); if (!jsCSSValue->hasCustomProperties()) return false; DOMWrapperWorld* world = static_cast<DOMWrapperWorld*>(context); - void* root = world->m_cssValueRoots.get(&jsCSSValue->impl()); + void* root = world->m_deprecatedCSSOMValueRoots.get(&jsCSSValue->wrapped()); if (!root) return false; return visitor.containsOpaqueRoot(root); } -void JSCSSValueOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context) +void JSDeprecatedCSSOMValueOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context) { - JSCSSValue* jsCSSValue = jsCast<JSCSSValue*>(handle.get().asCell()); + JSDeprecatedCSSOMValue* jsCSSValue = static_cast<JSDeprecatedCSSOMValue*>(handle.slot()->asCell()); DOMWrapperWorld& world = *static_cast<DOMWrapperWorld*>(context); - world.m_cssValueRoots.remove(&jsCSSValue->impl()); - uncacheWrapper(world, &jsCSSValue->impl(), jsCSSValue); - jsCSSValue->releaseImpl(); + world.m_deprecatedCSSOMValueRoots.remove(&jsCSSValue->wrapped()); + uncacheWrapper(world, &jsCSSValue->wrapped(), jsCSSValue); } -JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, CSSValue* value) +JSValue toJSNewlyCreated(ExecState*, JSDOMGlobalObject* globalObject, Ref<DeprecatedCSSOMValue>&& value) { - if (!value) - return jsNull(); - - // Scripts should only ever see cloned CSSValues, never the internal ones. - ASSERT(value->isCSSOMSafe()); - - // If we're here under erroneous circumstances, prefer returning null over a potentially insecure value. - if (!value->isCSSOMSafe()) - return jsNull(); - - JSObject* wrapper = getCachedWrapper(currentWorld(exec), value); - - if (wrapper) - return wrapper; - - if (value->isWebKitCSSTransformValue()) - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, WebKitCSSTransformValue, value); -#if ENABLE(CSS_FILTERS) - else if (value->isWebKitCSSFilterValue()) - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, WebKitCSSFilterValue, value); -#endif - else if (value->isValueList()) - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, CSSValueList, value); -#if ENABLE(SVG) - else if (value->isSVGPaint()) - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, SVGPaint, value); - else if (value->isSVGColor()) - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, SVGColor, value); -#endif - else if (value->isPrimitiveValue()) - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, CSSPrimitiveValue, value); - else - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, CSSValue, value); + if (value->isValueList()) + return createWrapper<DeprecatedCSSOMValueList>(globalObject, WTFMove(value)); + if (value->isPrimitiveValue()) + return createWrapper<DeprecatedCSSOMPrimitiveValue>(globalObject, WTFMove(value)); + return createWrapper<DeprecatedCSSOMValue>(globalObject, WTFMove(value)); +} - return wrapper; +JSValue toJS(ExecState* state, JSDOMGlobalObject* globalObject, DeprecatedCSSOMValue& value) +{ + return wrap(state, globalObject, value); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSCallbackData.cpp b/Source/WebCore/bindings/js/JSCallbackData.cpp index f53d4404f..655eaf44c 100644 --- a/Source/WebCore/bindings/js/JSCallbackData.cpp +++ b/Source/WebCore/bindings/js/JSCallbackData.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2007-2009, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,7 +10,7 @@ * 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -33,60 +33,63 @@ #include "JSDOMBinding.h" #include "JSMainThreadExecState.h" #include "JSMainThreadExecStateInstrumentation.h" +#include <runtime/Exception.h> using namespace JSC; namespace WebCore { -void JSCallbackData::deleteData(void* context) +JSValue JSCallbackData::invokeCallback(JSDOMGlobalObject& globalObject, JSObject* callback, MarkedArgumentBuffer& args, CallbackType method, PropertyName functionName, NakedPtr<JSC::Exception>& returnedException) { - delete static_cast<JSCallbackData*>(context); -} - -JSValue JSCallbackData::invokeCallback(MarkedArgumentBuffer& args, bool* raisedException) -{ - ASSERT(callback()); - return invokeCallback(callback(), args, raisedException); -} + ASSERT(callback); -JSValue JSCallbackData::invokeCallback(JSValue thisValue, MarkedArgumentBuffer& args, bool* raisedException) -{ - ASSERT(callback()); - ASSERT(globalObject()); + ExecState* exec = globalObject.globalExec(); + JSValue function; + CallData callData; + CallType callType = CallType::None; - ExecState* exec = globalObject()->globalExec(); - JSValue function = callback(); + if (method != CallbackType::Object) { + function = callback; + callType = callback->methodTable()->getCallData(callback, callData); + } + if (callType == CallType::None) { + if (method == CallbackType::Function) { + returnedException = JSC::Exception::create(exec->vm(), createTypeError(exec)); + return JSValue(); + } - CallData callData; - CallType callType = callback()->methodTable()->getCallData(callback(), callData); - if (callType == CallTypeNone) { - function = callback()->get(exec, Identifier(exec, "handleEvent")); + ASSERT(!functionName.isNull()); + function = callback->get(exec, functionName); callType = getCallData(function, callData); - if (callType == CallTypeNone) + if (callType == CallType::None) { + returnedException = JSC::Exception::create(exec->vm(), createTypeError(exec)); return JSValue(); + } } - ScriptExecutionContext* context = globalObject()->scriptExecutionContext(); + ASSERT(!function.isEmpty()); + ASSERT(callType != CallType::None); + + ScriptExecutionContext* context = globalObject.scriptExecutionContext(); // We will fail to get the context if the frame has been detached. if (!context) return JSValue(); InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(context, callType, callData); + returnedException = nullptr; JSValue result = context->isDocument() - ? JSMainThreadExecState::call(exec, function, callType, callData, thisValue, args) - : JSC::call(exec, function, callType, callData, thisValue, args); + ? JSMainThreadExecState::profiledCall(exec, JSC::ProfilingReason::Other, function, callType, callData, callback, args, returnedException) + : JSC::profiledCall(exec, JSC::ProfilingReason::Other, function, callType, callData, callback, args, returnedException); - InspectorInstrumentation::didCallFunction(cookie); - - if (exec->hadException()) { - reportCurrentException(exec); - if (raisedException) - *raisedException = true; - return result; - } + InspectorInstrumentation::didCallFunction(cookie, context); return result; } +bool JSCallbackDataWeak::WeakOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, SlotVisitor& visitor) +{ + return visitor.containsOpaqueRoot(context); +} + } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSCallbackData.h b/Source/WebCore/bindings/js/JSCallbackData.h index ff76a9e85..3ea990e56 100644 --- a/Source/WebCore/bindings/js/JSCallbackData.h +++ b/Source/WebCore/bindings/js/JSCallbackData.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2007-2009, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,7 +10,7 @@ * 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -26,8 +26,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSCallbackData_h -#define JSCallbackData_h +#pragma once #include "JSDOMBinding.h" #include "JSDOMGlobalObject.h" @@ -45,11 +44,13 @@ namespace WebCore { class JSCallbackData { public: - static void deleteData(void*); + enum class CallbackType { Function, Object, FunctionOrObject }; - JSCallbackData(JSC::JSObject* callback, JSDOMGlobalObject* globalObject) - : m_callback(globalObject->vm(), callback) - , m_globalObject(globalObject->vm(), globalObject) + JSDOMGlobalObject* globalObject() { return m_globalObject.get(); } + +protected: + explicit JSCallbackData(JSDOMGlobalObject* globalObject) + : m_globalObject(globalObject) #ifndef NDEBUG , m_thread(currentThread()) #endif @@ -62,40 +63,74 @@ public: ASSERT(m_thread == currentThread()); #endif } - - JSC::JSObject* callback() { return m_callback.get(); } - JSDOMGlobalObject* globalObject() { return m_globalObject.get(); } - JSC::JSValue invokeCallback(JSC::MarkedArgumentBuffer&, bool* raisedException = 0); - JSC::JSValue invokeCallback(JSC::JSValue thisValue, JSC::MarkedArgumentBuffer&, bool* raisedException = 0); + static JSC::JSValue invokeCallback(JSDOMGlobalObject&, JSC::JSObject* callback, JSC::MarkedArgumentBuffer&, CallbackType, JSC::PropertyName functionName, NakedPtr<JSC::Exception>& returnedException); private: - JSC::Strong<JSC::JSObject> m_callback; - JSC::Strong<JSDOMGlobalObject> m_globalObject; + JSC::Weak<JSDOMGlobalObject> m_globalObject; #ifndef NDEBUG ThreadIdentifier m_thread; #endif }; -class DeleteCallbackDataTask : public ScriptExecutionContext::Task { +class JSCallbackDataStrong : public JSCallbackData { public: - static PassOwnPtr<DeleteCallbackDataTask> create(JSCallbackData* data) + JSCallbackDataStrong(JSC::JSObject* callback, JSDOMGlobalObject* globalObject, void*) + : JSCallbackData(globalObject) + , m_callback(globalObject->vm(), callback) { - return adoptPtr(new DeleteCallbackDataTask(data)); } - virtual void performTask(ScriptExecutionContext*) + JSC::JSObject* callback() { return m_callback.get(); } + + JSC::JSValue invokeCallback(JSC::MarkedArgumentBuffer& args, CallbackType callbackType, JSC::PropertyName functionName, NakedPtr<JSC::Exception>& returnedException) { - delete m_data; + auto* globalObject = this->globalObject(); + if (!globalObject) + return { }; + + return JSCallbackData::invokeCallback(*globalObject, callback(), args, callbackType, functionName, returnedException); } - virtual bool isCleanupTask() const { return true; } + private: + JSC::Strong<JSC::JSObject> m_callback; +}; + +class JSCallbackDataWeak : public JSCallbackData { +public: + JSCallbackDataWeak(JSC::JSObject* callback, JSDOMGlobalObject* globalObject, void* owner) + : JSCallbackData(globalObject) + , m_callback(callback, &m_weakOwner, owner) + { + } + + JSC::JSObject* callback() { return m_callback.get(); } - DeleteCallbackDataTask(JSCallbackData* data) : m_data(data) {} + JSC::JSValue invokeCallback(JSC::MarkedArgumentBuffer& args, CallbackType callbackType, JSC::PropertyName functionName, NakedPtr<JSC::Exception>& returnedException) + { + auto* globalObject = this->globalObject(); + if (!globalObject) + return { }; + + return JSCallbackData::invokeCallback(*globalObject, callback(), args, callbackType, functionName, returnedException); + } - JSCallbackData* m_data; +private: + class WeakOwner : public JSC::WeakHandleOwner { + bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&) override; + }; + WeakOwner m_weakOwner; + JSC::Weak<JSC::JSObject> m_callback; }; -} // namespace WebCore +class DeleteCallbackDataTask : public ScriptExecutionContext::Task { +public: + template <typename CallbackDataType> + explicit DeleteCallbackDataTask(CallbackDataType* data) + : ScriptExecutionContext::Task(ScriptExecutionContext::Task::CleanupTask, [data = std::unique_ptr<CallbackDataType>(data)] (ScriptExecutionContext&) { + }) + { + } +}; -#endif // JSCallbackData_h +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp b/Source/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp index efa539fb5..b347e3bec 100644 --- a/Source/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp +++ b/Source/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2006-2017 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -38,84 +38,16 @@ using namespace JSC; namespace WebCore { -static JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, const CanvasStyle& style) +bool JSCanvasRenderingContext2DOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor) { - if (style.canvasGradient()) - return toJS(exec, globalObject, style.canvasGradient()); - if (style.canvasPattern()) - return toJS(exec, globalObject, style.canvasPattern()); - return jsStringWithCache(exec, style.color()); + JSCanvasRenderingContext2D* jsCanvasRenderingContext = jsCast<JSCanvasRenderingContext2D*>(handle.slot()->asCell()); + void* root = WebCore::root(jsCanvasRenderingContext->wrapped().canvas()); + return visitor.containsOpaqueRoot(root); } -static CanvasStyle toHTMLCanvasStyle(ExecState*, JSValue value) +void JSCanvasRenderingContext2D::visitAdditionalChildren(SlotVisitor& visitor) { - if (!value.isObject()) - return CanvasStyle(); - JSObject* object = asObject(value); - if (object->inherits(JSCanvasGradient::info())) - return CanvasStyle(&jsCast<JSCanvasGradient*>(object)->impl()); - if (object->inherits(JSCanvasPattern::info())) - return CanvasStyle(&jsCast<JSCanvasPattern*>(object)->impl()); - return CanvasStyle(); -} - -JSValue JSCanvasRenderingContext2D::strokeStyle(ExecState* exec) const -{ - return toJS(exec, globalObject(), impl().strokeStyle()); -} - -void JSCanvasRenderingContext2D::setStrokeStyle(ExecState* exec, JSValue value) -{ - CanvasRenderingContext2D& context = impl(); - if (value.isString()) { - context.setStrokeColor(asString(value)->value(exec)); - return; - } - context.setStrokeStyle(toHTMLCanvasStyle(exec, value)); -} - -JSValue JSCanvasRenderingContext2D::fillStyle(ExecState* exec) const -{ - return toJS(exec, globalObject(), impl().fillStyle()); -} - -void JSCanvasRenderingContext2D::setFillStyle(ExecState* exec, JSValue value) -{ - CanvasRenderingContext2D& context = impl(); - if (value.isString()) { - context.setFillColor(asString(value)->value(exec)); - return; - } - context.setFillStyle(toHTMLCanvasStyle(exec, value)); -} - -JSValue JSCanvasRenderingContext2D::webkitLineDash(ExecState* exec) const -{ - const Vector<float>& dash = impl().getLineDash(); - - MarkedArgumentBuffer list; - Vector<float>::const_iterator end = dash.end(); - for (Vector<float>::const_iterator it = dash.begin(); it != end; ++it) - list.append(JSValue(*it)); - return constructArray(exec, 0, globalObject(), list); -} - -void JSCanvasRenderingContext2D::setWebkitLineDash(ExecState* exec, JSValue value) -{ - if (!isJSArray(value)) - return; - - Vector<float> dash; - JSArray* valueArray = asArray(value); - for (unsigned i = 0; i < valueArray->length(); ++i) { - float elem = valueArray->getIndex(exec, i).toFloat(exec); - if (elem <= 0 || !std::isfinite(elem)) - return; - - dash.append(elem); - } - - impl().setWebkitLineDash(dash); + visitor.addOpaqueRoot(root(wrapped().canvas())); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSCanvasRenderingContextCustom.cpp b/Source/WebCore/bindings/js/JSCanvasRenderingContextCustom.cpp deleted file mode 100644 index 0314bd205..000000000 --- a/Source/WebCore/bindings/js/JSCanvasRenderingContextCustom.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2009 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 COMPUTER, INC. ``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 COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "JSCanvasRenderingContext.h" - -#include "CanvasRenderingContext2D.h" -#include "HTMLCanvasElement.h" -#include "JSCanvasRenderingContext2D.h" -#include "JSNode.h" -#if ENABLE(WEBGL) -#include "WebGLRenderingContext.h" -#include "JSWebGLRenderingContext.h" -#endif - -using namespace JSC; - -namespace WebCore { - -void JSCanvasRenderingContext::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - JSCanvasRenderingContext* thisObject = jsCast<JSCanvasRenderingContext*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(thisObject, visitor); - - visitor.addOpaqueRoot(root(thisObject->impl().canvas())); -} - -JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, CanvasRenderingContext* object) -{ - if (!object) - return jsNull(); - -#if ENABLE(WEBGL) - if (object->is3d()) - return wrap<JSWebGLRenderingContext>(exec, globalObject, static_cast<WebGLRenderingContext*>(object)); -#endif - ASSERT_WITH_SECURITY_IMPLICATION(object->is2d()); - return wrap<JSCanvasRenderingContext2D>(exec, globalObject, static_cast<CanvasRenderingContext2D*>(object)); -} - -} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSClipboardCustom.cpp b/Source/WebCore/bindings/js/JSClipboardCustom.cpp deleted file mode 100644 index 47314441c..000000000 --- a/Source/WebCore/bindings/js/JSClipboardCustom.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2008, 2013 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "JSClipboard.h" - -#include "Clipboard.h" - -using namespace JSC; - -namespace WebCore { - -JSValue JSClipboard::types(ExecState* exec) const -{ - Vector<String> types = impl().types(); - return types.isEmpty() ? jsNull() : jsArray(exec, globalObject(), types); -} - -} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSCommandLineAPIHostCustom.cpp b/Source/WebCore/bindings/js/JSCommandLineAPIHostCustom.cpp index be0ae27f3..d89b305be 100644 --- a/Source/WebCore/bindings/js/JSCommandLineAPIHostCustom.cpp +++ b/Source/WebCore/bindings/js/JSCommandLineAPIHostCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007-2008, 2016 Apple Inc. All rights reserved. * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com> * Copyright (C) 2010-2011 Google Inc. All rights reserved. * @@ -31,13 +31,12 @@ */ #include "config.h" - -#if ENABLE(INSPECTOR) - #include "JSCommandLineAPIHost.h" #include "CommandLineAPIHost.h" +#include "Database.h" #include "InspectorDOMAgent.h" +#include "JSDatabase.h" #include "JSEventListener.h" #include "JSNode.h" #include "JSStorage.h" @@ -45,129 +44,120 @@ #include <bindings/ScriptValue.h> #include <inspector/InspectorValues.h> #include <parser/SourceCode.h> +#include <runtime/IdentifierInlines.h> #include <runtime/JSArray.h> #include <runtime/JSFunction.h> #include <runtime/JSLock.h> #include <runtime/ObjectConstructor.h> -#if ENABLE(SQL_DATABASE) -#include "Database.h" -#include "JSDatabase.h" -#endif - using namespace JSC; namespace WebCore { -JSValue JSCommandLineAPIHost::inspectedObject(ExecState* exec) +JSValue JSCommandLineAPIHost::inspectedObject(ExecState& state) { - if (exec->argumentCount() < 1) - return jsUndefined(); - - CommandLineAPIHost::InspectableObject* object = impl().inspectedObject(exec->uncheckedArgument(0).toInt32(exec)); + CommandLineAPIHost::InspectableObject* object = wrapped().inspectedObject(); if (!object) return jsUndefined(); - JSLockHolder lock(exec); - Deprecated::ScriptValue scriptValue = object->get(exec); - if (scriptValue.hasNoValue()) - return jsUndefined(); - - return scriptValue.jsValue(); + JSLockHolder lock(&state); + auto scriptValue = object->get(state); + return scriptValue ? scriptValue : jsUndefined(); } -static JSArray* getJSListenerFunctions(ExecState* exec, Document* document, const EventListenerInfo& listenerInfo) +static JSArray* getJSListenerFunctions(ExecState& state, Document* document, const EventListenerInfo& listenerInfo) { - JSArray* result = constructEmptyArray(exec, nullptr); + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + JSArray* result = constructEmptyArray(&state, nullptr); + RETURN_IF_EXCEPTION(scope, nullptr); size_t handlersCount = listenerInfo.eventListenerVector.size(); for (size_t i = 0, outputIndex = 0; i < handlersCount; ++i) { - const JSEventListener* jsListener = JSEventListener::cast(listenerInfo.eventListenerVector[i].listener.get()); + const JSEventListener* jsListener = JSEventListener::cast(&listenerInfo.eventListenerVector[i]->callback()); if (!jsListener) { ASSERT_NOT_REACHED(); continue; } // Hide listeners from other contexts. - if (&jsListener->isolatedWorld() != ¤tWorld(exec)) + if (&jsListener->isolatedWorld() != ¤tWorld(&state)) continue; JSObject* function = jsListener->jsFunction(document); if (!function) continue; - JSObject* listenerEntry = constructEmptyObject(exec); - listenerEntry->putDirect(exec->vm(), Identifier(exec, "listener"), function); - listenerEntry->putDirect(exec->vm(), Identifier(exec, "useCapture"), jsBoolean(listenerInfo.eventListenerVector[i].useCapture)); - result->putDirectIndex(exec, outputIndex++, JSValue(listenerEntry)); + JSObject* listenerEntry = constructEmptyObject(&state); + listenerEntry->putDirect(vm, Identifier::fromString(&state, "listener"), function); + listenerEntry->putDirect(vm, Identifier::fromString(&state, "useCapture"), jsBoolean(listenerInfo.eventListenerVector[i]->useCapture())); + result->putDirectIndex(&state, outputIndex++, JSValue(listenerEntry)); + RETURN_IF_EXCEPTION(scope, nullptr); } return result; } -JSValue JSCommandLineAPIHost::getEventListeners(ExecState* exec) +JSValue JSCommandLineAPIHost::getEventListeners(ExecState& state) { - if (exec->argumentCount() < 1) + if (state.argumentCount() < 1) return jsUndefined(); - JSValue value = exec->uncheckedArgument(0); + VM& vm = state.vm(); + JSValue value = state.uncheckedArgument(0); if (!value.isObject() || value.isNull()) return jsUndefined(); - Node* node = toNode(value); + Node* node = JSNode::toWrapped(vm, value); if (!node) return jsUndefined(); Vector<EventListenerInfo> listenersArray; - impl().getEventListenersImpl(node, listenersArray); + wrapped().getEventListenersImpl(node, listenersArray); - JSObject* result = constructEmptyObject(exec); + JSObject* result = constructEmptyObject(&state); for (size_t i = 0; i < listenersArray.size(); ++i) { - JSArray* listeners = getJSListenerFunctions(exec, &node->document(), listenersArray[i]); + JSArray* listeners = getJSListenerFunctions(state, &node->document(), listenersArray[i]); if (!listeners->length()) continue; AtomicString eventType = listenersArray[i].eventType; - result->putDirect(exec->vm(), Identifier(exec, eventType.impl()), JSValue(listeners)); + result->putDirect(state.vm(), Identifier::fromString(&state, eventType.impl()), JSValue(listeners)); } return result; } -JSValue JSCommandLineAPIHost::inspect(ExecState* exec) +JSValue JSCommandLineAPIHost::inspect(ExecState& state) { - if (exec->argumentCount() >= 2) { - Deprecated::ScriptValue object(exec->vm(), exec->uncheckedArgument(0)); - Deprecated::ScriptValue hints(exec->vm(), exec->uncheckedArgument(1)); - impl().inspectImpl(object.toInspectorValue(exec), hints.toInspectorValue(exec)); - } - + if (state.argumentCount() < 2) + return jsUndefined(); + wrapped().inspectImpl(Inspector::toInspectorValue(state, state.uncheckedArgument(0)), + Inspector::toInspectorValue(state, state.uncheckedArgument(1))); return jsUndefined(); } -JSValue JSCommandLineAPIHost::databaseId(ExecState* exec) +JSValue JSCommandLineAPIHost::databaseId(ExecState& state) { - if (exec->argumentCount() < 1) + if (state.argumentCount() < 1) return jsUndefined(); -#if ENABLE(SQL_DATABASE) - Database* database = toDatabase(exec->uncheckedArgument(0)); + VM& vm = state.vm(); + Database* database = JSDatabase::toWrapped(vm, state.uncheckedArgument(0)); if (database) - return jsStringWithCache(exec, impl().databaseIdImpl(database)); -#endif + return jsStringWithCache(&state, wrapped().databaseIdImpl(database)); return jsUndefined(); } -JSValue JSCommandLineAPIHost::storageId(ExecState* exec) +JSValue JSCommandLineAPIHost::storageId(ExecState& state) { - if (exec->argumentCount() < 1) + if (state.argumentCount() < 1) return jsUndefined(); - Storage* storage = toStorage(exec->uncheckedArgument(0)); + VM& vm = state.vm(); + Storage* storage = JSStorage::toWrapped(vm, state.uncheckedArgument(0)); if (storage) - return jsStringWithCache(exec, impl().storageIdImpl(storage)); + return jsStringWithCache(&state, wrapped().storageIdImpl(storage)); return jsUndefined(); } } // namespace WebCore - -#endif // ENABLE(INSPECTOR) diff --git a/Source/WebCore/bindings/js/JSCryptoAlgorithmBuilder.cpp b/Source/WebCore/bindings/js/JSCryptoAlgorithmBuilder.cpp new file mode 100644 index 000000000..d99c27abd --- /dev/null +++ b/Source/WebCore/bindings/js/JSCryptoAlgorithmBuilder.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2013 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 "JSCryptoAlgorithmBuilder.h" + +#if ENABLE(SUBTLE_CRYPTO) + +#include <runtime/JSCInlines.h> +#include <runtime/ObjectConstructor.h> +#include <runtime/TypedArrays.h> +#include <runtime/TypedArrayInlines.h> +#include <runtime/VMEntryScope.h> + +using namespace JSC; + +namespace WebCore { + +JSCryptoAlgorithmBuilder::JSCryptoAlgorithmBuilder(ExecState* exec) + : m_exec(exec) + , m_dictionary(constructEmptyObject(exec)) +{ +} + +JSCryptoAlgorithmBuilder::~JSCryptoAlgorithmBuilder() +{ +} + +void JSCryptoAlgorithmBuilder::add(const char* key, unsigned value) +{ + VM& vm = m_exec->vm(); + Identifier identifier = Identifier::fromString(&vm, key); + m_dictionary->putDirect(vm, identifier, jsNumber(value)); +} + +void JSCryptoAlgorithmBuilder::add(const char* key, const String& value) +{ + VM& vm = m_exec->vm(); + Identifier identifier = Identifier::fromString(&vm, key); + m_dictionary->putDirect(vm, identifier, jsString(m_exec, value)); +} + +void JSCryptoAlgorithmBuilder::add(const char* key, const Vector<uint8_t>& buffer) +{ + VM& vm = m_exec->vm(); + Identifier identifier = Identifier::fromString(&vm, key); + RefPtr<Uint8Array> arrayView = Uint8Array::create(buffer.data(), buffer.size()); + m_dictionary->putDirect(vm, identifier, arrayView->wrap(m_exec, vm.entryScope->globalObject())); +} + +void JSCryptoAlgorithmBuilder::add(const char* key, const JSCryptoAlgorithmBuilder& nestedBuilder) +{ + VM& vm = m_exec->vm(); + Identifier identifier = Identifier::fromString(&vm, key); + m_dictionary->putDirect(vm, identifier, nestedBuilder.result()); +} + +} // namespace WebCore + +#endif // ENABLE(SUBTLE_CRYPTO) diff --git a/Source/WebCore/bindings/js/JSCryptoAlgorithmBuilder.h b/Source/WebCore/bindings/js/JSCryptoAlgorithmBuilder.h new file mode 100644 index 000000000..ce696aef2 --- /dev/null +++ b/Source/WebCore/bindings/js/JSCryptoAlgorithmBuilder.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2013 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. + */ + +#pragma once + +#if ENABLE(SUBTLE_CRYPTO) + +#include <wtf/Forward.h> +#include <wtf/Noncopyable.h> +#include <wtf/Vector.h> +#include <wtf/text/WTFString.h> + +namespace JSC { +class ExecState; +class JSObject; +} + +namespace WebCore { + +class JSCryptoAlgorithmBuilder { + WTF_MAKE_NONCOPYABLE(JSCryptoAlgorithmBuilder); +public: + JSCryptoAlgorithmBuilder(JSC::ExecState*); + virtual ~JSCryptoAlgorithmBuilder(); + + JSC::JSObject* result() const { return m_dictionary; } + + void add(const char*, unsigned); + void add(const char*, const String&); + void add(const char*, const Vector<uint8_t>&); + void add(const char*, const JSCryptoAlgorithmBuilder&); + +private: + JSC::ExecState* m_exec; + JSC::JSObject* m_dictionary; +}; + +} // namespace WebCore + +#endif // ENABLE(SUBTLE_CRYPTO) diff --git a/Source/WebCore/bindings/js/JSCryptoAlgorithmDictionary.cpp b/Source/WebCore/bindings/js/JSCryptoAlgorithmDictionary.cpp new file mode 100644 index 000000000..10e1230ed --- /dev/null +++ b/Source/WebCore/bindings/js/JSCryptoAlgorithmDictionary.cpp @@ -0,0 +1,668 @@ +/* + * Copyright (C) 2013, 2016 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 "JSCryptoAlgorithmDictionary.h" + +#if ENABLE(SUBTLE_CRYPTO) + +#include "CryptoAlgorithmAesCbcParamsDeprecated.h" +#include "CryptoAlgorithmAesKeyGenParamsDeprecated.h" +#include "CryptoAlgorithmHmacKeyParamsDeprecated.h" +#include "CryptoAlgorithmHmacParamsDeprecated.h" +#include "CryptoAlgorithmParameters.h" +#include "CryptoAlgorithmRegistry.h" +#include "CryptoAlgorithmRsaKeyGenParamsDeprecated.h" +#include "CryptoAlgorithmRsaKeyParamsWithHashDeprecated.h" +#include "CryptoAlgorithmRsaOaepParamsDeprecated.h" +#include "CryptoAlgorithmRsaSsaParamsDeprecated.h" +#include "ExceptionCode.h" +#include "JSCryptoOperationData.h" +#include "JSDOMBinding.h" +#include "JSDOMConvert.h" + +using namespace JSC; + +namespace WebCore { + +static inline JSValue getProperty(ExecState& state, JSObject* object, const char* name) +{ + return object->get(&state, Identifier::fromString(&state, name)); +} + +CryptoAlgorithmIdentifier JSCryptoAlgorithmDictionary::parseAlgorithmIdentifier(ExecState& state, ThrowScope& scope, JSValue value) +{ + // typedef (Algorithm or DOMString) AlgorithmIdentifier; + + String algorithmName; + VM& vm = state.vm(); + + if (value.isString()) { + algorithmName = asString(value)->value(&state); + RETURN_IF_EXCEPTION(scope, { }); + } else if (value.isObject()) { + if (asObject(value)->inherits(vm, StringObject::info())) { + algorithmName = asStringObject(value)->internalValue()->value(&state); + RETURN_IF_EXCEPTION(scope, { }); + } else { + // FIXME: This doesn't perform some checks mandated by WebIDL for dictionaries: + // - null and undefined input should be treated as if all elements in the dictionary were undefined; + // - undefined elements should be treated as having a default value, or as not present if there isn't such; + // - RegExp and Date objects cannot be converted to dictionaries. + // + // This is partially because we don't implement it elsewhere in WebCore yet, and partially because + // WebCrypto doesn't yet clearly specify what to do with non-present values in most cases anyway. + + auto nameValue = getProperty(state, asObject(value), "name"); + RETURN_IF_EXCEPTION(scope, { }); + + algorithmName = convert<IDLDOMString>(state, nameValue); + RETURN_IF_EXCEPTION(scope, { }); + } + } + + if (!algorithmName.containsOnlyASCII()) { + throwSyntaxError(&state, scope); + return { }; + } + + auto identifier = CryptoAlgorithmRegistry::singleton().identifier(algorithmName); + if (!identifier) { + throwNotSupportedError(state, scope); + return { }; + } + + return identifier.value(); +} + +static std::optional<CryptoAlgorithmIdentifier> optionalHashAlgorithm(ExecState& state, ThrowScope& scope, JSObject* object) +{ + auto hash = getProperty(state, object, "hash"); + RETURN_IF_EXCEPTION(scope, { }); + + if (hash.isUndefinedOrNull()) + return std::nullopt; + + return JSCryptoAlgorithmDictionary::parseAlgorithmIdentifier(state, scope, hash); +} + +static CryptoAlgorithmIdentifier requiredHashAlgorithm(ExecState& state, ThrowScope& scope, JSObject* object) +{ + auto result = optionalHashAlgorithm(state, scope, object); + RETURN_IF_EXCEPTION(scope, { }); + + if (!result) { + throwNotSupportedError(state, scope); + return { }; + } + + return result.value(); +} + +static RefPtr<CryptoAlgorithmParametersDeprecated> createAesCbcParams(ExecState& state, JSValue value) +{ + auto scope = DECLARE_THROW_SCOPE(state.vm()); + + if (!value.isObject()) { + throwTypeError(&state, scope); + return nullptr; + } + + auto iv = getProperty(state, asObject(value), "iv"); + RETURN_IF_EXCEPTION(scope, { }); + + auto result = adoptRef(*new CryptoAlgorithmAesCbcParamsDeprecated); + + auto ivData = cryptoOperationDataFromJSValue(state, scope, iv); + RETURN_IF_EXCEPTION(scope, { }); + + if (ivData.second != 16) { + throwException(&state, scope, createError(&state, "AES-CBC initialization data must be 16 bytes")); + return nullptr; + } + + memcpy(result->iv.data(), ivData.first, ivData.second); + + return WTFMove(result); +} + +static RefPtr<CryptoAlgorithmParametersDeprecated> createAesKeyGenParams(ExecState& state, JSValue value) +{ + auto scope = DECLARE_THROW_SCOPE(state.vm()); + + if (!value.isObject()) { + throwTypeError(&state, scope); + return nullptr; + } + + auto result = adoptRef(*new CryptoAlgorithmAesKeyGenParamsDeprecated); + + auto lengthValue = getProperty(state, asObject(value), "length"); + RETURN_IF_EXCEPTION(scope, nullptr); + + result->length = convert<IDLUnsignedShort>(state, lengthValue, IntegerConversionConfiguration::EnforceRange); + + return WTFMove(result); +} + +static RefPtr<CryptoAlgorithmParametersDeprecated> createHmacParams(ExecState& state, JSValue value) +{ + auto scope = DECLARE_THROW_SCOPE(state.vm()); + + if (!value.isObject()) { + throwTypeError(&state, scope); + return nullptr; + } + + auto result = adoptRef(*new CryptoAlgorithmHmacParamsDeprecated); + + result->hash = requiredHashAlgorithm(state, scope, asObject(value)); + RETURN_IF_EXCEPTION(scope, { }); + + return WTFMove(result); +} + +static RefPtr<CryptoAlgorithmParametersDeprecated> createHmacKeyParams(ExecState& state, JSValue value) +{ + auto scope = DECLARE_THROW_SCOPE(state.vm()); + + if (!value.isObject()) { + throwTypeError(&state, scope); + return nullptr; + } + + auto result = adoptRef(*new CryptoAlgorithmHmacKeyParamsDeprecated); + + result->hash = requiredHashAlgorithm(state, scope, asObject(value)); + RETURN_IF_EXCEPTION(scope, { }); + + auto lengthValue = getProperty(state, asObject(value), "length"); + RETURN_IF_EXCEPTION(scope, nullptr); + + result->length = convert<IDLUnsignedShort>(state, lengthValue, IntegerConversionConfiguration::Normal); + RETURN_IF_EXCEPTION(scope, nullptr); + + result->hasLength = true; + + return WTFMove(result); +} + +static RefPtr<CryptoAlgorithmParametersDeprecated> createRsaKeyGenParams(ExecState& state, JSValue value) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (!value.isObject()) { + throwTypeError(&state, scope); + return nullptr; + } + + auto result = adoptRef(*new CryptoAlgorithmRsaKeyGenParamsDeprecated); + + auto modulusLengthValue = getProperty(state, asObject(value), "modulusLength"); + RETURN_IF_EXCEPTION(scope, nullptr); + + // FIXME: Why no EnforceRange? Filed as <https://www.w3.org/Bugs/Public/show_bug.cgi?id=23779>. + result->modulusLength = convert<IDLUnsignedLong>(state, modulusLengthValue, IntegerConversionConfiguration::Normal); + RETURN_IF_EXCEPTION(scope, nullptr); + + auto publicExponentValue = getProperty(state, asObject(value), "publicExponent"); + RETURN_IF_EXCEPTION(scope, nullptr); + + auto publicExponentArray = toUnsharedUint8Array(vm, publicExponentValue); + if (!publicExponentArray) { + throwTypeError(&state, scope, ASCIILiteral("Expected a Uint8Array in publicExponent")); + return nullptr; + } + result->publicExponent.append(publicExponentArray->data(), publicExponentArray->byteLength()); + + if (auto optionalHash = optionalHashAlgorithm(state, scope, asObject(value))) { + result->hasHash = true; + result->hash = optionalHash.value(); + } + + return WTFMove(result); +} + +static RefPtr<CryptoAlgorithmParametersDeprecated> createRsaKeyParamsWithHash(ExecState&, JSValue) +{ + // WebCrypto RSA algorithms currently do not take any parameters to importKey. + return adoptRef(*new CryptoAlgorithmRsaKeyParamsWithHashDeprecated); +} + +static RefPtr<CryptoAlgorithmParametersDeprecated> createRsaOaepParams(ExecState& state, JSValue value) +{ + auto scope = DECLARE_THROW_SCOPE(state.vm()); + + if (!value.isObject()) { + throwTypeError(&state, scope); + return nullptr; + } + + auto result = adoptRef(*new CryptoAlgorithmRsaOaepParamsDeprecated); + + result->hash = requiredHashAlgorithm(state, scope, asObject(value)); + RETURN_IF_EXCEPTION(scope, { }); + + auto labelValue = getProperty(state, asObject(value), "label"); + RETURN_IF_EXCEPTION(scope, { }); + + result->hasLabel = !labelValue.isUndefinedOrNull(); + if (!result->hasLabel) + return WTFMove(result); + + auto labelData = cryptoOperationDataFromJSValue(state, scope, labelValue); + RETURN_IF_EXCEPTION(scope, { }); + + result->label.append(labelData.first, labelData.second); + + return WTFMove(result); +} + +static RefPtr<CryptoAlgorithmParametersDeprecated> createRsaSsaParams(ExecState& state, JSValue value) +{ + auto scope = DECLARE_THROW_SCOPE(state.vm()); + + if (!value.isObject()) { + throwTypeError(&state, scope); + return nullptr; + } + + auto result = adoptRef(*new CryptoAlgorithmRsaSsaParamsDeprecated); + + result->hash = requiredHashAlgorithm(state, scope, asObject(value)); + RETURN_IF_EXCEPTION(scope, { }); + + return WTFMove(result); +} + +RefPtr<CryptoAlgorithmParametersDeprecated> JSCryptoAlgorithmDictionary::createParametersForEncrypt(ExecState& state, ThrowScope& scope, CryptoAlgorithmIdentifier algorithm, JSValue value) +{ + switch (algorithm) { + case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: + return adoptRef(*new CryptoAlgorithmParametersDeprecated); + case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSA_PSS: + throwNotSupportedError(state, scope); + return nullptr; + case CryptoAlgorithmIdentifier::RSA_OAEP: + return createRsaOaepParams(state, value); + case CryptoAlgorithmIdentifier::ECDSA: + case CryptoAlgorithmIdentifier::ECDH: + case CryptoAlgorithmIdentifier::AES_CTR: + throwNotSupportedError(state, scope); + return nullptr; + case CryptoAlgorithmIdentifier::AES_CBC: + return createAesCbcParams(state, value); + case CryptoAlgorithmIdentifier::AES_CMAC: + case CryptoAlgorithmIdentifier::AES_GCM: + case CryptoAlgorithmIdentifier::AES_CFB: + throwNotSupportedError(state, scope); + return nullptr; + case CryptoAlgorithmIdentifier::AES_KW: + return adoptRef(*new CryptoAlgorithmParametersDeprecated); + case CryptoAlgorithmIdentifier::HMAC: + case CryptoAlgorithmIdentifier::DH: + case CryptoAlgorithmIdentifier::SHA_1: + case CryptoAlgorithmIdentifier::SHA_224: + case CryptoAlgorithmIdentifier::SHA_256: + case CryptoAlgorithmIdentifier::SHA_384: + case CryptoAlgorithmIdentifier::SHA_512: + case CryptoAlgorithmIdentifier::CONCAT: + case CryptoAlgorithmIdentifier::HKDF_CTR: + case CryptoAlgorithmIdentifier::PBKDF2: + throwNotSupportedError(state, scope); + return nullptr; + } + RELEASE_ASSERT_NOT_REACHED(); + return nullptr; +} + +RefPtr<CryptoAlgorithmParametersDeprecated> JSCryptoAlgorithmDictionary::createParametersForDecrypt(ExecState& state, ThrowScope& scope, CryptoAlgorithmIdentifier algorithm, JSValue value) +{ + switch (algorithm) { + case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: + return adoptRef(*new CryptoAlgorithmParametersDeprecated); + case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSA_PSS: + throwNotSupportedError(state, scope); + return nullptr; + case CryptoAlgorithmIdentifier::RSA_OAEP: + return createRsaOaepParams(state, value); + case CryptoAlgorithmIdentifier::ECDSA: + case CryptoAlgorithmIdentifier::ECDH: + case CryptoAlgorithmIdentifier::AES_CTR: + throwNotSupportedError(state, scope); + return nullptr; + case CryptoAlgorithmIdentifier::AES_CBC: + return createAesCbcParams(state, value); + case CryptoAlgorithmIdentifier::AES_CMAC: + case CryptoAlgorithmIdentifier::AES_GCM: + case CryptoAlgorithmIdentifier::AES_CFB: + throwNotSupportedError(state, scope); + return nullptr; + case CryptoAlgorithmIdentifier::AES_KW: + return adoptRef(*new CryptoAlgorithmParametersDeprecated); + case CryptoAlgorithmIdentifier::HMAC: + case CryptoAlgorithmIdentifier::DH: + case CryptoAlgorithmIdentifier::SHA_1: + case CryptoAlgorithmIdentifier::SHA_224: + case CryptoAlgorithmIdentifier::SHA_256: + case CryptoAlgorithmIdentifier::SHA_384: + case CryptoAlgorithmIdentifier::SHA_512: + case CryptoAlgorithmIdentifier::CONCAT: + case CryptoAlgorithmIdentifier::HKDF_CTR: + case CryptoAlgorithmIdentifier::PBKDF2: + throwNotSupportedError(state, scope); + return nullptr; + } + RELEASE_ASSERT_NOT_REACHED(); + return nullptr; +} + +RefPtr<CryptoAlgorithmParametersDeprecated> JSCryptoAlgorithmDictionary::createParametersForSign(ExecState& state, ThrowScope& scope, CryptoAlgorithmIdentifier algorithm, JSValue value) +{ + switch (algorithm) { + case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: + throwNotSupportedError(state, scope); + return nullptr; + case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5: + return createRsaSsaParams(state, value); + case CryptoAlgorithmIdentifier::RSA_PSS: + case CryptoAlgorithmIdentifier::RSA_OAEP: + case CryptoAlgorithmIdentifier::ECDSA: + case CryptoAlgorithmIdentifier::ECDH: + case CryptoAlgorithmIdentifier::AES_CTR: + case CryptoAlgorithmIdentifier::AES_CBC: + case CryptoAlgorithmIdentifier::AES_CMAC: + case CryptoAlgorithmIdentifier::AES_GCM: + case CryptoAlgorithmIdentifier::AES_CFB: + case CryptoAlgorithmIdentifier::AES_KW: + throwNotSupportedError(state, scope); + return nullptr; + case CryptoAlgorithmIdentifier::HMAC: + return createHmacParams(state, value); + case CryptoAlgorithmIdentifier::DH: + case CryptoAlgorithmIdentifier::SHA_1: + case CryptoAlgorithmIdentifier::SHA_224: + case CryptoAlgorithmIdentifier::SHA_256: + case CryptoAlgorithmIdentifier::SHA_384: + case CryptoAlgorithmIdentifier::SHA_512: + case CryptoAlgorithmIdentifier::CONCAT: + case CryptoAlgorithmIdentifier::HKDF_CTR: + case CryptoAlgorithmIdentifier::PBKDF2: + throwNotSupportedError(state, scope); + return nullptr; + } + RELEASE_ASSERT_NOT_REACHED(); + return nullptr; +} + +RefPtr<CryptoAlgorithmParametersDeprecated> JSCryptoAlgorithmDictionary::createParametersForVerify(ExecState& state, ThrowScope& scope, CryptoAlgorithmIdentifier algorithm, JSValue value) +{ + switch (algorithm) { + case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: + throwNotSupportedError(state, scope); + return nullptr; + case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5: + return createRsaSsaParams(state, value); + case CryptoAlgorithmIdentifier::RSA_PSS: + case CryptoAlgorithmIdentifier::RSA_OAEP: + case CryptoAlgorithmIdentifier::ECDSA: + case CryptoAlgorithmIdentifier::ECDH: + case CryptoAlgorithmIdentifier::AES_CTR: + case CryptoAlgorithmIdentifier::AES_CBC: + case CryptoAlgorithmIdentifier::AES_CMAC: + case CryptoAlgorithmIdentifier::AES_GCM: + case CryptoAlgorithmIdentifier::AES_CFB: + case CryptoAlgorithmIdentifier::AES_KW: + throwNotSupportedError(state, scope); + return nullptr; + case CryptoAlgorithmIdentifier::HMAC: + return createHmacParams(state, value); + case CryptoAlgorithmIdentifier::DH: + case CryptoAlgorithmIdentifier::SHA_1: + case CryptoAlgorithmIdentifier::SHA_224: + case CryptoAlgorithmIdentifier::SHA_256: + case CryptoAlgorithmIdentifier::SHA_384: + case CryptoAlgorithmIdentifier::SHA_512: + case CryptoAlgorithmIdentifier::CONCAT: + case CryptoAlgorithmIdentifier::HKDF_CTR: + case CryptoAlgorithmIdentifier::PBKDF2: + throwNotSupportedError(state, scope); + return nullptr; + } + RELEASE_ASSERT_NOT_REACHED(); + return nullptr; +} + +RefPtr<CryptoAlgorithmParametersDeprecated> JSCryptoAlgorithmDictionary::createParametersForDigest(ExecState& state, ThrowScope& scope, CryptoAlgorithmIdentifier algorithm, JSValue) +{ + switch (algorithm) { + case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSA_PSS: + case CryptoAlgorithmIdentifier::RSA_OAEP: + case CryptoAlgorithmIdentifier::ECDSA: + case CryptoAlgorithmIdentifier::ECDH: + case CryptoAlgorithmIdentifier::AES_CTR: + case CryptoAlgorithmIdentifier::AES_CBC: + case CryptoAlgorithmIdentifier::AES_CMAC: + case CryptoAlgorithmIdentifier::AES_GCM: + case CryptoAlgorithmIdentifier::AES_CFB: + case CryptoAlgorithmIdentifier::AES_KW: + case CryptoAlgorithmIdentifier::HMAC: + case CryptoAlgorithmIdentifier::DH: + throwNotSupportedError(state, scope); + return nullptr; + case CryptoAlgorithmIdentifier::SHA_1: + case CryptoAlgorithmIdentifier::SHA_224: + case CryptoAlgorithmIdentifier::SHA_256: + case CryptoAlgorithmIdentifier::SHA_384: + case CryptoAlgorithmIdentifier::SHA_512: + return adoptRef(*new CryptoAlgorithmParametersDeprecated); + case CryptoAlgorithmIdentifier::CONCAT: + case CryptoAlgorithmIdentifier::HKDF_CTR: + case CryptoAlgorithmIdentifier::PBKDF2: + throwNotSupportedError(state, scope); + return nullptr; + } + RELEASE_ASSERT_NOT_REACHED(); + return nullptr; +} + +RefPtr<CryptoAlgorithmParametersDeprecated> JSCryptoAlgorithmDictionary::createParametersForGenerateKey(ExecState& state, ThrowScope& scope, CryptoAlgorithmIdentifier algorithm, JSValue value) +{ + switch (algorithm) { + case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSA_PSS: + case CryptoAlgorithmIdentifier::RSA_OAEP: + return createRsaKeyGenParams(state, value); + case CryptoAlgorithmIdentifier::ECDSA: + case CryptoAlgorithmIdentifier::ECDH: + throwNotSupportedError(state, scope); + return nullptr; + case CryptoAlgorithmIdentifier::AES_CTR: + case CryptoAlgorithmIdentifier::AES_CBC: + case CryptoAlgorithmIdentifier::AES_CMAC: + case CryptoAlgorithmIdentifier::AES_GCM: + case CryptoAlgorithmIdentifier::AES_CFB: + case CryptoAlgorithmIdentifier::AES_KW: + return createAesKeyGenParams(state, value); + case CryptoAlgorithmIdentifier::HMAC: + return createHmacKeyParams(state, value); + case CryptoAlgorithmIdentifier::DH: + case CryptoAlgorithmIdentifier::SHA_1: + case CryptoAlgorithmIdentifier::SHA_224: + case CryptoAlgorithmIdentifier::SHA_256: + case CryptoAlgorithmIdentifier::SHA_384: + case CryptoAlgorithmIdentifier::SHA_512: + case CryptoAlgorithmIdentifier::CONCAT: + case CryptoAlgorithmIdentifier::HKDF_CTR: + case CryptoAlgorithmIdentifier::PBKDF2: + throwNotSupportedError(state, scope); + return nullptr; + } + RELEASE_ASSERT_NOT_REACHED(); + return nullptr; +} + +RefPtr<CryptoAlgorithmParametersDeprecated> JSCryptoAlgorithmDictionary::createParametersForDeriveKey(ExecState& state, ThrowScope& scope, CryptoAlgorithmIdentifier algorithm, JSValue) +{ + switch (algorithm) { + case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSA_PSS: + case CryptoAlgorithmIdentifier::RSA_OAEP: + case CryptoAlgorithmIdentifier::ECDSA: + case CryptoAlgorithmIdentifier::ECDH: + case CryptoAlgorithmIdentifier::AES_CTR: + case CryptoAlgorithmIdentifier::AES_CBC: + case CryptoAlgorithmIdentifier::AES_CMAC: + case CryptoAlgorithmIdentifier::AES_GCM: + case CryptoAlgorithmIdentifier::AES_CFB: + case CryptoAlgorithmIdentifier::AES_KW: + case CryptoAlgorithmIdentifier::HMAC: + case CryptoAlgorithmIdentifier::DH: + case CryptoAlgorithmIdentifier::SHA_1: + case CryptoAlgorithmIdentifier::SHA_224: + case CryptoAlgorithmIdentifier::SHA_256: + case CryptoAlgorithmIdentifier::SHA_384: + case CryptoAlgorithmIdentifier::SHA_512: + case CryptoAlgorithmIdentifier::CONCAT: + case CryptoAlgorithmIdentifier::HKDF_CTR: + case CryptoAlgorithmIdentifier::PBKDF2: + throwNotSupportedError(state, scope); + return nullptr; + } + RELEASE_ASSERT_NOT_REACHED(); + return nullptr; +} + +RefPtr<CryptoAlgorithmParametersDeprecated> JSCryptoAlgorithmDictionary::createParametersForDeriveBits(ExecState& state, ThrowScope& scope, CryptoAlgorithmIdentifier algorithm, JSValue) +{ + switch (algorithm) { + case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSA_PSS: + case CryptoAlgorithmIdentifier::RSA_OAEP: + case CryptoAlgorithmIdentifier::ECDSA: + case CryptoAlgorithmIdentifier::ECDH: + case CryptoAlgorithmIdentifier::AES_CTR: + case CryptoAlgorithmIdentifier::AES_CBC: + case CryptoAlgorithmIdentifier::AES_CMAC: + case CryptoAlgorithmIdentifier::AES_GCM: + case CryptoAlgorithmIdentifier::AES_CFB: + case CryptoAlgorithmIdentifier::AES_KW: + case CryptoAlgorithmIdentifier::HMAC: + case CryptoAlgorithmIdentifier::DH: + case CryptoAlgorithmIdentifier::SHA_1: + case CryptoAlgorithmIdentifier::SHA_224: + case CryptoAlgorithmIdentifier::SHA_256: + case CryptoAlgorithmIdentifier::SHA_384: + case CryptoAlgorithmIdentifier::SHA_512: + case CryptoAlgorithmIdentifier::CONCAT: + case CryptoAlgorithmIdentifier::HKDF_CTR: + case CryptoAlgorithmIdentifier::PBKDF2: + throwNotSupportedError(state, scope); + return nullptr; + } + RELEASE_ASSERT_NOT_REACHED(); + return nullptr; +} + +RefPtr<CryptoAlgorithmParametersDeprecated> JSCryptoAlgorithmDictionary::createParametersForImportKey(ExecState& state, ThrowScope& scope, CryptoAlgorithmIdentifier algorithm, JSValue value) +{ + switch (algorithm) { + case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSA_PSS: + case CryptoAlgorithmIdentifier::RSA_OAEP: + return createRsaKeyParamsWithHash(state, value); + case CryptoAlgorithmIdentifier::ECDSA: + case CryptoAlgorithmIdentifier::ECDH: + case CryptoAlgorithmIdentifier::AES_CTR: + case CryptoAlgorithmIdentifier::AES_CBC: + case CryptoAlgorithmIdentifier::AES_CMAC: + case CryptoAlgorithmIdentifier::AES_GCM: + case CryptoAlgorithmIdentifier::AES_CFB: + case CryptoAlgorithmIdentifier::AES_KW: + return adoptRef(*new CryptoAlgorithmParametersDeprecated); + case CryptoAlgorithmIdentifier::HMAC: + return createHmacParams(state, value); + case CryptoAlgorithmIdentifier::DH: + return adoptRef(*new CryptoAlgorithmParametersDeprecated); + case CryptoAlgorithmIdentifier::SHA_1: + case CryptoAlgorithmIdentifier::SHA_224: + case CryptoAlgorithmIdentifier::SHA_256: + case CryptoAlgorithmIdentifier::SHA_384: + case CryptoAlgorithmIdentifier::SHA_512: + case CryptoAlgorithmIdentifier::CONCAT: + case CryptoAlgorithmIdentifier::HKDF_CTR: + case CryptoAlgorithmIdentifier::PBKDF2: + throwNotSupportedError(state, scope); + return nullptr; + } + RELEASE_ASSERT_NOT_REACHED(); + return nullptr; +} + +RefPtr<CryptoAlgorithmParametersDeprecated> JSCryptoAlgorithmDictionary::createParametersForExportKey(ExecState& state, ThrowScope& scope, CryptoAlgorithmIdentifier algorithm, JSValue) +{ + switch (algorithm) { + case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSA_PSS: + case CryptoAlgorithmIdentifier::RSA_OAEP: + case CryptoAlgorithmIdentifier::ECDSA: + case CryptoAlgorithmIdentifier::ECDH: + case CryptoAlgorithmIdentifier::AES_CTR: + case CryptoAlgorithmIdentifier::AES_CBC: + case CryptoAlgorithmIdentifier::AES_CMAC: + case CryptoAlgorithmIdentifier::AES_GCM: + case CryptoAlgorithmIdentifier::AES_CFB: + case CryptoAlgorithmIdentifier::AES_KW: + case CryptoAlgorithmIdentifier::HMAC: + case CryptoAlgorithmIdentifier::DH: + return adoptRef(*new CryptoAlgorithmParametersDeprecated); + case CryptoAlgorithmIdentifier::SHA_1: + case CryptoAlgorithmIdentifier::SHA_224: + case CryptoAlgorithmIdentifier::SHA_256: + case CryptoAlgorithmIdentifier::SHA_384: + case CryptoAlgorithmIdentifier::SHA_512: + case CryptoAlgorithmIdentifier::CONCAT: + case CryptoAlgorithmIdentifier::HKDF_CTR: + case CryptoAlgorithmIdentifier::PBKDF2: + throwNotSupportedError(state, scope); + return nullptr; + } + RELEASE_ASSERT_NOT_REACHED(); + return nullptr; +} + +} + +#endif // ENABLE(SUBTLE_CRYPTO) diff --git a/Source/WebCore/bindings/js/JSCryptoAlgorithmDictionary.h b/Source/WebCore/bindings/js/JSCryptoAlgorithmDictionary.h new file mode 100644 index 000000000..64ce3db75 --- /dev/null +++ b/Source/WebCore/bindings/js/JSCryptoAlgorithmDictionary.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2013 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. + */ + +#pragma once + +#if ENABLE(SUBTLE_CRYPTO) + +#include "CryptoAlgorithmIdentifier.h" +#include <wtf/Forward.h> + +namespace JSC { +class ExecState; +class JSValue; +class ThrowScope; +} + +namespace WebCore { + +class CryptoAlgorithmParametersDeprecated; + +class JSCryptoAlgorithmDictionary { +public: + static CryptoAlgorithmIdentifier parseAlgorithmIdentifier(JSC::ExecState&, JSC::ThrowScope&, JSC::JSValue); + + static RefPtr<CryptoAlgorithmParametersDeprecated> createParametersForEncrypt(JSC::ExecState&, JSC::ThrowScope&, CryptoAlgorithmIdentifier, JSC::JSValue); + static RefPtr<CryptoAlgorithmParametersDeprecated> createParametersForDecrypt(JSC::ExecState&, JSC::ThrowScope&, CryptoAlgorithmIdentifier, JSC::JSValue); + static RefPtr<CryptoAlgorithmParametersDeprecated> createParametersForSign(JSC::ExecState&, JSC::ThrowScope&, CryptoAlgorithmIdentifier, JSC::JSValue); + static RefPtr<CryptoAlgorithmParametersDeprecated> createParametersForVerify(JSC::ExecState&, JSC::ThrowScope&, CryptoAlgorithmIdentifier, JSC::JSValue); + static RefPtr<CryptoAlgorithmParametersDeprecated> createParametersForDigest(JSC::ExecState&, JSC::ThrowScope&, CryptoAlgorithmIdentifier, JSC::JSValue); + static RefPtr<CryptoAlgorithmParametersDeprecated> createParametersForGenerateKey(JSC::ExecState&, JSC::ThrowScope&, CryptoAlgorithmIdentifier, JSC::JSValue); + static RefPtr<CryptoAlgorithmParametersDeprecated> createParametersForDeriveKey(JSC::ExecState&, JSC::ThrowScope&, CryptoAlgorithmIdentifier, JSC::JSValue); + static RefPtr<CryptoAlgorithmParametersDeprecated> createParametersForDeriveBits(JSC::ExecState&, JSC::ThrowScope&, CryptoAlgorithmIdentifier, JSC::JSValue); + static RefPtr<CryptoAlgorithmParametersDeprecated> createParametersForImportKey(JSC::ExecState&, JSC::ThrowScope&, CryptoAlgorithmIdentifier, JSC::JSValue); + static RefPtr<CryptoAlgorithmParametersDeprecated> createParametersForExportKey(JSC::ExecState&, JSC::ThrowScope&, CryptoAlgorithmIdentifier, JSC::JSValue); +}; + +} // namespace WebCore + +#endif // ENABLE(SUBTLE_CRYPTO) diff --git a/Source/WebCore/bindings/js/JSCryptoCustom.cpp b/Source/WebCore/bindings/js/JSCryptoCustom.cpp index 9d1177146..a71b71aeb 100644 --- a/Source/WebCore/bindings/js/JSCryptoCustom.cpp +++ b/Source/WebCore/bindings/js/JSCryptoCustom.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2012 Google Inc. All rights reserved. + * Copyright (C) 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,8 +26,9 @@ #include "config.h" #include "JSCrypto.h" -#include "ExceptionCode.h" - +#include "JSDOMConvertBufferSource.h" +#include "JSDOMExceptionHandling.h" +#include <heap/HeapInlines.h> #include <runtime/ArrayBufferView.h> #include <runtime/Error.h> #include <runtime/JSArrayBufferView.h> @@ -35,23 +37,20 @@ using namespace JSC; namespace WebCore { -JSValue JSCrypto::getRandomValues(ExecState* exec) +JSValue JSCrypto::getRandomValues(ExecState& state) { - if (exec->argumentCount() < 1) - return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); - JSValue buffer = exec->argument(0); - RefPtr<ArrayBufferView> arrayBufferView = toArrayBufferView(buffer); - if (!arrayBufferView) - return throwTypeError(exec); + if (state.argumentCount() < 1) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); - ExceptionCode ec = 0; - impl().getRandomValues(arrayBufferView.get(), ec); + JSValue buffer = state.argument(0); + auto arrayBufferView = toUnsharedArrayBufferView(vm, buffer); + if (!arrayBufferView) + return throwTypeError(&state, scope); - if (ec) { - setDOMException(exec, ec); - return jsUndefined(); - } + propagateException(state, scope, wrapped().getRandomValues(*arrayBufferView)); return buffer; } diff --git a/Source/WebCore/bindings/js/JSCryptoKeyCustom.cpp b/Source/WebCore/bindings/js/JSCryptoKeyCustom.cpp new file mode 100644 index 000000000..e975400db --- /dev/null +++ b/Source/WebCore/bindings/js/JSCryptoKeyCustom.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2013 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 "JSCryptoKey.h" + +#if ENABLE(SUBTLE_CRYPTO) + +#include "CryptoKeyAES.h" +#include "CryptoKeyHMAC.h" +#include "CryptoKeyRSA.h" +#include "JSCryptoAlgorithmBuilder.h" +#include <heap/HeapInlines.h> +#include <runtime/JSCJSValueInlines.h> + +using namespace JSC; + +namespace WebCore { + +JSValue JSCryptoKey::algorithm(JSC::ExecState& state) const +{ + if (m_algorithm) + return m_algorithm.get(); + + JSCryptoAlgorithmBuilder builder(&state); + + std::unique_ptr<KeyAlgorithm> algorithm = wrapped().buildAlgorithm(); + switch (algorithm->keyAlgorithmClass()) { + case KeyAlgorithmClass::AES: { + auto& aesAlgorithm = downcast<AesKeyAlgorithm>(*algorithm); + builder.add("name", aesAlgorithm.name()); + builder.add("length", aesAlgorithm.length()); + break; + } + case KeyAlgorithmClass::HMAC: { + auto& hmacAlgorithm = downcast<HmacKeyAlgorithm>(*algorithm); + builder.add("name", hmacAlgorithm.name()); + JSCryptoAlgorithmBuilder hmacHash(&state); + hmacHash.add("name", hmacAlgorithm.hash()); + builder.add("hash", hmacHash); + builder.add("length", hmacAlgorithm.length()); + break; + } + case KeyAlgorithmClass::HRSA: { + auto& rsaAlgorithm = downcast<RsaHashedKeyAlgorithm>(*algorithm); + builder.add("name", rsaAlgorithm.name()); + builder.add("modulusLength", rsaAlgorithm.modulusLength()); + builder.add("publicExponent", rsaAlgorithm.publicExponent()); + JSCryptoAlgorithmBuilder rsaHash(&state); + rsaHash.add("name", rsaAlgorithm.hash()); + builder.add("hash", rsaHash); + break; + } + case KeyAlgorithmClass::RSA: { + auto& rsaAlgorithm = downcast<RsaKeyAlgorithm>(*algorithm); + builder.add("name", rsaAlgorithm.name()); + builder.add("modulusLength", rsaAlgorithm.modulusLength()); + builder.add("publicExponent", rsaAlgorithm.publicExponent()); + break; + } + } + + m_algorithm.set(state.vm(), this, builder.result()); + return m_algorithm.get(); +} + +} // namespace WebCore + +#endif // ENABLE(SUBTLE_CRYPTO) diff --git a/Source/WebCore/bindings/js/JSCryptoKeySerializationJWK.cpp b/Source/WebCore/bindings/js/JSCryptoKeySerializationJWK.cpp new file mode 100644 index 000000000..92317c20d --- /dev/null +++ b/Source/WebCore/bindings/js/JSCryptoKeySerializationJWK.cpp @@ -0,0 +1,771 @@ +/* + * Copyright (C) 2013, 2016 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 "JSCryptoKeySerializationJWK.h" + +#if ENABLE(SUBTLE_CRYPTO) + +#include "CryptoAlgorithm.h" +#include "CryptoAlgorithmHmacParamsDeprecated.h" +#include "CryptoAlgorithmRegistry.h" +#include "CryptoAlgorithmRsaKeyParamsWithHashDeprecated.h" +#include "CryptoKey.h" +#include "CryptoKeyAES.h" +#include "CryptoKeyDataOctetSequence.h" +#include "CryptoKeyDataRSAComponents.h" +#include "CryptoKeyHMAC.h" +#include "CryptoKeyRSA.h" +#include "ExceptionCode.h" +#include "JSDOMBinding.h" +#include <heap/StrongInlines.h> +#include <runtime/JSCInlines.h> +#include <runtime/JSONObject.h> +#include <runtime/ObjectConstructor.h> +#include <wtf/text/Base64.h> + +using namespace JSC; + +namespace WebCore { + +static bool getJSArrayFromJSON(ExecState* exec, JSObject* json, const char* key, JSArray*& result) +{ + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + Identifier identifier = Identifier::fromString(exec, key); + PropertySlot slot(json, PropertySlot::InternalMethodType::Get); + + if (!json->getPropertySlot(exec, identifier, slot)) + return false; + + JSValue value = slot.getValue(exec, identifier); + ASSERT(!scope.exception()); + if (!isJSArray(value)) { + throwTypeError(exec, scope, String::format("Expected an array for \"%s\" JSON key", key)); + return false; + } + + result = asArray(value); + + return true; +} + +static bool getStringFromJSON(ExecState* exec, JSObject* json, const char* key, String& result) +{ + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + Identifier identifier = Identifier::fromString(exec, key); + PropertySlot slot(json, PropertySlot::InternalMethodType::Get); + + if (!json->getPropertySlot(exec, identifier, slot)) + return false; + + JSValue jsValue = slot.getValue(exec, identifier); + ASSERT(!scope.exception()); + if (!jsValue.getString(exec, result)) { + // Can get an out of memory exception. + RETURN_IF_EXCEPTION(scope, false); + throwTypeError(exec, scope, String::format("Expected a string value for \"%s\" JSON key", key)); + return false; + } + + return true; +} + +static bool getBooleanFromJSON(ExecState* exec, JSObject* json, const char* key, bool& result) +{ + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + Identifier identifier = Identifier::fromString(exec, key); + PropertySlot slot(json, PropertySlot::InternalMethodType::Get); + + if (!json->getPropertySlot(exec, identifier, slot)) + return false; + + JSValue jsValue = slot.getValue(exec, identifier); + ASSERT(!scope.exception()); + if (!jsValue.isBoolean()) { + throwTypeError(exec, scope, String::format("Expected a boolean value for \"%s\" JSON key", key)); + return false; + } + + result = jsValue.asBoolean(); + return true; +} + +static bool getBigIntegerVectorFromJSON(ExecState* exec, JSObject* json, const char* key, Vector<uint8_t>& result) +{ + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + String base64urlEncodedNumber; + if (!getStringFromJSON(exec, json, key, base64urlEncodedNumber)) + return false; + + if (!base64URLDecode(base64urlEncodedNumber, result)) { + throwTypeError(exec, scope, ASCIILiteral("Cannot decode base64url key data in JWK")); + return false; + } + + if (result[0] == 0) { + throwTypeError(exec, scope, ASCIILiteral("JWK BigInteger must utilize the minimum number of octets to represent the value")); + return false; + } + + return true; +} + +JSCryptoKeySerializationJWK::JSCryptoKeySerializationJWK(ExecState* exec, const String& jsonString) + : m_exec(exec) +{ + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSValue jsonValue = JSONParse(exec, jsonString); + if (UNLIKELY(scope.exception())) + return; + + if (!jsonValue || !jsonValue.isObject()) { + throwTypeError(exec, scope, ASCIILiteral("Invalid JWK serialization")); + return; + } + + m_json.set(vm, asObject(jsonValue)); +} + +JSCryptoKeySerializationJWK::~JSCryptoKeySerializationJWK() +{ +} + +static Ref<CryptoAlgorithmParametersDeprecated> createHMACParameters(CryptoAlgorithmIdentifier hashFunction) +{ + auto hmacParameters = adoptRef(*new CryptoAlgorithmHmacParamsDeprecated); + hmacParameters->hash = hashFunction; + return WTFMove(hmacParameters); +} + +static Ref<CryptoAlgorithmParametersDeprecated> createRSAKeyParametersWithHash(CryptoAlgorithmIdentifier hashFunction) +{ + auto rsaKeyParameters = adoptRef(*new CryptoAlgorithmRsaKeyParamsWithHashDeprecated); + rsaKeyParameters->hasHash = true; + rsaKeyParameters->hash = hashFunction; + return WTFMove(rsaKeyParameters); +} + +std::optional<CryptoAlgorithmPair> JSCryptoKeySerializationJWK::reconcileAlgorithm(CryptoAlgorithm* suggestedAlgorithm, CryptoAlgorithmParametersDeprecated* suggestedParameters) const +{ + VM& vm = m_exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (!getStringFromJSON(m_exec, m_json.get(), "alg", m_jwkAlgorithmName)) { + // Algorithm is optional in JWK. + return CryptoAlgorithmPair { suggestedAlgorithm, suggestedParameters }; + } + + auto& algorithmRegisty = CryptoAlgorithmRegistry::singleton(); + RefPtr<CryptoAlgorithm> algorithm; + RefPtr<CryptoAlgorithmParametersDeprecated> parameters; + if (m_jwkAlgorithmName == "HS256") { + algorithm = algorithmRegisty.create(CryptoAlgorithmIdentifier::HMAC); + parameters = createHMACParameters(CryptoAlgorithmIdentifier::SHA_256); + } else if (m_jwkAlgorithmName == "HS384") { + algorithm = algorithmRegisty.create(CryptoAlgorithmIdentifier::HMAC); + parameters = createHMACParameters(CryptoAlgorithmIdentifier::SHA_384); + } else if (m_jwkAlgorithmName == "HS512") { + algorithm = algorithmRegisty.create(CryptoAlgorithmIdentifier::HMAC); + parameters = createHMACParameters(CryptoAlgorithmIdentifier::SHA_512); + } else if (m_jwkAlgorithmName == "RS256") { + algorithm = algorithmRegisty.create(CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5); + parameters = createRSAKeyParametersWithHash(CryptoAlgorithmIdentifier::SHA_256); + } else if (m_jwkAlgorithmName == "RS384") { + algorithm = algorithmRegisty.create(CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5); + parameters = createRSAKeyParametersWithHash(CryptoAlgorithmIdentifier::SHA_384); + } else if (m_jwkAlgorithmName == "RS512") { + algorithm = algorithmRegisty.create(CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5); + parameters = createRSAKeyParametersWithHash(CryptoAlgorithmIdentifier::SHA_512); + } else if (m_jwkAlgorithmName == "RSA1_5") { + algorithm = algorithmRegisty.create(CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5); + parameters = adoptRef(*new CryptoAlgorithmRsaKeyParamsWithHashDeprecated); + } else if (m_jwkAlgorithmName == "RSA-OAEP") { + algorithm = algorithmRegisty.create(CryptoAlgorithmIdentifier::RSA_OAEP); + parameters = createRSAKeyParametersWithHash(CryptoAlgorithmIdentifier::SHA_1); + } else if (m_jwkAlgorithmName == "A128CBC") { + algorithm = algorithmRegisty.create(CryptoAlgorithmIdentifier::AES_CBC); + parameters = adoptRef(*new CryptoAlgorithmParametersDeprecated); + } else if (m_jwkAlgorithmName == "A192CBC") { + algorithm = algorithmRegisty.create(CryptoAlgorithmIdentifier::AES_CBC); + parameters = adoptRef(*new CryptoAlgorithmParametersDeprecated); + } else if (m_jwkAlgorithmName == "A256CBC") { + algorithm = algorithmRegisty.create(CryptoAlgorithmIdentifier::AES_CBC); + parameters = adoptRef(*new CryptoAlgorithmParametersDeprecated); + } else if (m_jwkAlgorithmName == "A128KW") { + algorithm = algorithmRegisty.create(CryptoAlgorithmIdentifier::AES_KW); + parameters = adoptRef(*new CryptoAlgorithmParametersDeprecated); + } else if (m_jwkAlgorithmName == "A192KW") { + algorithm = algorithmRegisty.create(CryptoAlgorithmIdentifier::AES_KW); + parameters = adoptRef(*new CryptoAlgorithmParametersDeprecated); + } else if (m_jwkAlgorithmName == "A256KW") { + algorithm = algorithmRegisty.create(CryptoAlgorithmIdentifier::AES_KW); + parameters = adoptRef(*new CryptoAlgorithmParametersDeprecated); + } else { + throwTypeError(m_exec, scope, "Unsupported JWK algorithm " + m_jwkAlgorithmName); + return std::nullopt; + } + + if (!suggestedAlgorithm) + return CryptoAlgorithmPair { algorithm, parameters }; + + if (!algorithm) + return CryptoAlgorithmPair { suggestedAlgorithm, suggestedParameters }; + + if (algorithm->identifier() != suggestedAlgorithm->identifier()) + return std::nullopt; + + if (algorithm->identifier() == CryptoAlgorithmIdentifier::HMAC) { + if (downcast<CryptoAlgorithmHmacParamsDeprecated>(*parameters).hash != downcast<CryptoAlgorithmHmacParamsDeprecated>(*suggestedParameters).hash) + return std::nullopt; + return CryptoAlgorithmPair { suggestedAlgorithm, suggestedParameters }; + } + if (algorithm->identifier() == CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5 + || algorithm->identifier() == CryptoAlgorithmIdentifier::RSA_OAEP) { + CryptoAlgorithmRsaKeyParamsWithHashDeprecated& rsaKeyParameters = downcast<CryptoAlgorithmRsaKeyParamsWithHashDeprecated>(*parameters); + CryptoAlgorithmRsaKeyParamsWithHashDeprecated& suggestedRSAKeyParameters = downcast<CryptoAlgorithmRsaKeyParamsWithHashDeprecated>(*suggestedParameters); + ASSERT(rsaKeyParameters.hasHash); + if (suggestedRSAKeyParameters.hasHash) { + if (suggestedRSAKeyParameters.hash != rsaKeyParameters.hash) + return std::nullopt; + return CryptoAlgorithmPair { suggestedAlgorithm, suggestedParameters }; + } + suggestedRSAKeyParameters.hasHash = true; + suggestedRSAKeyParameters.hash = rsaKeyParameters.hash; + } + + // Other algorithms don't have parameters. + return CryptoAlgorithmPair { suggestedAlgorithm, suggestedParameters }; +} + +static bool tryJWKKeyOpsValue(ExecState* exec, CryptoKeyUsageBitmap& usages, const String& operation, const String& tryOperation, CryptoKeyUsageBitmap tryUsage) +{ + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (operation == tryOperation) { + if (usages & tryUsage) { + throwTypeError(exec, scope, ASCIILiteral("JWK key_ops contains a duplicate operation")); + return false; + } + usages |= tryUsage; + } + return true; +} + +void JSCryptoKeySerializationJWK::reconcileUsages(CryptoKeyUsageBitmap& suggestedUsages) const +{ + VM& vm = m_exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + CryptoKeyUsageBitmap jwkUsages = 0; + + JSArray* keyOps; + if (getJSArrayFromJSON(m_exec, m_json.get(), "key_ops", keyOps)) { + for (size_t i = 0; i < keyOps->length(); ++i) { + JSValue jsValue = keyOps->getIndex(m_exec, i); + String operation; + if (!jsValue.getString(m_exec, operation)) { + if (!scope.exception()) + throwTypeError(m_exec, scope, ASCIILiteral("JWK key_ops attribute could not be processed")); + return; + } + if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("sign"), CryptoKeyUsageSign)) + return; + if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("verify"), CryptoKeyUsageVerify)) + return; + if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("encrypt"), CryptoKeyUsageEncrypt)) + return; + if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("decrypt"), CryptoKeyUsageDecrypt)) + return; + if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("wrapKey"), CryptoKeyUsageWrapKey)) + return; + if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("unwrapKey"), CryptoKeyUsageUnwrapKey)) + return; + if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("deriveKey"), CryptoKeyUsageDeriveKey)) + return; + if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("deriveBits"), CryptoKeyUsageDeriveBits)) + return; + } + } else { + RETURN_IF_EXCEPTION(scope, void()); + + String jwkUseString; + if (!getStringFromJSON(m_exec, m_json.get(), "use", jwkUseString)) { + // We have neither key_ops nor use. + return; + } + + if (jwkUseString == "enc") + jwkUsages |= (CryptoKeyUsageEncrypt | CryptoKeyUsageDecrypt | CryptoKeyUsageWrapKey | CryptoKeyUsageUnwrapKey); + else if (jwkUseString == "sig") + jwkUsages |= (CryptoKeyUsageSign | CryptoKeyUsageVerify); + else { + throwTypeError(m_exec, scope, "Unsupported JWK key use value \"" + jwkUseString + "\""); + return; + } + } + + suggestedUsages = suggestedUsages & jwkUsages; +} + +void JSCryptoKeySerializationJWK::reconcileExtractable(bool& suggestedExtractable) const +{ + bool jwkExtractable; + if (!getBooleanFromJSON(m_exec, m_json.get(), "ext", jwkExtractable)) + return; + + suggestedExtractable = suggestedExtractable && jwkExtractable; +} + +bool JSCryptoKeySerializationJWK::keySizeIsValid(size_t sizeInBits) const +{ + if (m_jwkAlgorithmName == "HS256") + return sizeInBits >= 256; + if (m_jwkAlgorithmName == "HS384") + return sizeInBits >= 384; + if (m_jwkAlgorithmName == "HS512") + return sizeInBits >= 512; + if (m_jwkAlgorithmName == "A128CBC") + return sizeInBits == 128; + if (m_jwkAlgorithmName == "A192CBC") + return sizeInBits == 192; + if (m_jwkAlgorithmName == "A256CBC") + return sizeInBits == 256; + if (m_jwkAlgorithmName == "A128KW") + return sizeInBits == 128; + if (m_jwkAlgorithmName == "A192KW") + return sizeInBits == 192; + if (m_jwkAlgorithmName == "A256KW") + return sizeInBits == 256; + if (m_jwkAlgorithmName == "RS256") + return sizeInBits >= 2048; + if (m_jwkAlgorithmName == "RS384") + return sizeInBits >= 2048; + if (m_jwkAlgorithmName == "RS512") + return sizeInBits >= 2048; + if (m_jwkAlgorithmName == "RSA1_5") + return sizeInBits >= 2048; + if (m_jwkAlgorithmName == "RSA_OAEP") + return sizeInBits >= 2048; + return true; +} + +std::unique_ptr<CryptoKeyData> JSCryptoKeySerializationJWK::keyDataOctetSequence() const +{ + VM& vm = m_exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + String keyBase64URL; + if (!getStringFromJSON(m_exec, m_json.get(), "k", keyBase64URL)) { + if (!scope.exception()) + throwTypeError(m_exec, scope, ASCIILiteral("Secret key data is not present is JWK")); + return nullptr; + } + + Vector<uint8_t> octetSequence; + if (!base64URLDecode(keyBase64URL, octetSequence)) { + throwTypeError(m_exec, scope, ASCIILiteral("Cannot decode base64url key data in JWK")); + return nullptr; + } + + if (!keySizeIsValid(octetSequence.size() * 8)) { + throwTypeError(m_exec, scope, "Key size is not valid for " + m_jwkAlgorithmName); + return nullptr; + } + + return std::make_unique<CryptoKeyDataOctetSequence>(octetSequence); +} + +std::unique_ptr<CryptoKeyData> JSCryptoKeySerializationJWK::keyDataRSAComponents() const +{ + VM& vm = m_exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + Vector<uint8_t> modulus; + Vector<uint8_t> exponent; + Vector<uint8_t> privateExponent; + + if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "n", modulus)) { + if (!scope.exception()) + throwTypeError(m_exec, scope, ASCIILiteral("Required JWK \"n\" member is missing")); + return nullptr; + } + + if (!keySizeIsValid(modulus.size() * 8)) { + throwTypeError(m_exec, scope, "Key size is not valid for " + m_jwkAlgorithmName); + return nullptr; + } + + if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "e", exponent)) { + if (!scope.exception()) + throwTypeError(m_exec, scope, ASCIILiteral("Required JWK \"e\" member is missing")); + return nullptr; + } + + if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "d", modulus)) { + RETURN_IF_EXCEPTION(scope, nullptr); + return CryptoKeyDataRSAComponents::createPublic(modulus, exponent); + } + + CryptoKeyDataRSAComponents::PrimeInfo firstPrimeInfo; + CryptoKeyDataRSAComponents::PrimeInfo secondPrimeInfo; + Vector<CryptoKeyDataRSAComponents::PrimeInfo> otherPrimeInfos; + if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "p", firstPrimeInfo.primeFactor)) { + RETURN_IF_EXCEPTION(scope, nullptr); + return CryptoKeyDataRSAComponents::createPrivate(modulus, exponent, privateExponent); + } + + if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "dp", firstPrimeInfo.factorCRTExponent)) { + RETURN_IF_EXCEPTION(scope, nullptr); + return CryptoKeyDataRSAComponents::createPrivate(modulus, exponent, privateExponent); + } + + if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "q", secondPrimeInfo.primeFactor)) { + RETURN_IF_EXCEPTION(scope, nullptr); + return CryptoKeyDataRSAComponents::createPrivate(modulus, exponent, privateExponent); + } + + if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "dq", secondPrimeInfo.factorCRTExponent)) { + RETURN_IF_EXCEPTION(scope, nullptr); + return CryptoKeyDataRSAComponents::createPrivate(modulus, exponent, privateExponent); + } + + if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "qi", secondPrimeInfo.factorCRTCoefficient)) { + RETURN_IF_EXCEPTION(scope, nullptr); + return CryptoKeyDataRSAComponents::createPrivate(modulus, exponent, privateExponent); + } + + JSArray* otherPrimeInfoJSArray; + if (!getJSArrayFromJSON(m_exec, m_json.get(), "oth", otherPrimeInfoJSArray)) { + RETURN_IF_EXCEPTION(scope, nullptr); + return CryptoKeyDataRSAComponents::createPrivateWithAdditionalData(modulus, exponent, privateExponent, firstPrimeInfo, secondPrimeInfo, otherPrimeInfos); + } + + for (size_t i = 0; i < otherPrimeInfoJSArray->length(); ++i) { + CryptoKeyDataRSAComponents::PrimeInfo info; + JSValue element = otherPrimeInfoJSArray->getIndex(m_exec, i); + RETURN_IF_EXCEPTION(scope, nullptr); + if (!element.isObject()) { + throwTypeError(m_exec, scope, ASCIILiteral("JWK \"oth\" array member is not an object")); + return nullptr; + } + if (!getBigIntegerVectorFromJSON(m_exec, asObject(element), "r", info.primeFactor)) { + if (!scope.exception()) + throwTypeError(m_exec, scope, ASCIILiteral("Cannot get prime factor for a prime in \"oth\" dictionary")); + return nullptr; + } + if (!getBigIntegerVectorFromJSON(m_exec, asObject(element), "d", info.factorCRTExponent)) { + if (!scope.exception()) + throwTypeError(m_exec, scope, ASCIILiteral("Cannot get factor CRT exponent for a prime in \"oth\" dictionary")); + return nullptr; + } + if (!getBigIntegerVectorFromJSON(m_exec, asObject(element), "t", info.factorCRTCoefficient)) { + if (!scope.exception()) + throwTypeError(m_exec, scope, ASCIILiteral("Cannot get factor CRT coefficient for a prime in \"oth\" dictionary")); + return nullptr; + } + otherPrimeInfos.append(info); + } + + return CryptoKeyDataRSAComponents::createPrivateWithAdditionalData(modulus, exponent, privateExponent, firstPrimeInfo, secondPrimeInfo, otherPrimeInfos); +} + +std::unique_ptr<CryptoKeyData> JSCryptoKeySerializationJWK::keyData() const +{ + VM& vm = m_exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + String jwkKeyType; + if (!getStringFromJSON(m_exec, m_json.get(), "kty", jwkKeyType)) { + if (!scope.exception()) + throwTypeError(m_exec, scope, ASCIILiteral("Required JWK \"kty\" member is missing")); + return nullptr; + } + + if (jwkKeyType == "oct") + return keyDataOctetSequence(); + + if (jwkKeyType == "RSA") + return keyDataRSAComponents(); + + throwTypeError(m_exec, scope, "Unsupported JWK key type " + jwkKeyType); + return nullptr; +} + +static void addToJSON(ExecState* exec, JSObject* json, const char* key, const String& value) +{ + VM& vm = exec->vm(); + Identifier identifier = Identifier::fromString(&vm, key); + json->putDirect(vm, identifier, jsString(exec, value)); +} + +static void buildJSONForOctetSequence(ExecState* exec, const Vector<uint8_t>& keyData, JSObject* result) +{ + addToJSON(exec, result, "kty", "oct"); + addToJSON(exec, result, "k", base64URLEncode(keyData)); +} + +static void buildJSONForRSAComponents(JSC::ExecState* exec, const CryptoKeyDataRSAComponents& data, JSC::JSObject* result) +{ + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + addToJSON(exec, result, "kty", "RSA"); + addToJSON(exec, result, "n", base64URLEncode(data.modulus())); + addToJSON(exec, result, "e", base64URLEncode(data.exponent())); + + if (data.type() == CryptoKeyDataRSAComponents::Type::Public) + return; + + addToJSON(exec, result, "d", base64URLEncode(data.privateExponent())); + + if (!data.hasAdditionalPrivateKeyParameters()) + return; + + addToJSON(exec, result, "p", base64URLEncode(data.firstPrimeInfo().primeFactor)); + addToJSON(exec, result, "q", base64URLEncode(data.secondPrimeInfo().primeFactor)); + addToJSON(exec, result, "dp", base64URLEncode(data.firstPrimeInfo().factorCRTExponent)); + addToJSON(exec, result, "dq", base64URLEncode(data.secondPrimeInfo().factorCRTExponent)); + addToJSON(exec, result, "qi", base64URLEncode(data.secondPrimeInfo().factorCRTCoefficient)); + + if (data.otherPrimeInfos().isEmpty()) + return; + + JSArray* oth = constructEmptyArray(exec, 0, exec->lexicalGlobalObject(), data.otherPrimeInfos().size()); + RETURN_IF_EXCEPTION(scope, void()); + for (size_t i = 0, size = data.otherPrimeInfos().size(); i < size; ++i) { + JSObject* jsPrimeInfo = constructEmptyObject(exec); + addToJSON(exec, jsPrimeInfo, "r", base64URLEncode(data.otherPrimeInfos()[i].primeFactor)); + addToJSON(exec, jsPrimeInfo, "d", base64URLEncode(data.otherPrimeInfos()[i].factorCRTExponent)); + addToJSON(exec, jsPrimeInfo, "t", base64URLEncode(data.otherPrimeInfos()[i].factorCRTCoefficient)); + oth->putDirectIndex(exec, i, jsPrimeInfo); + RETURN_IF_EXCEPTION(scope, void()); + } + result->putDirect(vm, Identifier::fromString(exec, "oth"), oth); +} + +static void addBoolToJSON(ExecState* exec, JSObject* json, const char* key, bool value) +{ + VM& vm = exec->vm(); + Identifier identifier = Identifier::fromString(&vm, key); + json->putDirect(vm, identifier, jsBoolean(value)); +} + +static void addJWKAlgorithmToJSON(ExecState* exec, JSObject* json, const CryptoKey& key) +{ + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + String jwkAlgorithm; + switch (key.algorithmIdentifier()) { + case CryptoAlgorithmIdentifier::HMAC: + switch (downcast<CryptoKeyHMAC>(key).hashAlgorithmIdentifier()) { + case CryptoAlgorithmIdentifier::SHA_256: + if (downcast<CryptoKeyHMAC>(key).key().size() * 8 >= 256) + jwkAlgorithm = "HS256"; + break; + case CryptoAlgorithmIdentifier::SHA_384: + if (downcast<CryptoKeyHMAC>(key).key().size() * 8 >= 384) + jwkAlgorithm = "HS384"; + break; + case CryptoAlgorithmIdentifier::SHA_512: + if (downcast<CryptoKeyHMAC>(key).key().size() * 8 >= 512) + jwkAlgorithm = "HS512"; + break; + default: + break; + } + break; + case CryptoAlgorithmIdentifier::AES_CBC: + switch (downcast<CryptoKeyAES>(key).key().size() * 8) { + case 128: + jwkAlgorithm = "A128CBC"; + break; + case 192: + jwkAlgorithm = "A192CBC"; + break; + case 256: + jwkAlgorithm = "A256CBC"; + break; + } + break; + case CryptoAlgorithmIdentifier::AES_KW: + switch (downcast<CryptoKeyAES>(key).key().size() * 8) { + case 128: + jwkAlgorithm = "A128KW"; + break; + case 192: + jwkAlgorithm = "A192KW"; + break; + case 256: + jwkAlgorithm = "A256KW"; + break; + } + break; + case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5: { + const CryptoKeyRSA& rsaKey = downcast<CryptoKeyRSA>(key); + CryptoAlgorithmIdentifier hash; + if (!rsaKey.isRestrictedToHash(hash)) + break; + if (rsaKey.keySizeInBits() < 2048) + break; + switch (hash) { + case CryptoAlgorithmIdentifier::SHA_256: + jwkAlgorithm = "RS256"; + break; + case CryptoAlgorithmIdentifier::SHA_384: + jwkAlgorithm = "RS384"; + break; + case CryptoAlgorithmIdentifier::SHA_512: + jwkAlgorithm = "RS512"; + break; + default: + break; + } + break; + } + case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: { + const CryptoKeyRSA& rsaKey = downcast<CryptoKeyRSA>(key); + if (rsaKey.keySizeInBits() < 2048) + break; + jwkAlgorithm = "RSA1_5"; + break; + } + case CryptoAlgorithmIdentifier::RSA_OAEP: { + const CryptoKeyRSA& rsaKey = downcast<CryptoKeyRSA>(key); + CryptoAlgorithmIdentifier hash; + // WebCrypto RSA-OAEP keys are not tied to any particular hash, unless previously imported from JWK, which only supports SHA-1. + if (rsaKey.isRestrictedToHash(hash) && hash != CryptoAlgorithmIdentifier::SHA_1) + break; + if (rsaKey.keySizeInBits() < 2048) + break; + jwkAlgorithm = "RSA-OAEP"; + break; + } + default: + break; + } + + if (jwkAlgorithm.isNull()) { + // The spec doesn't currently tell whether export should fail, or just skip "alg" (which is an optional key in JWK). + throwTypeError(exec, scope, ASCIILiteral("Key algorithm and size do not map to any JWK algorithm identifier")); + return; + } + + addToJSON(exec, json, "alg", jwkAlgorithm); +} + +static void addUsagesToJSON(ExecState* exec, JSObject* json, CryptoKeyUsageBitmap usages) +{ + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + JSArray* keyOps = constructEmptyArray(exec, 0, exec->lexicalGlobalObject(), 0); + RETURN_IF_EXCEPTION(scope, void()); + + unsigned index = 0; + if (usages & CryptoKeyUsageSign) { + keyOps->putDirectIndex(exec, index++, jsNontrivialString(exec, ASCIILiteral("sign"))); + RETURN_IF_EXCEPTION(scope, void()); + } + if (usages & CryptoKeyUsageVerify) { + keyOps->putDirectIndex(exec, index++, jsNontrivialString(exec, ASCIILiteral("verify"))); + RETURN_IF_EXCEPTION(scope, void()); + } + if (usages & CryptoKeyUsageEncrypt) { + keyOps->putDirectIndex(exec, index++, jsNontrivialString(exec, ASCIILiteral("encrypt"))); + RETURN_IF_EXCEPTION(scope, void()); + } + if (usages & CryptoKeyUsageDecrypt) { + keyOps->putDirectIndex(exec, index++, jsNontrivialString(exec, ASCIILiteral("decrypt"))); + RETURN_IF_EXCEPTION(scope, void()); + } + if (usages & CryptoKeyUsageWrapKey) { + keyOps->putDirectIndex(exec, index++, jsNontrivialString(exec, ASCIILiteral("wrapKey"))); + RETURN_IF_EXCEPTION(scope, void()); + } + if (usages & CryptoKeyUsageUnwrapKey) { + keyOps->putDirectIndex(exec, index++, jsNontrivialString(exec, ASCIILiteral("unwrapKey"))); + RETURN_IF_EXCEPTION(scope, void()); + } + if (usages & CryptoKeyUsageDeriveKey) { + keyOps->putDirectIndex(exec, index++, jsNontrivialString(exec, ASCIILiteral("deriveKey"))); + RETURN_IF_EXCEPTION(scope, void()); + } + if (usages & CryptoKeyUsageDeriveBits) { + keyOps->putDirectIndex(exec, index++, jsNontrivialString(exec, ASCIILiteral("deriveBits"))); + RETURN_IF_EXCEPTION(scope, void()); + } + + json->putDirect(vm, Identifier::fromString(exec, "key_ops"), keyOps); +} + +String JSCryptoKeySerializationJWK::serialize(ExecState* exec, const CryptoKey& key) +{ + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + std::unique_ptr<CryptoKeyData> keyData = key.exportData(); + if (!keyData) { + // This generally shouldn't happen as long as all key types implement exportData(), but as underlying libraries return errors, there may be some rare failure conditions. + throwTypeError(exec, scope, ASCIILiteral("Couldn't export key material")); + return String(); + } + + JSObject* result = constructEmptyObject(exec); + + addJWKAlgorithmToJSON(exec, result, key); + RETURN_IF_EXCEPTION(scope, String()); + + addBoolToJSON(exec, result, "ext", key.extractable()); + + addUsagesToJSON(exec, result, key.usagesBitmap()); + RETURN_IF_EXCEPTION(scope, String()); + + if (is<CryptoKeyDataOctetSequence>(*keyData)) + buildJSONForOctetSequence(exec, downcast<CryptoKeyDataOctetSequence>(*keyData).octetSequence(), result); + else if (is<CryptoKeyDataRSAComponents>(*keyData)) + buildJSONForRSAComponents(exec, downcast<CryptoKeyDataRSAComponents>(*keyData), result); + else { + throwTypeError(exec, scope, ASCIILiteral("Key doesn't support exportKey")); + return String(); + } + RETURN_IF_EXCEPTION(scope, String()); + + return JSONStringify(exec, result, 0); +} + +} // namespace WebCore + +#endif // ENABLE(SUBTLE_CRYPTO) diff --git a/Source/WebCore/bindings/js/JSCryptoKeySerializationJWK.h b/Source/WebCore/bindings/js/JSCryptoKeySerializationJWK.h new file mode 100644 index 000000000..47a5a03be --- /dev/null +++ b/Source/WebCore/bindings/js/JSCryptoKeySerializationJWK.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2013 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. + */ + +#pragma once + +#if ENABLE(SUBTLE_CRYPTO) + +#include "CryptoKeySerialization.h" +#include <heap/Strong.h> +#include <wtf/text/WTFString.h> + +namespace JSC { +class ExecState; +class JSObject; +} + +namespace WebCore { + +class CryptoAlgorithmParametersDeprecated; +class CryptoKey; +class CryptoKeyDataRSAComponents; + +class JSCryptoKeySerializationJWK final : public CryptoKeySerialization { +WTF_MAKE_NONCOPYABLE(JSCryptoKeySerializationJWK); +public: + JSCryptoKeySerializationJWK(JSC::ExecState*, const String&); + virtual ~JSCryptoKeySerializationJWK(); + + static String serialize(JSC::ExecState* exec, const CryptoKey&); + +private: + std::optional<CryptoAlgorithmPair> reconcileAlgorithm(CryptoAlgorithm*, CryptoAlgorithmParametersDeprecated*) const override; + + void reconcileUsages(CryptoKeyUsageBitmap&) const override; + void reconcileExtractable(bool&) const override; + + std::unique_ptr<CryptoKeyData> keyData() const override; + + bool keySizeIsValid(size_t sizeInBits) const; + std::unique_ptr<CryptoKeyData> keyDataOctetSequence() const; + std::unique_ptr<CryptoKeyData> keyDataRSAComponents() const; + + JSC::ExecState* m_exec; + JSC::Strong<JSC::JSObject> m_json; + + mutable String m_jwkAlgorithmName; // Stored when reconcileAlgorithm is called, and used later. +}; + +} // namespace WebCore + +#endif // ENABLE(SUBTLE_CRYPTO) diff --git a/Source/WebCore/bindings/js/JSCryptoOperationData.cpp b/Source/WebCore/bindings/js/JSCryptoOperationData.cpp new file mode 100644 index 000000000..2e35f2e14 --- /dev/null +++ b/Source/WebCore/bindings/js/JSCryptoOperationData.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2013, 2016 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 "JSCryptoOperationData.h" + +#if ENABLE(SUBTLE_CRYPTO) + +#include "JSDOMConvertBufferSource.h" +#include <heap/HeapInlines.h> + +using namespace JSC; + +namespace WebCore { + +CryptoOperationData cryptoOperationDataFromJSValue(ExecState& state, ThrowScope& scope, JSValue value) +{ + VM& vm = state.vm(); + if (auto* buffer = toUnsharedArrayBuffer(vm, value)) + return { static_cast<uint8_t*>(buffer->data()), buffer->byteLength() }; + + if (auto bufferView = toUnsharedArrayBufferView(vm, value)) + return { static_cast<uint8_t*>(bufferView->baseAddress()), bufferView->byteLength() }; + + throwTypeError(&state, scope, ASCIILiteral("Only ArrayBuffer and ArrayBufferView objects can be passed as CryptoOperationData")); + return { }; +} + +} // namespace WebCore + +#endif // ENABLE(SUBTLE_CRYPTO) diff --git a/Source/WebCore/bindings/js/JSCryptoOperationData.h b/Source/WebCore/bindings/js/JSCryptoOperationData.h new file mode 100644 index 000000000..909e13242 --- /dev/null +++ b/Source/WebCore/bindings/js/JSCryptoOperationData.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2013 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. + */ + +#pragma once + +#if ENABLE(SUBTLE_CRYPTO) + +namespace JSC { +class ExecState; +class JSValue; +class ThrowScope; +} + +namespace WebCore { + +using CryptoOperationData = std::pair<const uint8_t*, size_t>; + +CryptoOperationData cryptoOperationDataFromJSValue(JSC::ExecState&, JSC::ThrowScope&, JSC::JSValue); + +} // namespace WebCore + +#endif // ENABLE(SUBTLE_CRYPTO) diff --git a/Source/WebCore/bindings/js/JSCustomElementInterface.cpp b/Source/WebCore/bindings/js/JSCustomElementInterface.cpp new file mode 100644 index 000000000..793ecb842 --- /dev/null +++ b/Source/WebCore/bindings/js/JSCustomElementInterface.cpp @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2015-2016 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 "JSCustomElementInterface.h" + +#include "DOMWrapperWorld.h" +#include "HTMLUnknownElement.h" +#include "JSDOMBinding.h" +#include "JSDOMGlobalObject.h" +#include "JSElement.h" +#include "JSHTMLElement.h" +#include "JSMainThreadExecState.h" +#include "JSMainThreadExecStateInstrumentation.h" +#include "ScriptExecutionContext.h" +#include <heap/WeakInlines.h> +#include <runtime/JSLock.h> + +using namespace JSC; + +namespace WebCore { + +JSCustomElementInterface::JSCustomElementInterface(const QualifiedName& name, JSObject* constructor, JSDOMGlobalObject* globalObject) + : ActiveDOMCallback(globalObject->scriptExecutionContext()) + , m_name(name) + , m_constructor(constructor) + , m_isolatedWorld(&globalObject->world()) +{ +} + +JSCustomElementInterface::~JSCustomElementInterface() +{ +} + +static RefPtr<Element> constructCustomElementSynchronously(Document&, VM&, ExecState&, JSObject* constructor, const AtomicString& localName); + +Ref<Element> JSCustomElementInterface::constructElementWithFallback(Document& document, const AtomicString& localName) +{ + if (auto element = tryToConstructCustomElement(document, localName)) + return element.releaseNonNull(); + + auto element = HTMLUnknownElement::create(QualifiedName(nullAtom, localName, HTMLNames::xhtmlNamespaceURI), document); + element->setIsCustomElementUpgradeCandidate(); + element->setIsFailedCustomElement(*this); + + return WTFMove(element); +} + +Ref<Element> JSCustomElementInterface::constructElementWithFallback(Document& document, const QualifiedName& name) +{ + if (auto element = tryToConstructCustomElement(document, name.localName())) { + if (name.prefix() != nullAtom) + element->setPrefix(name.prefix()); + return element.releaseNonNull(); + } + + auto element = HTMLUnknownElement::create(name, document); + element->setIsCustomElementUpgradeCandidate(); + element->setIsFailedCustomElement(*this); + + return WTFMove(element); +} + +RefPtr<Element> JSCustomElementInterface::tryToConstructCustomElement(Document& document, const AtomicString& localName) +{ + if (!canInvokeCallback()) + return nullptr; + + Ref<JSCustomElementInterface> protectedThis(*this); + + VM& vm = m_isolatedWorld->vm(); + JSLockHolder lock(vm); + auto scope = DECLARE_CATCH_SCOPE(vm); + + if (!m_constructor) + return nullptr; + + ASSERT(&document == scriptExecutionContext()); + auto& state = *document.execState(); + auto element = constructCustomElementSynchronously(document, vm, state, m_constructor.get(), localName); + ASSERT(!!scope.exception() == !element); + if (!element) { + auto* exception = scope.exception(); + scope.clearException(); + reportException(&state, exception); + return nullptr; + } + + return element; +} + +// https://dom.spec.whatwg.org/#concept-create-element +// 6. 1. If the synchronous custom elements flag is set +static RefPtr<Element> constructCustomElementSynchronously(Document& document, VM& vm, ExecState& state, JSObject* constructor, const AtomicString& localName) +{ + auto scope = DECLARE_THROW_SCOPE(vm); + ConstructData constructData; + ConstructType constructType = constructor->methodTable()->getConstructData(constructor, constructData); + if (constructType == ConstructType::None) { + ASSERT_NOT_REACHED(); + return nullptr; + } + + InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionConstruct(&document, constructType, constructData); + MarkedArgumentBuffer args; + JSValue newElement = construct(&state, constructor, constructType, constructData, args); + InspectorInstrumentation::didCallFunction(cookie, &document); + RETURN_IF_EXCEPTION(scope, nullptr); + + ASSERT(!newElement.isEmpty()); + HTMLElement* wrappedElement = JSHTMLElement::toWrapped(vm, newElement); + if (!wrappedElement) { + throwTypeError(&state, scope, ASCIILiteral("The result of constructing a custom element must be a HTMLElement")); + return nullptr; + } + + if (wrappedElement->hasAttributes()) { + throwNotSupportedError(state, scope, ASCIILiteral("A newly constructed custom element must not have attributes")); + return nullptr; + } + if (wrappedElement->hasChildNodes()) { + throwNotSupportedError(state, scope, ASCIILiteral("A newly constructed custom element must not have child nodes")); + return nullptr; + } + if (wrappedElement->parentNode()) { + throwNotSupportedError(state, scope, ASCIILiteral("A newly constructed custom element must not have a parent node")); + return nullptr; + } + if (&wrappedElement->document() != &document) { + throwNotSupportedError(state, scope, ASCIILiteral("A newly constructed custom element belongs to a wrong docuemnt")); + return nullptr; + } + ASSERT(wrappedElement->namespaceURI() == HTMLNames::xhtmlNamespaceURI); + if (wrappedElement->localName() != localName) { + throwNotSupportedError(state, scope, ASCIILiteral("A newly constructed custom element belongs to a wrong docuemnt")); + return nullptr; + } + + return wrappedElement; +} + +void JSCustomElementInterface::upgradeElement(Element& element) +{ + ASSERT(element.tagQName() == name()); + ASSERT(element.isCustomElementUpgradeCandidate()); + if (!canInvokeCallback()) + return; + + Ref<JSCustomElementInterface> protectedThis(*this); + VM& vm = m_isolatedWorld->vm(); + JSLockHolder lock(vm); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (!m_constructor) + return; + + ScriptExecutionContext* context = scriptExecutionContext(); + if (!context) + return; + ASSERT(context->isDocument()); + JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(context, *m_isolatedWorld); + ExecState* state = globalObject->globalExec(); + RETURN_IF_EXCEPTION(scope, void()); + + ConstructData constructData; + ConstructType constructType = m_constructor->methodTable()->getConstructData(m_constructor.get(), constructData); + if (constructType == ConstructType::None) { + ASSERT_NOT_REACHED(); + return; + } + + CustomElementReactionQueue::enqueuePostUpgradeReactions(element); + + m_constructionStack.append(&element); + + MarkedArgumentBuffer args; + InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionConstruct(context, constructType, constructData); + JSValue returnedElement = construct(state, m_constructor.get(), constructType, constructData, args); + InspectorInstrumentation::didCallFunction(cookie, context); + + m_constructionStack.removeLast(); + + if (UNLIKELY(scope.exception())) { + element.setIsFailedCustomElement(*this); + reportException(state, scope.exception()); + return; + } + + Element* wrappedElement = JSElement::toWrapped(vm, returnedElement); + if (!wrappedElement || wrappedElement != &element) { + element.setIsFailedCustomElement(*this); + reportException(state, createDOMException(state, INVALID_STATE_ERR, "Custom element constructor failed to upgrade an element")); + return; + } + element.setIsDefinedCustomElement(*this); +} + +void JSCustomElementInterface::invokeCallback(Element& element, JSObject* callback, const WTF::Function<void(ExecState*, JSDOMGlobalObject*, MarkedArgumentBuffer&)>& addArguments) +{ + if (!canInvokeCallback()) + return; + + auto* context = scriptExecutionContext(); + if (!context) + return; + + Ref<JSCustomElementInterface> protectedThis(*this); + JSLockHolder lock(m_isolatedWorld->vm()); + + ASSERT(context); + ASSERT(context->isDocument()); + JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(context, *m_isolatedWorld); + ExecState* state = globalObject->globalExec(); + + JSObject* jsElement = asObject(toJS(state, globalObject, element)); + + CallData callData; + CallType callType = callback->methodTable()->getCallData(callback, callData); + ASSERT(callType != CallType::None); + + MarkedArgumentBuffer args; + addArguments(state, globalObject, args); + + InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(context, callType, callData); + + NakedPtr<JSC::Exception> exception; + JSMainThreadExecState::call(state, callback, callType, callData, jsElement, args, exception); + + InspectorInstrumentation::didCallFunction(cookie, context); + + if (exception) + reportException(state, exception); +} + +void JSCustomElementInterface::setConnectedCallback(JSC::JSObject* callback) +{ + m_connectedCallback = callback; +} + +void JSCustomElementInterface::invokeConnectedCallback(Element& element) +{ + invokeCallback(element, m_connectedCallback.get()); +} + +void JSCustomElementInterface::setDisconnectedCallback(JSC::JSObject* callback) +{ + m_disconnectedCallback = callback; +} + +void JSCustomElementInterface::invokeDisconnectedCallback(Element& element) +{ + invokeCallback(element, m_disconnectedCallback.get()); +} + +void JSCustomElementInterface::setAdoptedCallback(JSC::JSObject* callback) +{ + m_adoptedCallback = callback; +} + +void JSCustomElementInterface::invokeAdoptedCallback(Element& element, Document& oldDocument, Document& newDocument) +{ + invokeCallback(element, m_adoptedCallback.get(), [&](ExecState* state, JSDOMGlobalObject* globalObject, MarkedArgumentBuffer& args) { + args.append(toJS(state, globalObject, oldDocument)); + args.append(toJS(state, globalObject, newDocument)); + }); +} + +void JSCustomElementInterface::setAttributeChangedCallback(JSC::JSObject* callback, const Vector<String>& observedAttributes) +{ + m_attributeChangedCallback = callback; + m_observedAttributes.clear(); + for (auto& name : observedAttributes) + m_observedAttributes.add(name); +} + +void JSCustomElementInterface::invokeAttributeChangedCallback(Element& element, const QualifiedName& attributeName, const AtomicString& oldValue, const AtomicString& newValue) +{ + invokeCallback(element, m_attributeChangedCallback.get(), [&](ExecState* state, JSDOMGlobalObject*, MarkedArgumentBuffer& args) { + args.append(toJS<IDLDOMString>(*state, attributeName.localName())); + args.append(toJS<IDLNullable<IDLDOMString>>(*state, oldValue)); + args.append(toJS<IDLNullable<IDLDOMString>>(*state, newValue)); + args.append(toJS<IDLNullable<IDLDOMString>>(*state, attributeName.namespaceURI())); + }); +} + +void JSCustomElementInterface::didUpgradeLastElementInConstructionStack() +{ + m_constructionStack.last() = nullptr; +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSCustomElementInterface.h b/Source/WebCore/bindings/js/JSCustomElementInterface.h new file mode 100644 index 000000000..8a3f656ee --- /dev/null +++ b/Source/WebCore/bindings/js/JSCustomElementInterface.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2015, 2016 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. + */ + +#pragma once + +#include "ActiveDOMCallback.h" +#include "QualifiedName.h" +#include <heap/Weak.h> +#include <heap/WeakInlines.h> +#include <runtime/JSObject.h> +#include <wtf/Forward.h> +#include <wtf/Function.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> +#include <wtf/text/AtomicStringHash.h> + +namespace JSC { +class JSObject; +class PrivateName; +} + +namespace WebCore { + +class DOMWrapperWorld; +class Document; +class Element; +class JSDOMGlobalObject; +class MathMLElement; +class SVGElement; + +class JSCustomElementInterface : public RefCounted<JSCustomElementInterface>, public ActiveDOMCallback { +public: + static Ref<JSCustomElementInterface> create(const QualifiedName& name, JSC::JSObject* callback, JSDOMGlobalObject* globalObject) + { + return adoptRef(*new JSCustomElementInterface(name, callback, globalObject)); + } + + Ref<Element> constructElementWithFallback(Document&, const AtomicString&); + Ref<Element> constructElementWithFallback(Document&, const QualifiedName&); + + void upgradeElement(Element&); + + void setConnectedCallback(JSC::JSObject*); + bool hasConnectedCallback() const { return !!m_connectedCallback; } + void invokeConnectedCallback(Element&); + + void setDisconnectedCallback(JSC::JSObject*); + bool hasDisconnectedCallback() const { return !!m_disconnectedCallback; } + void invokeDisconnectedCallback(Element&); + + void setAdoptedCallback(JSC::JSObject*); + bool hasAdoptedCallback() const { return !!m_adoptedCallback; } + void invokeAdoptedCallback(Element&, Document& oldDocument, Document& newDocument); + + void setAttributeChangedCallback(JSC::JSObject* callback, const Vector<String>& observedAttributes); + bool observesAttribute(const AtomicString& name) const { return m_observedAttributes.contains(name); } + void invokeAttributeChangedCallback(Element&, const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue); + + ScriptExecutionContext* scriptExecutionContext() const { return ContextDestructionObserver::scriptExecutionContext(); } + JSC::JSObject* constructor() { return m_constructor.get(); } + + const QualifiedName& name() const { return m_name; } + + bool isUpgradingElement() const { return !m_constructionStack.isEmpty(); } + Element* lastElementInConstructionStack() const { return m_constructionStack.last().get(); } + void didUpgradeLastElementInConstructionStack(); + + virtual ~JSCustomElementInterface(); + +private: + JSCustomElementInterface(const QualifiedName&, JSC::JSObject* callback, JSDOMGlobalObject*); + + RefPtr<Element> tryToConstructCustomElement(Document&, const AtomicString&); + + void invokeCallback(Element&, JSC::JSObject* callback, const WTF::Function<void(JSC::ExecState*, JSDOMGlobalObject*, JSC::MarkedArgumentBuffer&)>& addArguments = { }); + + QualifiedName m_name; + JSC::Weak<JSC::JSObject> m_constructor; + JSC::Weak<JSC::JSObject> m_connectedCallback; + JSC::Weak<JSC::JSObject> m_disconnectedCallback; + JSC::Weak<JSC::JSObject> m_adoptedCallback; + JSC::Weak<JSC::JSObject> m_attributeChangedCallback; + RefPtr<DOMWrapperWorld> m_isolatedWorld; + Vector<RefPtr<Element>, 1> m_constructionStack; + HashSet<AtomicString> m_observedAttributes; +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSCustomElementRegistryCustom.cpp b/Source/WebCore/bindings/js/JSCustomElementRegistryCustom.cpp new file mode 100644 index 000000000..cf9e96d27 --- /dev/null +++ b/Source/WebCore/bindings/js/JSCustomElementRegistryCustom.cpp @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2015, 2016 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. ``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 + * 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 "JSCustomElementRegistry.h" + +#include "CustomElementRegistry.h" +#include "Document.h" +#include "HTMLNames.h" +#include "JSCustomElementInterface.h" +#include "JSDOMBinding.h" +#include "JSDOMConvert.h" +#include "JSDOMPromise.h" + +using namespace JSC; + +namespace WebCore { + +static JSObject* getCustomElementCallback(ExecState& state, JSObject& prototype, const Identifier& id) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSValue callback = prototype.get(&state, id); + RETURN_IF_EXCEPTION(scope, nullptr); + if (callback.isUndefined()) + return nullptr; + if (!callback.isFunction()) { + throwTypeError(&state, scope, ASCIILiteral("A custom element callback must be a function")); + return nullptr; + } + return callback.getObject(); +} + +static bool validateCustomElementNameAndThrowIfNeeded(ExecState& state, const AtomicString& name) +{ + auto scope = DECLARE_THROW_SCOPE(state.vm()); + + switch (Document::validateCustomElementName(name)) { + case CustomElementNameValidationStatus::Valid: + return true; + case CustomElementNameValidationStatus::ConflictsWithBuiltinNames: + throwSyntaxError(&state, scope, ASCIILiteral("Custom element name cannot be same as one of the builtin elements")); + return false; + case CustomElementNameValidationStatus::NoHyphen: + throwSyntaxError(&state, scope, ASCIILiteral("Custom element name must contain a hyphen")); + return false; + case CustomElementNameValidationStatus::ContainsUpperCase: + throwSyntaxError(&state, scope, ASCIILiteral("Custom element name cannot contain an upper case letter")); + return false; + } + ASSERT_NOT_REACHED(); + return false; +} + +// https://html.spec.whatwg.org/#dom-customelementregistry-define +JSValue JSCustomElementRegistry::define(ExecState& state) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(state.argumentCount() < 2)) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + + AtomicString localName(state.uncheckedArgument(0).toString(&state)->toAtomicString(&state)); + RETURN_IF_EXCEPTION(scope, JSValue()); + + JSValue constructorValue = state.uncheckedArgument(1); + if (!constructorValue.isConstructor()) + return throwTypeError(&state, scope, ASCIILiteral("The second argument must be a constructor")); + JSObject* constructor = constructorValue.getObject(); + + if (!validateCustomElementNameAndThrowIfNeeded(state, localName)) + return jsUndefined(); + + CustomElementRegistry& registry = wrapped(); + + if (registry.elementDefinitionIsRunning()) { + throwNotSupportedError(state, scope, ASCIILiteral("Cannot define a custom element while defining another custom element")); + return jsUndefined(); + } + SetForScope<bool> change(registry.elementDefinitionIsRunning(), true); + + if (registry.findInterface(localName)) { + throwNotSupportedError(state, scope, ASCIILiteral("Cannot define multiple custom elements with the same tag name")); + return jsUndefined(); + } + + if (registry.containsConstructor(constructor)) { + throwNotSupportedError(state, scope, ASCIILiteral("Cannot define multiple custom elements with the same class")); + return jsUndefined(); + } + + JSValue prototypeValue = constructor->get(&state, vm.propertyNames->prototype); + RETURN_IF_EXCEPTION(scope, JSValue()); + if (!prototypeValue.isObject()) + return throwTypeError(&state, scope, ASCIILiteral("Custom element constructor's prototype must be an object")); + JSObject& prototypeObject = *asObject(prototypeValue); + + QualifiedName name(nullAtom, localName, HTMLNames::xhtmlNamespaceURI); + auto elementInterface = JSCustomElementInterface::create(name, constructor, globalObject()); + + auto* connectedCallback = getCustomElementCallback(state, prototypeObject, Identifier::fromString(&vm, "connectedCallback")); + if (connectedCallback) + elementInterface->setConnectedCallback(connectedCallback); + RETURN_IF_EXCEPTION(scope, JSValue()); + + auto* disconnectedCallback = getCustomElementCallback(state, prototypeObject, Identifier::fromString(&vm, "disconnectedCallback")); + if (disconnectedCallback) + elementInterface->setDisconnectedCallback(disconnectedCallback); + RETURN_IF_EXCEPTION(scope, JSValue()); + + auto* adoptedCallback = getCustomElementCallback(state, prototypeObject, Identifier::fromString(&vm, "adoptedCallback")); + if (adoptedCallback) + elementInterface->setAdoptedCallback(adoptedCallback); + RETURN_IF_EXCEPTION(scope, JSValue()); + + auto* attributeChangedCallback = getCustomElementCallback(state, prototypeObject, Identifier::fromString(&vm, "attributeChangedCallback")); + RETURN_IF_EXCEPTION(scope, JSValue()); + if (attributeChangedCallback) { + auto observedAttributesValue = constructor->get(&state, Identifier::fromString(&state, "observedAttributes")); + RETURN_IF_EXCEPTION(scope, JSValue()); + if (!observedAttributesValue.isUndefined()) { + auto observedAttributes = convert<IDLSequence<IDLDOMString>>(state, observedAttributesValue); + RETURN_IF_EXCEPTION(scope, JSValue()); + elementInterface->setAttributeChangedCallback(attributeChangedCallback, observedAttributes); + } + } + + auto addToGlobalObjectWithPrivateName = [&] (JSObject* objectToAdd) { + if (objectToAdd) { + PrivateName uniquePrivateName; + globalObject()->putDirect(vm, uniquePrivateName, objectToAdd); + } + }; + + addToGlobalObjectWithPrivateName(constructor); + addToGlobalObjectWithPrivateName(connectedCallback); + addToGlobalObjectWithPrivateName(disconnectedCallback); + addToGlobalObjectWithPrivateName(adoptedCallback); + addToGlobalObjectWithPrivateName(attributeChangedCallback); + + registry.addElementDefinition(WTFMove(elementInterface)); + + return jsUndefined(); +} + +// https://html.spec.whatwg.org/#dom-customelementregistry-whendefined +static JSValue whenDefinedPromise(ExecState& state, JSDOMGlobalObject& globalObject, CustomElementRegistry& registry, JSPromiseDeferred& promiseDeferred) +{ + auto scope = DECLARE_THROW_SCOPE(state.vm()); + + if (UNLIKELY(state.argumentCount() < 1)) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + + AtomicString localName(state.uncheckedArgument(0).toString(&state)->toAtomicString(&state)); + RETURN_IF_EXCEPTION(scope, JSValue()); + + if (!validateCustomElementNameAndThrowIfNeeded(state, localName)) { + ASSERT(scope.exception()); + return jsUndefined(); + } + + if (registry.findInterface(localName)) { + DeferredPromise::create(globalObject, promiseDeferred)->resolve(); + return promiseDeferred.promise(); + } + + auto result = registry.promiseMap().ensure(localName, [&] { + return DeferredPromise::create(globalObject, promiseDeferred); + }); + + return result.iterator->value->promise(); +} + +JSValue JSCustomElementRegistry::whenDefined(ExecState& state) +{ + auto scope = DECLARE_CATCH_SCOPE(state.vm()); + + ASSERT(globalObject()); + auto promiseDeferred = JSPromiseDeferred::create(&state, globalObject()); + ASSERT(promiseDeferred); + JSValue promise = whenDefinedPromise(state, *globalObject(), wrapped(), *promiseDeferred); + + if (UNLIKELY(scope.exception())) { + rejectPromiseWithExceptionIfAny(state, *globalObject(), *promiseDeferred); + ASSERT(!scope.exception()); + return promiseDeferred->promise(); + } + + return promise; +} + +} diff --git a/Source/WebCore/bindings/js/JSRTCStatsResponseCustom.cpp b/Source/WebCore/bindings/js/JSCustomEventCustom.cpp index 821dc1b1f..8cfb769f4 100644 --- a/Source/WebCore/bindings/js/JSRTCStatsResponseCustom.cpp +++ b/Source/WebCore/bindings/js/JSCustomEventCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) Research In Motion Limited 2013. All rights reserved. + * Copyright (C) 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,28 +24,37 @@ */ #include "config.h" +#include "JSCustomEvent.h" -#if ENABLE(MEDIA_STREAM) -#include "JSRTCStatsResponse.h" - -#include "JSRTCStatsReport.h" -#include <wtf/text/AtomicString.h> +#include "CustomEvent.h" +#include "DOMWrapperWorld.h" +#include <runtime/JSCInlines.h> +#include <runtime/JSCJSValue.h> +#include <runtime/Structure.h> using namespace JSC; namespace WebCore { - -bool JSRTCStatsResponse::canGetItemsForName(ExecState*, RTCStatsResponse* response, PropertyName propertyName) -{ - return response->canGetItemsForName(propertyNameToAtomicString(propertyName)); -} - -EncodedJSValue JSRTCStatsResponse::nameGetter(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName propertyName) + +JSValue JSCustomEvent::detail(ExecState& state) const { - JSRTCStatsResponse* thisObj = jsCast<JSRTCStatsResponse*>(JSValue::decode(slotBase)); - return JSValue::encode(toJS(exec, thisObj->globalObject(), thisObj->impl().namedItem(propertyNameToAtomicString(propertyName)))); + auto& event = wrapped(); + + auto detail = event.detail(); + if (!detail) + return jsNull(); + + if (detail.isObject() && &worldForDOMObject(detail.getObject()) != ¤tWorld(&state)) { + // We need to make sure CustomEvents do not leak their detail property across isolated DOM worlds. + // Ideally, we would check that the worlds have different privileges but that's not possible yet. + auto serializedDetail = event.trySerializeDetail(state); + if (!serializedDetail) + return jsNull(); + return serializedDetail->deserialize(state, globalObject()); + } + + return detail; } } // namespace WebCore -#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/bindings/js/JSCustomXPathNSResolver.cpp b/Source/WebCore/bindings/js/JSCustomXPathNSResolver.cpp index f1b63f85a..2f14dff6b 100644 --- a/Source/WebCore/bindings/js/JSCustomXPathNSResolver.cpp +++ b/Source/WebCore/bindings/js/JSCustomXPathNSResolver.cpp @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,14 +26,14 @@ #include "config.h" #include "JSCustomXPathNSResolver.h" +#include "CommonVM.h" #include "Document.h" -#include "ExceptionCode.h" #include "Frame.h" +#include "JSDOMExceptionHandling.h" #include "JSDOMWindowCustom.h" #include "JSMainThreadExecState.h" #include "Page.h" -#include "PageConsole.h" -#include "SecurityOrigin.h" +#include "PageConsoleClient.h" #include <runtime/JSLock.h> #include <wtf/Ref.h> @@ -41,23 +41,21 @@ namespace WebCore { using namespace JSC; -PassRefPtr<JSCustomXPathNSResolver> JSCustomXPathNSResolver::create(ExecState* exec, JSValue value) +ExceptionOr<Ref<JSCustomXPathNSResolver>> JSCustomXPathNSResolver::create(ExecState& state, JSValue value) { if (value.isUndefinedOrNull()) - return 0; + return Exception { TypeError }; - JSObject* resolverObject = value.getObject(); - if (!resolverObject) { - setDOMException(exec, TYPE_MISMATCH_ERR); - return 0; - } + auto* resolverObject = value.getObject(); + if (!resolverObject) + return Exception { TYPE_MISMATCH_ERR }; - return adoptRef(new JSCustomXPathNSResolver(exec, resolverObject, asJSDOMWindow(exec->vmEntryGlobalObject()))); + return adoptRef(*new JSCustomXPathNSResolver(state.vm(), resolverObject, asJSDOMWindow(state.vmEntryGlobalObject()))); } -JSCustomXPathNSResolver::JSCustomXPathNSResolver(ExecState* exec, JSObject* customResolver, JSDOMWindow* globalObject) - : m_customResolver(exec->vm(), customResolver) - , m_globalObject(exec->vm(), globalObject) +JSCustomXPathNSResolver::JSCustomXPathNSResolver(VM& vm, JSObject* customResolver, JSDOMWindow* globalObject) + : m_customResolver(vm, customResolver) + , m_globalObject(vm, globalObject) { } @@ -69,37 +67,37 @@ String JSCustomXPathNSResolver::lookupNamespaceURI(const String& prefix) { ASSERT(m_customResolver); - JSLockHolder lock(JSDOMWindowBase::commonVM()); + JSLockHolder lock(commonVM()); ExecState* exec = m_globalObject->globalExec(); - JSValue function = m_customResolver->get(exec, Identifier(exec, "lookupNamespaceURI")); + JSValue function = m_customResolver->get(exec, Identifier::fromString(exec, "lookupNamespaceURI")); CallData callData; CallType callType = getCallData(function, callData); - if (callType == CallTypeNone) { + if (callType == CallType::None) { callType = m_customResolver->methodTable()->getCallData(m_customResolver.get(), callData); - if (callType == CallTypeNone) { - // FIXME: <http://webkit.org/b/114312> JSCustomXPathNSResolver::lookupNamespaceURI Console Message should include Line, Column, and SourceURL - if (PageConsole* console = m_globalObject->impl().pageConsole()) - console->addMessage(JSMessageSource, ErrorMessageLevel, "XPathNSResolver does not have a lookupNamespaceURI method."); + if (callType == CallType::None) { + if (PageConsoleClient* console = m_globalObject->wrapped().console()) + console->addMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("XPathNSResolver does not have a lookupNamespaceURI method.")); return String(); } function = m_customResolver.get(); } - Ref<JSCustomXPathNSResolver> selfProtector(*this); + Ref<JSCustomXPathNSResolver> protectedThis(*this); MarkedArgumentBuffer args; args.append(jsStringWithCache(exec, prefix)); - JSValue retval = JSMainThreadExecState::call(exec, function, callType, callData, m_customResolver.get(), args); + NakedPtr<JSC::Exception> exception; + JSValue retval = JSMainThreadExecState::call(exec, function, callType, callData, m_customResolver.get(), args, exception); String result; - if (exec->hadException()) - reportCurrentException(exec); + if (exception) + reportException(exec, exception); else { if (!retval.isUndefinedOrNull()) - result = retval.toString(exec)->value(exec); + result = retval.toWTFString(exec); } return result; diff --git a/Source/WebCore/bindings/js/JSCustomXPathNSResolver.h b/Source/WebCore/bindings/js/JSCustomXPathNSResolver.h index 7e218e8b7..4cee8d316 100644 --- a/Source/WebCore/bindings/js/JSCustomXPathNSResolver.h +++ b/Source/WebCore/bindings/js/JSCustomXPathNSResolver.h @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,43 +23,32 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSCustomXPathNSResolver_h -#define JSCustomXPathNSResolver_h +#pragma once +#include "ExceptionOr.h" #include "XPathNSResolver.h" #include <heap/Strong.h> #include <heap/StrongInlines.h> +#include <runtime/JSCInlines.h> #include <runtime/JSCJSValue.h> -#include <runtime/Operations.h> -#include <wtf/Forward.h> -#include <wtf/RefPtr.h> - -namespace JSC { - class ExecState; - class JSObject; -} namespace WebCore { - class Frame; - class JSDOMWindow; +class JSDOMWindow; - class JSCustomXPathNSResolver : public XPathNSResolver { - public: - static PassRefPtr<JSCustomXPathNSResolver> create(JSC::ExecState*, JSC::JSValue); - - virtual ~JSCustomXPathNSResolver(); +class JSCustomXPathNSResolver final : public XPathNSResolver { +public: + static ExceptionOr<Ref<JSCustomXPathNSResolver>> create(JSC::ExecState&, JSC::JSValue); + virtual ~JSCustomXPathNSResolver(); - virtual String lookupNamespaceURI(const String& prefix); +private: + JSCustomXPathNSResolver(JSC::VM&, JSC::JSObject*, JSDOMWindow*); - private: - JSCustomXPathNSResolver(JSC::ExecState*, JSC::JSObject*, JSDOMWindow*); + String lookupNamespaceURI(const String& prefix) final; - // JSCustomXPathNSResolvers are always temporary so using a Strong reference is safe here. - JSC::Strong<JSC::JSObject> m_customResolver; - JSC::Strong<JSDOMWindow> m_globalObject; - }; + // JSCustomXPathNSResolvers are always temporary so using a Strong reference is safe here. + JSC::Strong<JSC::JSObject> m_customResolver; + JSC::Strong<JSDOMWindow> m_globalObject; +}; } // namespace WebCore - -#endif // JSCustomXPathNSResolver_h diff --git a/Source/WebCore/bindings/js/JSDOMBinding.cpp b/Source/WebCore/bindings/js/JSDOMBinding.cpp deleted file mode 100644 index a32d332ad..000000000 --- a/Source/WebCore/bindings/js/JSDOMBinding.cpp +++ /dev/null @@ -1,536 +0,0 @@ -/* - * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013 Apple Inc. All rights reserved. - * Copyright (C) 2007 Samuel Weinig <sam@webkit.org> - * Copyright (C) 2013 Michael Pruett <michael@68k.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include "JSDOMBinding.h" - -#include "CachedScript.h" -#include "DOMConstructorWithDocument.h" -#include "DOMObjectHashTableMap.h" -#include "DOMStringList.h" -#include "ExceptionCode.h" -#include "ExceptionHeaders.h" -#include "ExceptionInterfaces.h" -#include "Frame.h" -#include "HTMLParserIdioms.h" -#include "JSDOMWindowCustom.h" -#include "JSExceptionBase.h" -#include "SecurityOrigin.h" -#include "ScriptCallStack.h" -#include "ScriptCallStackFactory.h" -#include <interpreter/Interpreter.h> -#include <runtime/DateInstance.h> -#include <runtime/Error.h> -#include <runtime/ExceptionHelpers.h> -#include <runtime/JSFunction.h> -#include <wtf/MathExtras.h> - -using namespace JSC; - -namespace WebCore { - -STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(DOMConstructorObject); -STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(DOMConstructorWithDocument); - -void addImpureProperty(const AtomicString& propertyName) -{ - JSDOMWindow::commonVM()->addImpureProperty(propertyName); -} - -const JSC::HashTable& getHashTableForGlobalData(VM& vm, const JSC::HashTable& staticTable) -{ - return DOMObjectHashTableMap::mapFor(vm).get(staticTable); -} - -JSValue jsStringOrNull(ExecState* exec, const String& s) -{ - if (s.isNull()) - return jsNull(); - return jsStringWithCache(exec, s); -} - -JSValue jsOwnedStringOrNull(ExecState* exec, const String& s) -{ - if (s.isNull()) - return jsNull(); - return jsOwnedString(exec, s); -} - -JSValue jsStringOrUndefined(ExecState* exec, const String& s) -{ - if (s.isNull()) - return jsUndefined(); - return jsStringWithCache(exec, s); -} - -JSValue jsString(ExecState* exec, const URL& url) -{ - return jsStringWithCache(exec, url.string()); -} - -JSValue jsStringOrNull(ExecState* exec, const URL& url) -{ - if (url.isNull()) - return jsNull(); - return jsStringWithCache(exec, url.string()); -} - -JSValue jsStringOrUndefined(ExecState* exec, const URL& url) -{ - if (url.isNull()) - return jsUndefined(); - return jsStringWithCache(exec, url.string()); -} - -AtomicStringImpl* findAtomicString(PropertyName propertyName) -{ - StringImpl* impl = propertyName.publicName(); - if (!impl) - return 0; - ASSERT(impl->existingHash()); - return AtomicString::find(impl); -} - -String valueToStringWithNullCheck(ExecState* exec, JSValue value) -{ - if (value.isNull()) - return String(); - return value.toString(exec)->value(exec); -} - -String valueToStringWithUndefinedOrNullCheck(ExecState* exec, JSValue value) -{ - if (value.isUndefinedOrNull()) - return String(); - return value.toString(exec)->value(exec); -} - -JSValue jsDateOrNull(ExecState* exec, double value) -{ - if (!std::isfinite(value)) - return jsNull(); - return DateInstance::create(exec->vm(), exec->lexicalGlobalObject()->dateStructure(), value); -} - -double valueToDate(ExecState* exec, JSValue value) -{ - if (value.isNumber()) - return value.asNumber(); - if (!value.inherits(DateInstance::info())) - return std::numeric_limits<double>::quiet_NaN(); - return static_cast<DateInstance*>(value.toObject(exec))->internalNumber(); -} - -JSC::JSValue jsArray(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, PassRefPtr<DOMStringList> stringList) -{ - JSC::MarkedArgumentBuffer list; - if (stringList) { - for (unsigned i = 0; i < stringList->length(); ++i) - list.append(jsStringWithCache(exec, stringList->item(i))); - } - return JSC::constructArray(exec, 0, globalObject, list); -} - -void reportException(ExecState* exec, JSValue exception, CachedScript* cachedScript) -{ - if (isTerminatedExecutionException(exception)) - return; - - Interpreter::ErrorHandlingMode mode(exec); - - RefPtr<ScriptCallStack> callStack(createScriptCallStackFromException(exec, exception, ScriptCallStack::maxCallStackSizeToCapture)); - exec->clearException(); - exec->clearSupplementaryExceptionInfo(); - - JSDOMGlobalObject* globalObject = jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()); - if (JSDOMWindow* window = jsDynamicCast<JSDOMWindow*>(globalObject)) { - if (!window->impl().isCurrentlyDisplayedInFrame()) - return; - } - - int lineNumber = 0; - int columnNumber = 0; - String exceptionSourceURL; - if (callStack->size()) { - const ScriptCallFrame& frame = callStack->at(0); - lineNumber = frame.lineNumber(); - columnNumber = frame.columnNumber(); - exceptionSourceURL = frame.sourceURL(); - } else { - // There may not be an exceptionStack for a <script> SyntaxError. Fallback to getting at least the line and sourceURL from the exception. - JSObject* exceptionObject = exception.toObject(exec); - JSValue lineValue = exceptionObject->getDirect(exec->vm(), Identifier(exec, "line")); - lineNumber = lineValue && lineValue.isNumber() ? int(lineValue.toNumber(exec)) : 0; - JSValue columnValue = exceptionObject->getDirect(exec->vm(), Identifier(exec, "column")); - columnNumber = columnValue && columnValue.isNumber() ? int(columnValue.toNumber(exec)) : 0; - JSValue sourceURLValue = exceptionObject->getDirect(exec->vm(), Identifier(exec, "sourceURL")); - exceptionSourceURL = sourceURLValue && sourceURLValue.isString() ? sourceURLValue.toString(exec)->value(exec) : ASCIILiteral("undefined"); - } - - String errorMessage; - if (ExceptionBase* exceptionBase = toExceptionBase(exception)) - errorMessage = exceptionBase->message() + ": " + exceptionBase->description(); - else { - // FIXME: <http://webkit.org/b/115087> Web Inspector: WebCore::reportException should not evaluate JavaScript handling exceptions - // If this is a custon exception object, call toString on it to try and get a nice string representation for the exception. - errorMessage = exception.toString(exec)->value(exec); - exec->clearException(); - exec->clearSupplementaryExceptionInfo(); - } - - ScriptExecutionContext* scriptExecutionContext = globalObject->scriptExecutionContext(); - scriptExecutionContext->reportException(errorMessage, lineNumber, columnNumber, exceptionSourceURL, callStack->size() ? callStack : 0, cachedScript); -} - -void reportCurrentException(ExecState* exec) -{ - JSValue exception = exec->exception(); - exec->clearException(); - reportException(exec, exception); -} - -#define TRY_TO_CREATE_EXCEPTION(interfaceName) \ - case interfaceName##Type: \ - errorObject = toJS(exec, globalObject, interfaceName::create(description)); \ - break; - -void setDOMException(ExecState* exec, ExceptionCode ec) -{ - if (!ec || exec->hadException()) - return; - - // FIXME: Handle other WebIDL exception types. - if (ec == TypeError) { - throwTypeError(exec); - return; - } - - // FIXME: All callers to setDOMException need to pass in the right global object - // for now, we're going to assume the lexicalGlobalObject. Which is wrong in cases like this: - // frames[0].document.createElement(null, null); // throws an exception which should have the subframes prototypes. - JSDOMGlobalObject* globalObject = deprecatedGlobalObjectForPrototype(exec); - - ExceptionCodeDescription description(ec); - - JSValue errorObject; - switch (description.type) { - DOM_EXCEPTION_INTERFACES_FOR_EACH(TRY_TO_CREATE_EXCEPTION) - } - - ASSERT(errorObject); - exec->vm().throwException(exec, errorObject); -} - -#undef TRY_TO_CREATE_EXCEPTION - -bool shouldAllowAccessToNode(ExecState* exec, Node* node) -{ - return BindingSecurity::shouldAllowAccessToNode(exec, node); -} - -bool shouldAllowAccessToFrame(ExecState* exec, Frame* target) -{ - return BindingSecurity::shouldAllowAccessToFrame(exec, target); -} - -bool shouldAllowAccessToFrame(ExecState* exec, Frame* frame, String& message) -{ - if (!frame) - return false; - if (BindingSecurity::shouldAllowAccessToFrame(exec, frame, DoNotReportSecurityError)) - return true; - message = frame->document()->domWindow()->crossDomainAccessErrorMessage(activeDOMWindow(exec)); - return false; -} - -bool shouldAllowAccessToDOMWindow(ExecState* exec, DOMWindow& target, String& message) -{ - if (BindingSecurity::shouldAllowAccessToDOMWindow(exec, target, DoNotReportSecurityError)) - return true; - message = target.crossDomainAccessErrorMessage(activeDOMWindow(exec)); - return false; -} - -void printErrorMessageForFrame(Frame* frame, const String& message) -{ - if (!frame) - return; - frame->document()->domWindow()->printErrorMessage(message); -} - -EncodedJSValue objectToStringFunctionGetter(ExecState* exec, EncodedJSValue, EncodedJSValue, PropertyName propertyName) -{ - return JSValue::encode(JSFunction::create(exec->vm(), exec->lexicalGlobalObject(), 0, propertyName.publicName(), objectProtoFuncToString)); -} - -Structure* getCachedDOMStructure(JSDOMGlobalObject* globalObject, const ClassInfo* classInfo) -{ - JSDOMStructureMap& structures = globalObject->structures(); - return structures.get(classInfo).get(); -} - -Structure* cacheDOMStructure(JSDOMGlobalObject* globalObject, Structure* structure, const ClassInfo* classInfo) -{ - JSDOMStructureMap& structures = globalObject->structures(); - ASSERT(!structures.contains(classInfo)); - return structures.set(classInfo, WriteBarrier<Structure>(globalObject->vm(), globalObject, structure)).iterator->value.get(); -} - -static const int32_t kMaxInt32 = 0x7fffffff; -static const int32_t kMinInt32 = -kMaxInt32 - 1; -static const uint32_t kMaxUInt32 = 0xffffffffU; -static const int64_t kJSMaxInteger = 0x20000000000000LL - 1; // 2^53 - 1, largest integer exactly representable in ECMAScript. - -static double enforceRange(ExecState* exec, double x, double minimum, double maximum) -{ - if (std::isnan(x) || std::isinf(x)) { - throwTypeError(exec); - return 0; - } - x = trunc(x); - if (x < minimum || x > maximum) { - throwTypeError(exec); - return 0; - } - return x; -} - -template <typename T> -struct IntTypeLimits { -}; - -template <> -struct IntTypeLimits<int8_t> { - static const int8_t minValue = -128; - static const int8_t maxValue = 127; - static const unsigned numberOfValues = 256; // 2^8 -}; - -template <> -struct IntTypeLimits<uint8_t> { - static const uint8_t maxValue = 255; - static const unsigned numberOfValues = 256; // 2^8 -}; - -template <> -struct IntTypeLimits<int16_t> { - static const short minValue = -32768; - static const short maxValue = 32767; - static const unsigned numberOfValues = 65536; // 2^16 -}; - -template <> -struct IntTypeLimits<uint16_t> { - static const unsigned short maxValue = 65535; - static const unsigned numberOfValues = 65536; // 2^16 -}; - -template <typename T> -static inline T toSmallerInt(ExecState* exec, JSValue value, IntegerConversionConfiguration configuration) -{ - typedef IntTypeLimits<T> LimitsTrait; - // Fast path if the value is already a 32-bit signed integer in the right range. - if (value.isInt32()) { - int32_t d = value.asInt32(); - if (d >= LimitsTrait::minValue && d <= LimitsTrait::maxValue) - return static_cast<T>(d); - if (configuration == EnforceRange) { - throwTypeError(exec); - return 0; - } - d %= LimitsTrait::numberOfValues; - return static_cast<T>(d > LimitsTrait::maxValue ? d - LimitsTrait::numberOfValues : d); - } - - double x = value.toNumber(exec); - if (exec->hadException()) - return 0; - - if (configuration == EnforceRange) - return enforceRange(exec, x, LimitsTrait::minValue, LimitsTrait::maxValue); - - if (std::isnan(x) || std::isinf(x) || !x) - return 0; - - x = x < 0 ? -floor(fabs(x)) : floor(fabs(x)); - x = fmod(x, LimitsTrait::numberOfValues); - - return static_cast<T>(x > LimitsTrait::maxValue ? x - LimitsTrait::numberOfValues : x); -} - -template <typename T> -static inline T toSmallerUInt(ExecState* exec, JSValue value, IntegerConversionConfiguration configuration) -{ - typedef IntTypeLimits<T> LimitsTrait; - // Fast path if the value is already a 32-bit unsigned integer in the right range. - if (value.isUInt32()) { - uint32_t d = value.asUInt32(); - if (d <= LimitsTrait::maxValue) - return static_cast<T>(d); - if (configuration == EnforceRange) { - throwTypeError(exec); - return 0; - } - return static_cast<T>(d); - } - - double x = value.toNumber(exec); - if (exec->hadException()) - return 0; - - if (configuration == EnforceRange) - return enforceRange(exec, x, 0, LimitsTrait::maxValue); - - if (std::isnan(x) || std::isinf(x) || !x) - return 0; - - x = x < 0 ? -floor(fabs(x)) : floor(fabs(x)); - return static_cast<T>(fmod(x, LimitsTrait::numberOfValues)); -} - -// http://www.w3.org/TR/WebIDL/#es-byte -int8_t toInt8(ExecState* exec, JSValue value, IntegerConversionConfiguration configuration) -{ - return toSmallerInt<int8_t>(exec, value, configuration); -} - -// http://www.w3.org/TR/WebIDL/#es-octet -uint8_t toUInt8(ExecState* exec, JSValue value, IntegerConversionConfiguration configuration) -{ - return toSmallerUInt<uint8_t>(exec, value, configuration); -} - -// http://www.w3.org/TR/WebIDL/#es-short -int16_t toInt16(ExecState* exec, JSValue value, IntegerConversionConfiguration configuration) -{ - return toSmallerInt<int16_t>(exec, value, configuration); -} - -// http://www.w3.org/TR/WebIDL/#es-unsigned-short -uint16_t toUInt16(ExecState* exec, JSValue value, IntegerConversionConfiguration configuration) -{ - return toSmallerUInt<uint16_t>(exec, value, configuration); -} - -// http://www.w3.org/TR/WebIDL/#es-long -int32_t toInt32EnforceRange(ExecState* exec, JSValue value) -{ - if (value.isInt32()) - return value.asInt32(); - - double x = value.toNumber(exec); - if (exec->hadException()) - return 0; - return enforceRange(exec, x, kMinInt32, kMaxInt32); -} - -// http://www.w3.org/TR/WebIDL/#es-unsigned-long -uint32_t toUInt32EnforceRange(ExecState* exec, JSValue value) -{ - if (value.isUInt32()) - return value.asUInt32(); - - double x = value.toNumber(exec); - if (exec->hadException()) - return 0; - return enforceRange(exec, x, 0, kMaxUInt32); -} - -// http://www.w3.org/TR/WebIDL/#es-long-long -int64_t toInt64(ExecState* exec, JSValue value, IntegerConversionConfiguration configuration) -{ - if (value.isInt32()) - return value.asInt32(); - - double x = value.toNumber(exec); - if (exec->hadException()) - return 0; - - if (configuration == EnforceRange) - return enforceRange(exec, x, -kJSMaxInteger, kJSMaxInteger); - - // Map NaNs and +/-Infinity to 0; convert finite values modulo 2^64. - unsigned long long n; - doubleToInteger(x, n); - return n; -} - -// http://www.w3.org/TR/WebIDL/#es-unsigned-long-long -uint64_t toUInt64(ExecState* exec, JSValue value, IntegerConversionConfiguration configuration) -{ - if (value.isUInt32()) - return value.asUInt32(); - - double x = value.toNumber(exec); - if (exec->hadException()) - return 0; - - if (configuration == EnforceRange) - return enforceRange(exec, x, 0, kJSMaxInteger); - - // Map NaNs and +/-Infinity to 0; convert finite values modulo 2^64. - unsigned long long n; - doubleToInteger(x, n); - return n; -} - -DOMWindow& activeDOMWindow(ExecState* exec) -{ - return asJSDOMWindow(exec->lexicalGlobalObject())->impl(); -} - -DOMWindow& firstDOMWindow(ExecState* exec) -{ - return asJSDOMWindow(exec->vmEntryGlobalObject())->impl(); -} - -static inline bool canAccessDocument(JSC::ExecState* state, Document* targetDocument, SecurityReportingOption reportingOption = ReportSecurityError) -{ - if (!targetDocument) - return false; - - DOMWindow& active = activeDOMWindow(state); - - if (active.document()->securityOrigin()->canAccess(targetDocument->securityOrigin())) - return true; - - if (reportingOption == ReportSecurityError) - printErrorMessageForFrame(targetDocument->frame(), targetDocument->domWindow()->crossDomainAccessErrorMessage(active)); - - return false; -} - -bool BindingSecurity::shouldAllowAccessToDOMWindow(JSC::ExecState* state, DOMWindow& target, SecurityReportingOption reportingOption) -{ - return canAccessDocument(state, target.document(), reportingOption); -} - -bool BindingSecurity::shouldAllowAccessToFrame(JSC::ExecState* state, Frame* target, SecurityReportingOption reportingOption) -{ - return target && canAccessDocument(state, target->document(), reportingOption); -} - -bool BindingSecurity::shouldAllowAccessToNode(JSC::ExecState* state, Node* target) -{ - return target && canAccessDocument(state, &target->document()); -} - -} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMBinding.h b/Source/WebCore/bindings/js/JSDOMBinding.h index 097ce6b26..34890157c 100644 --- a/Source/WebCore/bindings/js/JSDOMBinding.h +++ b/Source/WebCore/bindings/js/JSDOMBinding.h @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2003-2006, 2008-2009, 2013, 2016 Apple Inc. All rights reserved. * Copyright (C) 2007 Samuel Weinig <sam@webkit.org> * Copyright (C) 2009 Google, Inc. All rights reserved. * Copyright (C) 2012 Ericsson AB. All rights reserved. @@ -21,653 +21,24 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef JSDOMBinding_h -#define JSDOMBinding_h +#pragma once -#include "JSDOMGlobalObject.h" -#include "JSDOMWrapper.h" -#include "DOMWrapperWorld.h" -#include "ScriptWrappable.h" -#include "ScriptWrappableInlines.h" -#include "WebCoreTypedArrayController.h" +// FIXME: Remove this header. + +#include "ExceptionOr.h" +#include "JSDOMWrapperCache.h" #include <cstddef> -#include <heap/Weak.h> -#include <heap/WeakInlines.h> -#include <runtime/Error.h> -#include <runtime/FunctionPrototype.h> +#include <heap/HeapInlines.h> +#include <heap/SlotVisitorInlines.h> +#include <runtime/AuxiliaryBarrierInlines.h> #include <runtime/JSArray.h> -#include <runtime/JSArrayBuffer.h> -#include <runtime/JSDataView.h> -#include <runtime/JSTypedArrays.h> +#include <runtime/JSCJSValueInlines.h> +#include <runtime/JSCellInlines.h> +#include <runtime/JSObjectInlines.h> #include <runtime/Lookup.h> -#include <runtime/ObjectPrototype.h> -#include <runtime/Operations.h> -#include <runtime/TypedArrayInlines.h> -#include <runtime/TypedArrays.h> +#include <runtime/ObjectConstructor.h> +#include <runtime/StructureInlines.h> +#include <runtime/WriteBarrier.h> #include <wtf/Forward.h> -#include <wtf/Noncopyable.h> +#include <wtf/GetPtr.h> #include <wtf/Vector.h> - -namespace JSC { -class HashEntry; -} - -namespace WebCore { - -class DOMStringList; - -class CachedScript; -class Document; -class DOMWindow; -class Frame; -class HTMLDocument; -class URL; -class Node; - -typedef int ExceptionCode; - -DOMWindow& activeDOMWindow(JSC::ExecState*); -DOMWindow& firstDOMWindow(JSC::ExecState*); - -// Base class for all constructor objects in the JSC bindings. -class DOMConstructorObject : public JSDOMWrapper { - typedef JSDOMWrapper Base; -public: - static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) - { - return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); - } - -protected: - static const unsigned StructureFlags = JSC::ImplementsHasInstance | JSC::OverridesVisitChildren | JSDOMWrapper::StructureFlags; - DOMConstructorObject(JSC::Structure* structure, JSDOMGlobalObject* globalObject) - : JSDOMWrapper(structure, globalObject) - { - } -}; - -JSC::Structure* getCachedDOMStructure(JSDOMGlobalObject*, const JSC::ClassInfo*); -JSC::Structure* cacheDOMStructure(JSDOMGlobalObject*, JSC::Structure*, const JSC::ClassInfo*); - -inline JSDOMGlobalObject* deprecatedGlobalObjectForPrototype(JSC::ExecState* exec) -{ - // FIXME: Callers to this function should be using the global object - // from which the object is being created, instead of assuming the lexical one. - // e.g. subframe.document.body should use the subframe's global object, not the lexical one. - return JSC::jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()); -} - -template<class WrapperClass> inline JSC::Structure* getDOMStructure(JSC::VM& vm, JSDOMGlobalObject* globalObject) -{ - if (JSC::Structure* structure = getCachedDOMStructure(globalObject, WrapperClass::info())) - return structure; - return cacheDOMStructure(globalObject, WrapperClass::createStructure(vm, globalObject, WrapperClass::createPrototype(vm, globalObject)), WrapperClass::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->vm(), deprecatedGlobalObjectForPrototype(exec)); -} - -template<class WrapperClass> inline JSC::JSObject* getDOMPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject) -{ - return JSC::jsCast<JSC::JSObject*>(asObject(getDOMStructure<WrapperClass>(vm, JSC::jsCast<JSDOMGlobalObject*>(globalObject))->storedPrototype())); -} - -inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld& world, JSC::ArrayBuffer*) -{ - return static_cast<WebCoreTypedArrayController*>(world.vm()->m_typedArrayController.get())->wrapperOwner(); -} - -inline void* wrapperContext(DOMWrapperWorld& world, JSC::ArrayBuffer*) -{ - return &world; -} - -inline JSDOMWrapper* getInlineCachedWrapper(DOMWrapperWorld&, void*) { return 0; } -inline bool setInlineCachedWrapper(DOMWrapperWorld&, void*, JSDOMWrapper*, JSC::WeakHandleOwner*, void*) { return false; } -inline bool clearInlineCachedWrapper(DOMWrapperWorld&, void*, JSDOMWrapper*) { return false; } - -inline JSDOMWrapper* getInlineCachedWrapper(DOMWrapperWorld& world, ScriptWrappable* domObject) -{ - if (!world.isNormal()) - return 0; - return domObject->wrapper(); -} - -inline JSC::JSArrayBuffer* getInlineCachedWrapper(DOMWrapperWorld& world, JSC::ArrayBuffer* buffer) -{ - if (!world.isNormal()) - return 0; - return buffer->m_wrapper.get(); -} - -inline bool setInlineCachedWrapper(DOMWrapperWorld& world, ScriptWrappable* domObject, JSDOMWrapper* wrapper, JSC::WeakHandleOwner* wrapperOwner, void* context) -{ - if (!world.isNormal()) - return false; - domObject->setWrapper(wrapper, wrapperOwner, context); - return true; -} - -inline bool setInlineCachedWrapper(DOMWrapperWorld& world, JSC::ArrayBuffer* domObject, JSC::JSArrayBuffer* wrapper, JSC::WeakHandleOwner* wrapperOwner, void* context) -{ - if (!world.isNormal()) - return false; - domObject->m_wrapper = JSC::Weak<JSC::JSArrayBuffer>(wrapper, wrapperOwner, context); - return true; -} - -inline bool clearInlineCachedWrapper(DOMWrapperWorld& world, ScriptWrappable* domObject, JSDOMWrapper* wrapper) -{ - if (!world.isNormal()) - return false; - domObject->clearWrapper(wrapper); - return true; -} - -inline bool clearInlineCachedWrapper(DOMWrapperWorld& world, JSC::ArrayBuffer* domObject, JSC::JSArrayBuffer* wrapper) -{ - if (!world.isNormal()) - return false; - weakClear(domObject->m_wrapper, wrapper); - return true; -} - -template <typename DOMClass> inline JSC::JSObject* getCachedWrapper(DOMWrapperWorld& world, DOMClass* domObject) -{ - if (JSC::JSObject* wrapper = getInlineCachedWrapper(world, domObject)) - return wrapper; - return world.m_wrappers.get(domObject); -} - -template <typename DOMClass, typename WrapperClass> inline void cacheWrapper(DOMWrapperWorld& world, DOMClass* domObject, WrapperClass* wrapper) -{ - JSC::WeakHandleOwner* owner = wrapperOwner(world, domObject); - void* context = wrapperContext(world, domObject); - if (setInlineCachedWrapper(world, domObject, wrapper, owner, context)) - return; - weakAdd(world.m_wrappers, (void*)domObject, JSC::Weak<JSC::JSObject>(wrapper, owner, context)); -} - -template <typename DOMClass, typename WrapperClass> inline void uncacheWrapper(DOMWrapperWorld& world, DOMClass* domObject, WrapperClass* wrapper) -{ - if (clearInlineCachedWrapper(world, domObject, wrapper)) - return; - weakRemove(world.m_wrappers, (void*)domObject, wrapper); -} - -#define CREATE_DOM_WRAPPER(exec, globalObject, className, object) 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(!getCachedWrapper(currentWorld(exec), node)); - WrapperClass* wrapper = WrapperClass::create(getDOMStructure<WrapperClass>(exec->vm(), 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. - cacheWrapper(currentWorld(exec), node, wrapper); - return wrapper; -} - -template<class WrapperClass, class DOMClass> inline JSC::JSValue wrap(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* domObject) -{ - if (!domObject) - return JSC::jsNull(); - if (JSC::JSObject* wrapper = getCachedWrapper(currentWorld(exec), domObject)) - return wrapper; - return createWrapper<WrapperClass>(exec, globalObject, domObject); -} - -template<class WrapperClass, class DOMClass> inline JSC::JSValue getExistingWrapper(JSC::ExecState* exec, DOMClass* domObject) -{ - ASSERT(domObject); - return getCachedWrapper(currentWorld(exec), domObject); -} - -template<class WrapperClass, class DOMClass> inline JSC::JSValue createNewWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* domObject) -{ - ASSERT(domObject); - ASSERT(!getCachedWrapper(currentWorld(exec), domObject)); - return createWrapper<WrapperClass>(exec, globalObject, domObject); -} - -inline JSC::JSValue argumentOrNull(JSC::ExecState* exec, unsigned index) -{ - return index >= exec->argumentCount() ? JSC::JSValue() : exec->argument(index); -} - -void addImpureProperty(const AtomicString&); - -const JSC::HashTable& getHashTableForGlobalData(JSC::VM&, const JSC::HashTable& staticTable); - -void reportException(JSC::ExecState*, JSC::JSValue exception, CachedScript* = 0); -void reportCurrentException(JSC::ExecState*); - -// Convert a DOM implementation exception code into a JavaScript exception in the execution state. -void setDOMException(JSC::ExecState*, ExceptionCode); - -JSC::JSValue jsStringWithCache(JSC::ExecState*, const String&); -JSC::JSValue jsString(JSC::ExecState*, const URL&); // empty if the URL is null -inline JSC::JSValue jsStringWithCache(JSC::ExecState* exec, const AtomicString& s) -{ - return jsStringWithCache(exec, s.string()); -} - -JSC::JSValue jsStringOrNull(JSC::ExecState*, const String&); // null if the string is null -JSC::JSValue jsStringOrNull(JSC::ExecState*, const URL&); // null if the URL is null - -JSC::JSValue jsStringOrUndefined(JSC::ExecState*, const String&); // undefined if the string is null -JSC::JSValue jsStringOrUndefined(JSC::ExecState*, const URL&); // undefined if the URL is null - -// See JavaScriptCore for explanation: Should be used for any string that is already owned by another -// object, to let the engine know that collecting the JSString wrapper is unlikely to save memory. -JSC::JSValue jsOwnedStringOrNull(JSC::ExecState*, const String&); - -String propertyNameToString(JSC::PropertyName); - -AtomicString propertyNameToAtomicString(JSC::PropertyName); -AtomicStringImpl* findAtomicString(JSC::PropertyName); - -String valueToStringWithNullCheck(JSC::ExecState*, JSC::JSValue); // null if the value is null -String valueToStringWithUndefinedOrNullCheck(JSC::ExecState*, JSC::JSValue); // null if the value is null or undefined - -inline int32_t finiteInt32Value(JSC::JSValue value, JSC::ExecState* exec, bool& okay) -{ - double number = value.toNumber(exec); - okay = std::isfinite(number); - return JSC::toInt32(number); -} - -enum IntegerConversionConfiguration { - NormalConversion, - EnforceRange, - // FIXME: Implement Clamp -}; - -int32_t toInt32EnforceRange(JSC::ExecState*, JSC::JSValue); -uint32_t toUInt32EnforceRange(JSC::ExecState*, JSC::JSValue); - -int8_t toInt8(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration); -uint8_t toUInt8(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration); - -int16_t toInt16(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration); -uint16_t toUInt16(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration); - -/* - Convert a value to an integer as per <http://www.w3.org/TR/WebIDL/>. - The conversion fails if the value cannot be converted to a number or, - if EnforceRange is specified, the value is outside the range of the - destination integer type. -*/ -inline int32_t toInt32(JSC::ExecState* exec, JSC::JSValue value, IntegerConversionConfiguration configuration) -{ - if (configuration == EnforceRange) - return toInt32EnforceRange(exec, value); - return value.toInt32(exec); -} - -inline uint32_t toUInt32(JSC::ExecState* exec, JSC::JSValue value, IntegerConversionConfiguration configuration) -{ - if (configuration == EnforceRange) - return toUInt32EnforceRange(exec, value); - return value.toUInt32(exec); -} - -int64_t toInt64(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration); -uint64_t toUInt64(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration); - -// Returns a Date instance for the specified value, or null if the value is NaN or infinity. -JSC::JSValue jsDateOrNull(JSC::ExecState*, double); -// NaN if the value can't be converted to a date. -double valueToDate(JSC::ExecState*, JSC::JSValue); - -// Validates that the passed object is a sequence type per section 4.1.13 of the WebIDL spec. -inline JSC::JSObject* toJSSequence(JSC::ExecState* exec, JSC::JSValue value, unsigned& length) -{ - JSC::JSObject* object = value.getObject(); - if (!object) { - throwVMError(exec, createTypeError(exec, "Value is not a sequence")); - return 0; - } - - JSC::JSValue lengthValue = object->get(exec, exec->propertyNames().length); - if (exec->hadException()) - return 0; - - if (lengthValue.isUndefinedOrNull()) { - throwVMError(exec, createTypeError(exec, "Value is not a sequence")); - return 0; - } - - length = lengthValue.toUInt32(exec); - if (exec->hadException()) - return 0; - - return object; -} - -inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, JSC::ArrayBuffer* buffer) -{ - if (!buffer) - return JSC::jsNull(); - if (JSC::JSValue result = getExistingWrapper<JSC::JSArrayBuffer>(exec, buffer)) - return result; - buffer->ref(); - JSC::JSArrayBuffer* wrapper = JSC::JSArrayBuffer::create(exec->vm(), globalObject->arrayBufferStructure(), buffer); - cacheWrapper(currentWorld(exec), buffer, wrapper); - return wrapper; -} - -inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, JSC::ArrayBufferView* view) -{ - if (!view) - return JSC::jsNull(); - return view->wrap(exec, globalObject); -} - -template <typename T> -inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, PassRefPtr<T> ptr) -{ - return toJS(exec, globalObject, ptr.get()); -} - -template <typename T> -inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const Vector<T>& vector) -{ - JSC::JSArray* array = constructEmptyArray(exec, 0, vector.size()); - - for (size_t i = 0; i < vector.size(); ++i) - array->putDirectIndex(exec, i, toJS(exec, globalObject, vector[i])); - - return array; -} - -template <typename T> -inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const Vector<RefPtr<T>>& vector) -{ - JSC::JSArray* array = constructEmptyArray(exec, 0, vector.size()); - - for (size_t i = 0; i < vector.size(); ++i) - array->putDirectIndex(exec, i, toJS(exec, globalObject, vector[i].get())); - - return array; -} - -inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject*, const String& value) -{ - return jsStringOrNull(exec, value); -} - -template <class T> -struct JSValueTraits { - static inline JSC::JSValue arrayJSValue(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const T& value) - { - return toJS(exec, globalObject, WTF::getPtr(value)); - } -}; - -template<> -struct JSValueTraits<String> { - static inline JSC::JSValue arrayJSValue(JSC::ExecState* exec, JSDOMGlobalObject*, const String& value) - { - return jsStringWithCache(exec, value); - } -}; - -template<> -struct JSValueTraits<float> { - static inline JSC::JSValue arrayJSValue(JSC::ExecState*, JSDOMGlobalObject*, const float& value) - { - return JSC::jsNumber(value); - } -}; - -template<> -struct JSValueTraits<unsigned long> { - static inline JSC::JSValue arrayJSValue(JSC::ExecState*, JSDOMGlobalObject*, const unsigned long& value) - { - return JSC::jsNumber(value); - } -}; - -template <typename T, size_t inlineCapacity> -JSC::JSValue jsArray(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const Vector<T, inlineCapacity>& iterator) -{ - JSC::MarkedArgumentBuffer list; - typename Vector<T, inlineCapacity>::const_iterator end = iterator.end(); - typedef JSValueTraits<T> TraitsType; - - for (typename Vector<T, inlineCapacity>::const_iterator iter = iterator.begin(); iter != end; ++iter) - list.append(TraitsType::arrayJSValue(exec, globalObject, *iter)); - - return JSC::constructArray(exec, 0, globalObject, list); -} - -JSC::JSValue jsArray(JSC::ExecState*, JSDOMGlobalObject*, PassRefPtr<DOMStringList>); - -inline PassRefPtr<JSC::ArrayBufferView> toArrayBufferView(JSC::JSValue value) -{ - JSC::JSArrayBufferView* wrapper = JSC::jsDynamicCast<JSC::JSArrayBufferView*>(value); - if (!wrapper) - return 0; - return wrapper->impl(); -} - -inline PassRefPtr<JSC::Int8Array> toInt8Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int8Adaptor>(value); } -inline PassRefPtr<JSC::Int16Array> toInt16Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int16Adaptor>(value); } -inline PassRefPtr<JSC::Int32Array> toInt32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int32Adaptor>(value); } -inline PassRefPtr<JSC::Uint8Array> toUint8Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint8Adaptor>(value); } -inline PassRefPtr<JSC::Uint8ClampedArray> toUint8ClampedArray(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint8ClampedAdaptor>(value); } -inline PassRefPtr<JSC::Uint16Array> toUint16Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint16Adaptor>(value); } -inline PassRefPtr<JSC::Uint32Array> toUint32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint32Adaptor>(value); } -inline PassRefPtr<JSC::Float32Array> toFloat32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Float32Adaptor>(value); } -inline PassRefPtr<JSC::Float64Array> toFloat64Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Float64Adaptor>(value); } - -inline PassRefPtr<JSC::DataView> toDataView(JSC::JSValue value) -{ - JSC::JSDataView* wrapper = JSC::jsDynamicCast<JSC::JSDataView*>(value); - if (!wrapper) - return 0; - return wrapper->typedImpl(); -} - -template<class T> struct NativeValueTraits; - -template<> -struct NativeValueTraits<String> { - static inline bool nativeValue(JSC::ExecState* exec, JSC::JSValue jsValue, String& indexedValue) - { - indexedValue = jsValue.toString(exec)->value(exec); - return true; - } -}; - -template<> -struct NativeValueTraits<unsigned> { - static inline bool nativeValue(JSC::ExecState* exec, JSC::JSValue jsValue, unsigned& indexedValue) - { - if (!jsValue.isNumber()) - return false; - - indexedValue = jsValue.toUInt32(exec); - if (exec->hadException()) - return false; - - return true; - } -}; - -template<> -struct NativeValueTraits<float> { - static inline bool nativeValue(JSC::ExecState* exec, JSC::JSValue jsValue, float& indexedValue) - { - indexedValue = jsValue.toFloat(exec); - return !exec->hadException(); - } -}; - -template <class T, class JST> -Vector<RefPtr<T>> toRefPtrNativeArray(JSC::ExecState* exec, JSC::JSValue value, T* (*toT)(JSC::JSValue value)) -{ - if (!isJSArray(value)) - return Vector<RefPtr<T>>(); - - Vector<RefPtr<T>> result; - JSC::JSArray* array = asArray(value); - size_t size = array->length(); - result.reserveInitialCapacity(size); - for (size_t i = 0; i < size; ++i) { - JSC::JSValue element = array->getIndex(exec, i); - if (element.inherits(JST::info())) - result.uncheckedAppend((*toT)(element)); - else { - throwVMError(exec, createTypeError(exec, "Invalid Array element type")); - return Vector<RefPtr<T>>(); - } - } - return result; -} - -template <class T> -Vector<T> toNativeArray(JSC::ExecState* exec, JSC::JSValue value) -{ - unsigned length = 0; - if (isJSArray(value)) { - JSC::JSArray* array = asArray(value); - length = array->length(); - } else - toJSSequence(exec, value, length); - - JSC::JSObject* object = value.getObject(); - Vector<T> result; - result.reserveInitialCapacity(length); - typedef NativeValueTraits<T> TraitsType; - - for (unsigned i = 0; i < length; ++i) { - T indexValue; - if (!TraitsType::nativeValue(exec, object->get(exec, i), indexValue)) - return Vector<T>(); - result.uncheckedAppend(indexValue); - } - return result; -} - -template <class T> -Vector<T> toNativeArguments(JSC::ExecState* exec, size_t startIndex = 0) -{ - size_t length = exec->argumentCount(); - ASSERT(startIndex <= length); - - Vector<T> result; - result.reserveInitialCapacity(length); - typedef NativeValueTraits<T> TraitsType; - - for (size_t i = startIndex; i < length; ++i) { - T indexValue; - if (!TraitsType::nativeValue(exec, exec->argument(i), indexValue)) - return Vector<T>(); - result.uncheckedAppend(indexValue); - } - return result; -} - -bool shouldAllowAccessToNode(JSC::ExecState*, Node*); -bool shouldAllowAccessToFrame(JSC::ExecState*, Frame*); -bool shouldAllowAccessToFrame(JSC::ExecState*, Frame*, String& message); -bool shouldAllowAccessToDOMWindow(JSC::ExecState*, DOMWindow&, String& message); - -void printErrorMessageForFrame(Frame*, const String& message); -JSC::EncodedJSValue objectToStringFunctionGetter(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue, JSC::PropertyName); - -inline JSC::JSValue jsStringWithCache(JSC::ExecState* exec, const String& s) -{ - StringImpl* stringImpl = s.impl(); - if (!stringImpl || !stringImpl->length()) - return jsEmptyString(exec); - - if (stringImpl->length() == 1) { - UChar singleCharacter = (*stringImpl)[0u]; - if (singleCharacter <= JSC::maxSingleCharacterString) { - JSC::VM* vm = &exec->vm(); - return vm->smallStrings.singleCharacterString(static_cast<unsigned char>(singleCharacter)); - } - } - - JSStringCache& stringCache = currentWorld(exec).m_stringCache; - JSStringCache::AddResult addResult = stringCache.add(stringImpl, nullptr); - if (addResult.isNewEntry) - addResult.iterator->value = JSC::jsString(exec, String(stringImpl)); - return JSC::JSValue(addResult.iterator->value.get()); -} - -inline String propertyNameToString(JSC::PropertyName propertyName) -{ - return propertyName.publicName(); -} - -inline AtomicString propertyNameToAtomicString(JSC::PropertyName propertyName) -{ - return AtomicString(propertyName.publicName()); -} - -template <class ThisImp> -inline const JSC::HashEntry* getStaticValueSlotEntryWithoutCaching(JSC::ExecState* exec, JSC::PropertyName propertyName) -{ - const JSC::HashEntry* entry = ThisImp::info()->propHashTable(exec)->entry(exec, propertyName); - if (!entry) // not found, forward to parent - return getStaticValueSlotEntryWithoutCaching<typename ThisImp::Base>(exec, propertyName); - return entry; -} - -template <> -inline const JSC::HashEntry* getStaticValueSlotEntryWithoutCaching<JSDOMWrapper>(JSC::ExecState*, JSC::PropertyName) -{ - return 0; -} - -template<typename T> -class HasMemoryCostMemberFunction { - typedef char YesType; - struct NoType { - char padding[8]; - }; - - template<typename U> - static decltype(static_cast<U*>(nullptr)->memoryCost(), YesType()) test(int); - - template<typename U> - static NoType test(...); - -public: - static const bool value = sizeof(test<T>(0)) == sizeof(YesType); -}; - -template <typename T, bool hasReportCostFunction = HasMemoryCostMemberFunction<T>::value > struct ReportMemoryCost; -template <typename T> struct ReportMemoryCost<T, true> { - static void reportMemoryCost(JSC::ExecState* exec, T* impl) - { - exec->heap()->reportExtraMemoryCost(impl->memoryCost()); - } -}; -template <typename T> struct ReportMemoryCost<T, false> { - static void reportMemoryCost(JSC::ExecState*, T*) - { - } -}; - -enum SecurityReportingOption { - DoNotReportSecurityError, - ReportSecurityError, -}; - -class BindingSecurity { -public: - static bool shouldAllowAccessToNode(JSC::ExecState*, Node*); - static bool shouldAllowAccessToDOMWindow(JSC::ExecState*, DOMWindow&, SecurityReportingOption = ReportSecurityError); - static bool shouldAllowAccessToFrame(JSC::ExecState*, Frame*, SecurityReportingOption = ReportSecurityError); -}; - -} // namespace WebCore - -#endif // JSDOMBinding_h diff --git a/Source/WebCore/bindings/js/JSDOMBindingCaller.h b/Source/WebCore/bindings/js/JSDOMBindingCaller.h new file mode 100644 index 000000000..715c6713d --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMBindingCaller.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2003-2006, 2008-2009, 2013, 2016 Apple Inc. All rights reserved. + * Copyright (C) 2007 Samuel Weinig <sam@webkit.org> + * Copyright (C) 2009 Google, Inc. All rights reserved. + * Copyright (C) 2012 Ericsson AB. All rights reserved. + * Copyright (C) 2013 Michael Pruett <michael@68k.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "JSDOMExceptionHandling.h" + +namespace WebCore { + +enum class CastedThisErrorBehavior { Throw, ReturnEarly, RejectPromise, Assert }; + +template<typename JSClass> +struct BindingCaller { + using AttributeSetterFunction = bool(JSC::ExecState&, JSClass&, JSC::JSValue, JSC::ThrowScope&); + using AttributeGetterFunction = JSC::JSValue(JSC::ExecState&, JSClass&, JSC::ThrowScope&); + using OperationCallerFunction = JSC::EncodedJSValue(JSC::ExecState*, JSClass*, JSC::ThrowScope&); + using PromiseOperationCallerFunction = JSC::EncodedJSValue(JSC::ExecState*, JSClass*, Ref<DeferredPromise>&&, JSC::ThrowScope&); + + static JSClass* castForAttribute(JSC::ExecState&, JSC::EncodedJSValue); + static JSClass* castForOperation(JSC::ExecState&); + + template<PromiseOperationCallerFunction operationCaller, CastedThisErrorBehavior shouldThrow = CastedThisErrorBehavior::RejectPromise> + static JSC::EncodedJSValue callPromiseOperation(JSC::ExecState* state, Ref<DeferredPromise>&& promise, const char* operationName) + { + ASSERT(state); + auto throwScope = DECLARE_THROW_SCOPE(state->vm()); + auto* thisObject = castForOperation(*state); + if (shouldThrow != CastedThisErrorBehavior::Assert && UNLIKELY(!thisObject)) + return rejectPromiseWithThisTypeError(promise.get(), JSClass::info()->className, operationName); + ASSERT(thisObject); + ASSERT_GC_OBJECT_INHERITS(thisObject, JSClass::info()); + // FIXME: We should refactor the binding generated code to use references for state and thisObject. + return operationCaller(state, thisObject, WTFMove(promise), throwScope); + } + + template<OperationCallerFunction operationCaller, CastedThisErrorBehavior shouldThrow = CastedThisErrorBehavior::Throw> + static JSC::EncodedJSValue callOperation(JSC::ExecState* state, const char* operationName) + { + ASSERT(state); + auto throwScope = DECLARE_THROW_SCOPE(state->vm()); + auto* thisObject = castForOperation(*state); + if (shouldThrow != CastedThisErrorBehavior::Assert && UNLIKELY(!thisObject)) { + if (shouldThrow == CastedThisErrorBehavior::Throw) + return throwThisTypeError(*state, throwScope, JSClass::info()->className, operationName); + // For custom promise-returning operations + return rejectPromiseWithThisTypeError(*state, JSClass::info()->className, operationName); + } + ASSERT(thisObject); + ASSERT_GC_OBJECT_INHERITS(thisObject, JSClass::info()); + // FIXME: We should refactor the binding generated code to use references for state and thisObject. + return operationCaller(state, thisObject, throwScope); + } + + template<AttributeSetterFunction setter, CastedThisErrorBehavior shouldThrow = CastedThisErrorBehavior::Throw> + static bool setAttribute(JSC::ExecState* state, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue encodedValue, const char* attributeName) + { + ASSERT(state); + auto throwScope = DECLARE_THROW_SCOPE(state->vm()); + auto* thisObject = castForAttribute(*state, thisValue); + if (UNLIKELY(!thisObject)) + return (shouldThrow == CastedThisErrorBehavior::Throw) ? throwSetterTypeError(*state, throwScope, JSClass::info()->className, attributeName) : false; + return setter(*state, *thisObject, JSC::JSValue::decode(encodedValue), throwScope); + } + + template<AttributeGetterFunction getter, CastedThisErrorBehavior shouldThrow = CastedThisErrorBehavior::Throw> + static JSC::EncodedJSValue attribute(JSC::ExecState* state, JSC::EncodedJSValue thisValue, const char* attributeName) + { + ASSERT(state); + auto throwScope = DECLARE_THROW_SCOPE(state->vm()); + auto* thisObject = castForAttribute(*state, thisValue); + if (UNLIKELY(!thisObject)) { + if (shouldThrow == CastedThisErrorBehavior::Throw) + return throwGetterTypeError(*state, throwScope, JSClass::info()->className, attributeName); + if (shouldThrow == CastedThisErrorBehavior::RejectPromise) + return rejectPromiseWithGetterTypeError(*state, JSClass::info()->className, attributeName); + return JSC::JSValue::encode(JSC::jsUndefined()); + } + return JSC::JSValue::encode(getter(*state, *thisObject, throwScope)); + } +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMBindingSecurity.cpp b/Source/WebCore/bindings/js/JSDOMBindingSecurity.cpp new file mode 100644 index 000000000..4eefc8691 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMBindingSecurity.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2004-2011, 2013, 2016 Apple Inc. All rights reserved. + * Copyright (C) 2007 Samuel Weinig <sam@webkit.org> + * Copyright (C) 2013 Michael Pruett <michael@68k.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "JSDOMBindingSecurity.h" + +#include "DOMWindow.h" +#include "Document.h" +#include "Frame.h" +#include "JSDOMExceptionHandling.h" +#include "JSDOMWindowBase.h" +#include "SecurityOrigin.h" +#include <wtf/text/WTFString.h> + +using namespace JSC; + +namespace WebCore { + +void printErrorMessageForFrame(Frame* frame, const String& message) +{ + if (!frame) + return; + frame->document()->domWindow()->printErrorMessage(message); +} + +static inline bool canAccessDocument(JSC::ExecState* state, Document* targetDocument, SecurityReportingOption reportingOption) +{ + VM& vm = state->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (!targetDocument) + return false; + + DOMWindow& active = activeDOMWindow(state); + + if (active.document()->securityOrigin().canAccess(targetDocument->securityOrigin())) + return true; + + switch (reportingOption) { + case ThrowSecurityError: + throwSecurityError(*state, scope, targetDocument->domWindow()->crossDomainAccessErrorMessage(active)); + break; + case LogSecurityError: + printErrorMessageForFrame(targetDocument->frame(), targetDocument->domWindow()->crossDomainAccessErrorMessage(active)); + break; + case DoNotReportSecurityError: + break; + } + + return false; +} + +bool BindingSecurity::shouldAllowAccessToFrame(ExecState& state, Frame& frame, String& message) +{ + if (BindingSecurity::shouldAllowAccessToFrame(&state, &frame, DoNotReportSecurityError)) + return true; + message = frame.document()->domWindow()->crossDomainAccessErrorMessage(activeDOMWindow(&state)); + return false; +} + +bool BindingSecurity::shouldAllowAccessToDOMWindow(ExecState& state, DOMWindow& globalObject, String& message) +{ + if (BindingSecurity::shouldAllowAccessToDOMWindow(&state, globalObject, DoNotReportSecurityError)) + return true; + message = globalObject.crossDomainAccessErrorMessage(activeDOMWindow(&state)); + return false; +} + +bool BindingSecurity::shouldAllowAccessToDOMWindow(JSC::ExecState* state, DOMWindow& target, SecurityReportingOption reportingOption) +{ + return canAccessDocument(state, target.document(), reportingOption); +} + +bool BindingSecurity::shouldAllowAccessToFrame(JSC::ExecState* state, Frame* target, SecurityReportingOption reportingOption) +{ + return target && canAccessDocument(state, target->document(), reportingOption); +} + +bool BindingSecurity::shouldAllowAccessToNode(JSC::ExecState& state, Node* target) +{ + return !target || canAccessDocument(&state, &target->document(), LogSecurityError); +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMBindingSecurity.h b/Source/WebCore/bindings/js/JSDOMBindingSecurity.h new file mode 100644 index 000000000..7b4085a51 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMBindingSecurity.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2003-2006, 2008-2009, 2013, 2016 Apple Inc. All rights reserved. + * Copyright (C) 2007 Samuel Weinig <sam@webkit.org> + * Copyright (C) 2009 Google, Inc. All rights reserved. + * Copyright (C) 2012 Ericsson AB. All rights reserved. + * Copyright (C) 2013 Michael Pruett <michael@68k.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "ExceptionOr.h" +#include <wtf/Forward.h> + +namespace JSC { +class ExecState; +} + +namespace WebCore { + +class DOMWindow; +class Frame; +class Node; + +void printErrorMessageForFrame(Frame*, const String& message); + +enum SecurityReportingOption { DoNotReportSecurityError, LogSecurityError, ThrowSecurityError }; + +namespace BindingSecurity { + +template<typename T> T* checkSecurityForNode(JSC::ExecState&, T&); +template<typename T> T* checkSecurityForNode(JSC::ExecState&, T*); +template<typename T> ExceptionOr<T*> checkSecurityForNode(JSC::ExecState&, ExceptionOr<T*>&&); +template<typename T> ExceptionOr<T*> checkSecurityForNode(JSC::ExecState&, ExceptionOr<T&>&&); + +bool shouldAllowAccessToDOMWindow(JSC::ExecState*, DOMWindow&, SecurityReportingOption = LogSecurityError); +bool shouldAllowAccessToDOMWindow(JSC::ExecState&, DOMWindow&, String& message); +bool shouldAllowAccessToFrame(JSC::ExecState*, Frame*, SecurityReportingOption = LogSecurityError); +bool shouldAllowAccessToFrame(JSC::ExecState&, Frame&, String& message); +bool shouldAllowAccessToNode(JSC::ExecState&, Node*); + +}; + +template<typename T> inline T* BindingSecurity::checkSecurityForNode(JSC::ExecState& state, T& node) +{ + return shouldAllowAccessToNode(state, &node) ? &node : nullptr; +} + +template<typename T> inline T* BindingSecurity::checkSecurityForNode(JSC::ExecState& state, T* node) +{ + return shouldAllowAccessToNode(state, node) ? node : nullptr; +} + +template<typename T> inline ExceptionOr<T*> BindingSecurity::checkSecurityForNode(JSC::ExecState& state, ExceptionOr<T*>&& value) +{ + if (value.hasException()) + return value.releaseException(); + return checkSecurityForNode(state, value.releaseReturnValue()); +} + +template<typename T> inline ExceptionOr<T*> BindingSecurity::checkSecurityForNode(JSC::ExecState& state, ExceptionOr<T&>&& value) +{ + if (value.hasException()) + return value.releaseException(); + return checkSecurityForNode(state, value.releaseReturnValue()); +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMBuiltinConstructor.h b/Source/WebCore/bindings/js/JSDOMBuiltinConstructor.h new file mode 100644 index 000000000..74ee3a5ca --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMBuiltinConstructor.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2015, 2016 Canon Inc. All rights reserved. + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "JSDOMBuiltinConstructorBase.h" +#include "JSDOMExceptionHandling.h" +#include "JSDOMWrapperCache.h" + +namespace WebCore { + +template<typename JSClass> class JSDOMBuiltinConstructor : public JSDOMBuiltinConstructorBase { +public: + using Base = JSDOMBuiltinConstructorBase; + + static JSDOMBuiltinConstructor* create(JSC::VM&, JSC::Structure*, JSDOMGlobalObject&); + static JSC::Structure* createStructure(JSC::VM&, JSC::JSGlobalObject&, JSC::JSValue prototype); + + DECLARE_INFO; + + // Usually defined for each specialization class. + static JSC::JSValue prototypeForStructure(JSC::VM&, const JSDOMGlobalObject&); + +private: + JSDOMBuiltinConstructor(JSC::Structure* structure, JSDOMGlobalObject& globalObject) + : Base(structure, globalObject) + { + } + + void finishCreation(JSC::VM&, JSDOMGlobalObject&); + static JSC::ConstructType getConstructData(JSC::JSCell*, JSC::ConstructData&); + static JSC::EncodedJSValue JSC_HOST_CALL construct(JSC::ExecState*); + + JSC::EncodedJSValue callConstructor(JSC::ExecState&, JSC::JSObject&); + JSC::EncodedJSValue callConstructor(JSC::ExecState&, JSC::JSObject*); + + // Usually defined for each specialization class. + void initializeProperties(JSC::VM&, JSDOMGlobalObject&) { } + // Must be defined for each specialization class. + JSC::FunctionExecutable* initializeExecutable(JSC::VM&); +}; + +template<typename JSClass> inline JSDOMBuiltinConstructor<JSClass>* JSDOMBuiltinConstructor<JSClass>::create(JSC::VM& vm, JSC::Structure* structure, JSDOMGlobalObject& globalObject) +{ + JSDOMBuiltinConstructor* constructor = new (NotNull, JSC::allocateCell<JSDOMBuiltinConstructor>(vm.heap)) JSDOMBuiltinConstructor(structure, globalObject); + constructor->finishCreation(vm, globalObject); + return constructor; +} + +template<typename JSClass> inline JSC::Structure* JSDOMBuiltinConstructor<JSClass>::createStructure(JSC::VM& vm, JSC::JSGlobalObject& globalObject, JSC::JSValue prototype) +{ + return JSC::Structure::create(vm, &globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); +} + +template<typename JSClass> inline void JSDOMBuiltinConstructor<JSClass>::finishCreation(JSC::VM& vm, JSDOMGlobalObject& globalObject) +{ + Base::finishCreation(vm); + ASSERT(inherits(vm, info())); + setInitializeFunction(vm, *JSC::JSFunction::createBuiltinFunction(vm, initializeExecutable(vm), &globalObject)); + initializeProperties(vm, globalObject); +} + +template<typename JSClass> inline JSC::EncodedJSValue JSDOMBuiltinConstructor<JSClass>::callConstructor(JSC::ExecState& state, JSC::JSObject& object) +{ + Base::callFunctionWithCurrentArguments(state, object, *initializeFunction()); + return JSC::JSValue::encode(&object); +} + +template<typename JSClass> inline JSC::EncodedJSValue JSDOMBuiltinConstructor<JSClass>::callConstructor(JSC::ExecState& state, JSC::JSObject* object) +{ + JSC::VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + if (!object) + return throwConstructorScriptExecutionContextUnavailableError(state, scope, info()->className); + return callConstructor(state, *object); +} + +template<typename JSClass> inline +typename std::enable_if<JSDOMObjectInspector<JSClass>::isSimpleWrapper, JSC::JSObject&>::type createJSObject(JSDOMBuiltinConstructor<JSClass>& constructor) +{ + auto& globalObject = *constructor.globalObject(); + return *JSClass::create(getDOMStructure<JSClass>(globalObject.vm(), globalObject), &globalObject, JSClass::DOMWrapped::create()); +} + +template<typename JSClass> inline +typename std::enable_if<JSDOMObjectInspector<JSClass>::isBuiltin, JSC::JSObject&>::type createJSObject(JSDOMBuiltinConstructor<JSClass>& constructor) +{ + auto& globalObject = *constructor.globalObject(); + return *JSClass::create(getDOMStructure<JSClass>(globalObject.vm(), globalObject), &globalObject); +} + +template<typename JSClass> inline +typename std::enable_if<JSDOMObjectInspector<JSClass>::isComplexWrapper, JSC::JSObject*>::type createJSObject(JSDOMBuiltinConstructor<JSClass>& constructor) +{ + ScriptExecutionContext* context = constructor.scriptExecutionContext(); + if (!context) + return nullptr; + auto& globalObject = *constructor.globalObject(); + return JSClass::create(getDOMStructure<JSClass>(globalObject.vm(), globalObject), &globalObject, JSClass::DOMWrapped::create(*context)); +} + +template<typename JSClass> inline JSC::EncodedJSValue JSC_HOST_CALL JSDOMBuiltinConstructor<JSClass>::construct(JSC::ExecState* state) +{ + ASSERT(state); + auto* castedThis = JSC::jsCast<JSDOMBuiltinConstructor*>(state->jsCallee()); + return castedThis->callConstructor(*state, createJSObject(*castedThis)); +} + +template<typename JSClass> inline JSC::ConstructType JSDOMBuiltinConstructor<JSClass>::getConstructData(JSC::JSCell*, JSC::ConstructData& constructData) +{ + constructData.native.function = construct; + return JSC::ConstructType::Host; +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMBuiltinConstructorBase.cpp b/Source/WebCore/bindings/js/JSDOMBuiltinConstructorBase.cpp new file mode 100644 index 000000000..42ea13278 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMBuiltinConstructorBase.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2004-2011, 2013, 2016 Apple Inc. All rights reserved. + * Copyright (C) 2007 Samuel Weinig <sam@webkit.org> + * Copyright (C) 2013 Michael Pruett <michael@68k.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "JSDOMBuiltinConstructorBase.h" + +#include <runtime/JSCInlines.h> + +using namespace JSC; + +namespace WebCore { + +void JSDOMBuiltinConstructorBase::callFunctionWithCurrentArguments(JSC::ExecState& state, JSC::JSObject& thisObject, JSC::JSFunction& function) +{ + JSC::CallData callData; + JSC::CallType callType = JSC::getCallData(&function, callData); + ASSERT(callType != CallType::None); + + JSC::MarkedArgumentBuffer arguments; + for (unsigned i = 0; i < state.argumentCount(); ++i) + arguments.append(state.uncheckedArgument(i)); + JSC::call(&state, &function, callType, callData, &thisObject, arguments); +} + +void JSDOMBuiltinConstructorBase::visitChildren(JSC::JSCell* cell, JSC::SlotVisitor& visitor) +{ + auto* thisObject = jsCast<JSDOMBuiltinConstructorBase*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + Base::visitChildren(thisObject, visitor); + visitor.append(thisObject->m_initializeFunction); +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMBuiltinConstructorBase.h b/Source/WebCore/bindings/js/JSDOMBuiltinConstructorBase.h new file mode 100644 index 000000000..c6cf294f1 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMBuiltinConstructorBase.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2015, 2016 Canon Inc. All rights reserved. + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "JSDOMConstructorBase.h" + +namespace WebCore { + +class JSDOMBuiltinConstructorBase : public JSDOMConstructorBase { +public: + using Base = JSDOMConstructorBase; + +protected: + JSDOMBuiltinConstructorBase(JSC::Structure* structure, JSDOMGlobalObject& globalObject) + : JSDOMConstructorBase(structure, globalObject) + { + } + + static void visitChildren(JSC::JSCell*, JSC::SlotVisitor&); + + JSC::JSFunction* initializeFunction(); + void setInitializeFunction(JSC::VM&, JSC::JSFunction&); + + static void callFunctionWithCurrentArguments(JSC::ExecState&, JSC::JSObject& thisObject, JSC::JSFunction&); + +private: + JSC::WriteBarrier<JSC::JSFunction> m_initializeFunction; +}; + +inline JSC::JSFunction* JSDOMBuiltinConstructorBase::initializeFunction() +{ + return m_initializeFunction.get(); +} + +inline void JSDOMBuiltinConstructorBase::setInitializeFunction(JSC::VM& vm, JSC::JSFunction& function) +{ + m_initializeFunction.set(vm, this, &function); +} + + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConstructor.h b/Source/WebCore/bindings/js/JSDOMConstructor.h new file mode 100644 index 000000000..01767a940 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConstructor.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2015, 2016 Canon Inc. All rights reserved. + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "JSDOMConstructorBase.h" + +namespace WebCore { + +template<typename JSClass> class JSDOMConstructor : public JSDOMConstructorBase { +public: + using Base = JSDOMConstructorBase; + + static JSDOMConstructor* create(JSC::VM&, JSC::Structure*, JSDOMGlobalObject&); + static JSC::Structure* createStructure(JSC::VM&, JSC::JSGlobalObject&, JSC::JSValue prototype); + + DECLARE_INFO; + + // Must be defined for each specialization class. + static JSC::JSValue prototypeForStructure(JSC::VM&, const JSDOMGlobalObject&); + +private: + JSDOMConstructor(JSC::Structure* structure, JSDOMGlobalObject& globalObject) + : Base(structure, globalObject) + { + } + + void finishCreation(JSC::VM&, JSDOMGlobalObject&); + static JSC::ConstructType getConstructData(JSC::JSCell*, JSC::ConstructData&); + + // Usually defined for each specialization class. + void initializeProperties(JSC::VM&, JSDOMGlobalObject&) { } + // Must be defined for each specialization class. + static JSC::EncodedJSValue JSC_HOST_CALL construct(JSC::ExecState*); +}; + +template<typename JSClass> inline JSDOMConstructor<JSClass>* JSDOMConstructor<JSClass>::create(JSC::VM& vm, JSC::Structure* structure, JSDOMGlobalObject& globalObject) +{ + JSDOMConstructor* constructor = new (NotNull, JSC::allocateCell<JSDOMConstructor>(vm.heap)) JSDOMConstructor(structure, globalObject); + constructor->finishCreation(vm, globalObject); + return constructor; +} + +template<typename JSClass> inline JSC::Structure* JSDOMConstructor<JSClass>::createStructure(JSC::VM& vm, JSC::JSGlobalObject& globalObject, JSC::JSValue prototype) +{ + return JSC::Structure::create(vm, &globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); +} + +template<typename JSClass> inline void JSDOMConstructor<JSClass>::finishCreation(JSC::VM& vm, JSDOMGlobalObject& globalObject) +{ + Base::finishCreation(vm); + ASSERT(inherits(vm, info())); + initializeProperties(vm, globalObject); +} + +template<typename JSClass> inline JSC::ConstructType JSDOMConstructor<JSClass>::getConstructData(JSC::JSCell*, JSC::ConstructData& constructData) +{ + constructData.native.function = construct; + return JSC::ConstructType::Host; +} + + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMPluginCustom.cpp b/Source/WebCore/bindings/js/JSDOMConstructorBase.cpp index e23e60f76..3c04c5408 100644 --- a/Source/WebCore/bindings/js/JSDOMPluginCustom.cpp +++ b/Source/WebCore/bindings/js/JSDOMConstructorBase.cpp @@ -1,5 +1,8 @@ /* - * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2004-2011, 2013, 2016 Apple Inc. All rights reserved. + * Copyright (C) 2007 Samuel Weinig <sam@webkit.org> + * Copyright (C) 2013 Michael Pruett <michael@68k.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,25 +20,28 @@ */ #include "config.h" -#include "JSDOMPlugin.h" +#include "JSDOMConstructor.h" -#include "DOMPlugin.h" -#include "JSDOMMimeType.h" -#include <wtf/text/AtomicString.h> +#include <runtime/JSCInlines.h> + +using namespace JSC; namespace WebCore { -using namespace JSC; +STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSDOMConstructorBase); -bool JSDOMPlugin::canGetItemsForName(ExecState*, DOMPlugin* plugin, PropertyName propertyName) +static EncodedJSValue JSC_HOST_CALL callThrowTypeError(ExecState* exec) { - return plugin->canGetItemsForName(propertyNameToAtomicString(propertyName)); + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + throwTypeError(exec, scope, ASCIILiteral("Constructor requires 'new' operator")); + return JSValue::encode(jsNull()); } -EncodedJSValue JSDOMPlugin::nameGetter(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName propertyName) +CallType JSDOMConstructorBase::getCallData(JSCell*, CallData& callData) { - JSDOMPlugin* thisObj = jsCast<JSDOMPlugin*>(JSValue::decode(slotBase)); - return JSValue::encode(toJS(exec, thisObj->globalObject(), thisObj->impl().namedItem(propertyNameToAtomicString(propertyName)))); + callData.native.function = callThrowTypeError; + return CallType::Host; } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConstructorBase.h b/Source/WebCore/bindings/js/JSDOMConstructorBase.h new file mode 100644 index 000000000..a142e5ad6 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConstructorBase.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015, 2016 Canon Inc. All rights reserved. + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "JSDOMWrapper.h" + +namespace WebCore { + +// Base class for all constructor objects in the JSC bindings. +class JSDOMConstructorBase : public JSDOMObject { +public: + using Base = JSDOMObject; + + static const unsigned StructureFlags = Base::StructureFlags | JSC::ImplementsHasInstance | JSC::ImplementsDefaultHasInstance | JSC::TypeOfShouldCallGetCallData; + static JSC::Structure* createStructure(JSC::VM&, JSC::JSGlobalObject*, JSC::JSValue); + +protected: + JSDOMConstructorBase(JSC::Structure* structure, JSDOMGlobalObject& globalObject) + : JSDOMObject(structure, globalObject) + { + } + + static String className(const JSObject*); + static JSC::CallType getCallData(JSCell*, JSC::CallData&); +}; + +inline JSC::Structure* JSDOMConstructorBase::createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) +{ + return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); +} + +inline String JSDOMConstructorBase::className(const JSObject*) +{ + return ASCIILiteral("Function"); +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConstructorNotConstructable.h b/Source/WebCore/bindings/js/JSDOMConstructorNotConstructable.h new file mode 100644 index 000000000..399742b38 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConstructorNotConstructable.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2015, 2016 Canon Inc. All rights reserved. + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "JSDOMConstructorBase.h" +#include "JSDOMExceptionHandling.h" + +namespace WebCore { + +template<typename JSClass> class JSDOMConstructorNotConstructable : public JSDOMConstructorBase { +public: + using Base = JSDOMConstructorBase; + + static JSDOMConstructorNotConstructable* create(JSC::VM&, JSC::Structure*, JSDOMGlobalObject&); + static JSC::Structure* createStructure(JSC::VM&, JSC::JSGlobalObject&, JSC::JSValue prototype); + + DECLARE_INFO; + + // Must be defined for each specialization class. + static JSC::JSValue prototypeForStructure(JSC::VM&, const JSDOMGlobalObject&); + +private: + JSDOMConstructorNotConstructable(JSC::Structure* structure, JSDOMGlobalObject& globalObject) + : Base(structure, globalObject) + { + } + + void finishCreation(JSC::VM&, JSDOMGlobalObject&); + + // Usually defined for each specialization class. + void initializeProperties(JSC::VM&, JSDOMGlobalObject&) { } + + static JSC::EncodedJSValue JSC_HOST_CALL callThrowTypeError(JSC::ExecState* exec) + { + JSC::VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + JSC::throwTypeError(exec, scope, ASCIILiteral("Illegal constructor")); + return JSC::JSValue::encode(JSC::jsNull()); + } + + static JSC::CallType getCallData(JSC::JSCell*, JSC::CallData& callData) + { + callData.native.function = callThrowTypeError; + return JSC::CallType::Host; + } +}; + +template<typename JSClass> inline JSDOMConstructorNotConstructable<JSClass>* JSDOMConstructorNotConstructable<JSClass>::create(JSC::VM& vm, JSC::Structure* structure, JSDOMGlobalObject& globalObject) +{ + JSDOMConstructorNotConstructable* constructor = new (NotNull, JSC::allocateCell<JSDOMConstructorNotConstructable>(vm.heap)) JSDOMConstructorNotConstructable(structure, globalObject); + constructor->finishCreation(vm, globalObject); + return constructor; +} + +template<typename JSClass> inline JSC::Structure* JSDOMConstructorNotConstructable<JSClass>::createStructure(JSC::VM& vm, JSC::JSGlobalObject& globalObject, JSC::JSValue prototype) +{ + return JSC::Structure::create(vm, &globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); +} + +template<typename JSClass> inline void JSDOMConstructorNotConstructable<JSClass>::finishCreation(JSC::VM& vm, JSDOMGlobalObject& globalObject) +{ + Base::finishCreation(vm); + ASSERT(inherits(vm, info())); + initializeProperties(vm, globalObject); +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/DOMObjectHashTableMap.cpp b/Source/WebCore/bindings/js/JSDOMConstructorWithDocument.cpp index 4d6b916bc..c23acffd0 100644 --- a/Source/WebCore/bindings/js/DOMObjectHashTableMap.cpp +++ b/Source/WebCore/bindings/js/JSDOMConstructorWithDocument.cpp @@ -1,7 +1,8 @@ /* * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2004-2011, 2013, 2016 Apple Inc. All rights reserved. * Copyright (C) 2007 Samuel Weinig <sam@webkit.org> + * Copyright (C) 2013 Michael Pruett <michael@68k.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,19 +20,12 @@ */ #include "config.h" -#include "DOMObjectHashTableMap.h" - -#include "WebCoreJSClientData.h" +#include "JSDOMConstructorWithDocument.h" using namespace JSC; -namespace WebCore{ +namespace WebCore { -DOMObjectHashTableMap& DOMObjectHashTableMap::mapFor(VM& vm) -{ - VM::ClientData* clientData = vm.clientData; - ASSERT(clientData); - return static_cast<WebCoreJSClientData*>(clientData)->hashTableMap; -} +STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSDOMConstructorWithDocument); } // namespace WebCore diff --git a/Source/WebCore/bindings/js/DOMConstructorWithDocument.h b/Source/WebCore/bindings/js/JSDOMConstructorWithDocument.h index 5c98f6116..1a9a95964 100644 --- a/Source/WebCore/bindings/js/DOMConstructorWithDocument.h +++ b/Source/WebCore/bindings/js/JSDOMConstructorWithDocument.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2009 Google, Inc. All rights reserved. + * Copyright (C) 2015, 2016 Canon Inc. All rights reserved. + * Copyright (C) 2016 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,38 +17,35 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ - -#ifndef DOMConstructorWithDocument_h -#define DOMConstructorWithDocument_h +#pragma once #include "Document.h" -#include "JSDOMBinding.h" +#include "JSDOMConstructorBase.h" namespace WebCore { // Constructors using this base class depend on being in a Document and // can never be used from a WorkerGlobalScope. -class DOMConstructorWithDocument : public DOMConstructorObject { - typedef DOMConstructorObject Base; +class JSDOMConstructorWithDocument : public JSDOMConstructorBase { public: + using Base = JSDOMConstructorBase; + Document* document() const { - return toDocument(scriptExecutionContext()); + return downcast<Document>(scriptExecutionContext()); } protected: - DOMConstructorWithDocument(JSC::Structure* structure, JSDOMGlobalObject* globalObject) - : DOMConstructorObject(structure, globalObject) + JSDOMConstructorWithDocument(JSC::Structure* structure, JSDOMGlobalObject& globalObject) + : JSDOMConstructorBase(structure, globalObject) { } - void finishCreation(JSDOMGlobalObject* globalObject) + void finishCreation(JSDOMGlobalObject& globalObject) { - Base::finishCreation(globalObject->vm()); - ASSERT(globalObject->scriptExecutionContext()->isDocument()); + Base::finishCreation(globalObject.vm()); + ASSERT(globalObject.scriptExecutionContext()->isDocument()); } }; } // namespace WebCore - -#endif // DOMConstructorWithDocument_h diff --git a/Source/WebCore/bindings/js/JSDOMConvert.h b/Source/WebCore/bindings/js/JSDOMConvert.h new file mode 100644 index 000000000..44afd4d3e --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvert.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "JSDOMConvertAny.h" +#include "JSDOMConvertBoolean.h" +#include "JSDOMConvertBufferSource.h" +#include "JSDOMConvertCallbacks.h" +#include "JSDOMConvertDate.h" +#include "JSDOMConvertDictionary.h" +#include "JSDOMConvertEnumeration.h" +#include "JSDOMConvertEventListener.h" +#include "JSDOMConvertIndexedDB.h" +#include "JSDOMConvertInterface.h" +#include "JSDOMConvertJSON.h" +#include "JSDOMConvertNull.h" +#include "JSDOMConvertNullable.h" +#include "JSDOMConvertNumbers.h" +#include "JSDOMConvertObject.h" +#include "JSDOMConvertRecord.h" +#include "JSDOMConvertSequences.h" +#include "JSDOMConvertSerializedScriptValue.h" +#include "JSDOMConvertStrings.h" +#include "JSDOMConvertUnion.h" +#include "JSDOMConvertWebGL.h" +#include "JSDOMConvertXPathNSResolver.h" diff --git a/Source/WebCore/bindings/js/JSDOMConvertAny.h b/Source/WebCore/bindings/js/JSDOMConvertAny.h new file mode 100644 index 000000000..b27ab7ca6 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertAny.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "IDLTypes.h" +#include "JSDOMConvertBase.h" + +namespace WebCore { + +template<> struct Converter<IDLAny> : DefaultConverter<IDLAny> { + using ReturnType = JSC::JSValue; + + static JSC::JSValue convert(JSC::ExecState&, JSC::JSValue value) + { + return value; + } + + static JSC::JSValue convert(const JSC::Strong<JSC::Unknown>& value) + { + return value.get(); + } +}; + +template<> struct JSConverter<IDLAny> { + static constexpr bool needsState = false; + static constexpr bool needsGlobalObject = false; + + static JSC::JSValue convert(const JSC::JSValue& value) + { + return value; + } + + static JSC::JSValue convert(const JSC::Strong<JSC::Unknown>& value) + { + return value.get(); + } +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertBase.h b/Source/WebCore/bindings/js/JSDOMConvertBase.h new file mode 100644 index 000000000..bd23abe52 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertBase.h @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "JSDOMExceptionHandling.h" + +namespace WebCore { + +// Conversion from JSValue -> Implementation +template<typename T> struct Converter; + + +struct DefaultExceptionThrower { + void operator()(JSC::ExecState& state, JSC::ThrowScope& scope) + { + throwTypeError(&state, scope); + } +}; + +template<typename T> typename Converter<T>::ReturnType convert(JSC::ExecState&, JSC::JSValue); +template<typename T> typename Converter<T>::ReturnType convert(JSC::ExecState&, JSC::JSValue, JSC::JSObject&); +template<typename T> typename Converter<T>::ReturnType convert(JSC::ExecState&, JSC::JSValue, JSDOMGlobalObject&); +template<typename T, typename ExceptionThrower> typename Converter<T>::ReturnType convert(JSC::ExecState&, JSC::JSValue, ExceptionThrower&&); +template<typename T, typename ExceptionThrower> typename Converter<T>::ReturnType convert(JSC::ExecState&, JSC::JSValue, JSC::JSObject&, ExceptionThrower&&); +template<typename T, typename ExceptionThrower> typename Converter<T>::ReturnType convert(JSC::ExecState&, JSC::JSValue, JSDOMGlobalObject&, ExceptionThrower&&); + +template<typename T> inline typename Converter<T>::ReturnType convert(JSC::ExecState& state, JSC::JSValue value) +{ + return Converter<T>::convert(state, value); +} + +template<typename T> inline typename Converter<T>::ReturnType convert(JSC::ExecState& state, JSC::JSValue value, JSC::JSObject& thisObject) +{ + return Converter<T>::convert(state, value, thisObject); +} + +template<typename T> inline typename Converter<T>::ReturnType convert(JSC::ExecState& state, JSC::JSValue value, JSDOMGlobalObject& globalObject) +{ + return Converter<T>::convert(state, value, globalObject); +} + +template<typename T, typename ExceptionThrower> inline typename Converter<T>::ReturnType convert(JSC::ExecState& state, JSC::JSValue value, ExceptionThrower&& exceptionThrower) +{ + return Converter<T>::convert(state, value, std::forward<ExceptionThrower>(exceptionThrower)); +} + +template<typename T, typename ExceptionThrower> inline typename Converter<T>::ReturnType convert(JSC::ExecState& state, JSC::JSValue value, JSC::JSObject& thisObject, ExceptionThrower&& exceptionThrower) +{ + return Converter<T>::convert(state, value, thisObject, std::forward<ExceptionThrower>(exceptionThrower)); +} + +template<typename T, typename ExceptionThrower> inline typename Converter<T>::ReturnType convert(JSC::ExecState& state, JSC::JSValue value, JSDOMGlobalObject& globalObject, ExceptionThrower&& exceptionThrower) +{ + return Converter<T>::convert(state, value, globalObject, std::forward<ExceptionThrower>(exceptionThrower)); +} + +// Conversion from Implementation -> JSValue +template<typename T> struct JSConverter; + +template<typename T, typename U> inline JSC::JSValue toJS(U&&); +template<typename T, typename U> inline JSC::JSValue toJS(JSC::ExecState&, U&&); +template<typename T, typename U> inline JSC::JSValue toJS(JSC::ExecState&, JSDOMGlobalObject&, U&&); +template<typename T, typename U> inline JSC::JSValue toJS(JSC::ExecState&, JSC::ThrowScope&, ExceptionOr<U>&&); +template<typename T, typename U> inline JSC::JSValue toJS(JSC::ExecState&, JSDOMGlobalObject&, JSC::ThrowScope&, ExceptionOr<U>&&); +template<typename T, typename U> inline JSC::JSValue toJSNewlyCreated(JSC::ExecState&, JSDOMGlobalObject&, U&&); +template<typename T, typename U> inline JSC::JSValue toJSNewlyCreated(JSC::ExecState&, JSDOMGlobalObject&, JSC::ThrowScope&, ExceptionOr<U>&&); + +template<typename T, bool needsState = JSConverter<T>::needsState, bool needsGlobalObject = JSConverter<T>::needsGlobalObject> +struct JSConverterOverloader; + +template<typename T> +struct JSConverterOverloader<T, true, true> { + template<typename U> static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject& globalObject, U&& value) + { + return JSConverter<T>::convert(state, globalObject, std::forward<U>(value)); + } +}; + +template<typename T> +struct JSConverterOverloader<T, true, false> { + template<typename U> static JSC::JSValue convert(JSC::ExecState& state, U&& value) + { + return JSConverter<T>::convert(state, std::forward<U>(value)); + } + + template<typename U> static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject&, U&& value) + { + return JSConverter<T>::convert(state, std::forward<U>(value)); + } +}; + +template<typename T> +struct JSConverterOverloader<T, false, false> { + template<typename U> static JSC::JSValue convert(JSC::ExecState&, U&& value) + { + return JSConverter<T>::convert(std::forward<U>(value)); + } + + template<typename U> static JSC::JSValue convert(JSC::ExecState&, JSDOMGlobalObject&, U&& value) + { + return JSConverter<T>::convert(std::forward<U>(value)); + } +}; + +template<typename T, typename U> inline JSC::JSValue toJS(U&& value) +{ + return JSConverter<T>::convert(std::forward<U>(value)); +} + +template<typename T, typename U> inline JSC::JSValue toJS(JSC::ExecState& state, U&& value) +{ + return JSConverterOverloader<T>::convert(state, std::forward<U>(value)); +} + +template<typename T, typename U> inline JSC::JSValue toJS(JSC::ExecState& state, JSDOMGlobalObject& globalObject, U&& value) +{ + return JSConverterOverloader<T>::convert(state, globalObject, std::forward<U>(value)); +} + +template<typename T, typename U> inline JSC::JSValue toJS(JSC::ExecState& state, JSC::ThrowScope& throwScope, ExceptionOr<U>&& value) +{ + if (UNLIKELY(value.hasException())) { + propagateException(state, throwScope, value.releaseException()); + return { }; + } + + return toJS<T>(state, value.releaseReturnValue()); +} + +template<typename T, typename U> inline JSC::JSValue toJS(JSC::ExecState& state, JSDOMGlobalObject& globalObject, JSC::ThrowScope& throwScope, ExceptionOr<U>&& value) +{ + if (UNLIKELY(value.hasException())) { + propagateException(state, throwScope, value.releaseException()); + return { }; + } + + return toJS<T>(state, globalObject, value.releaseReturnValue()); +} + +template<typename T, typename U> inline JSC::JSValue toJSNewlyCreated(JSC::ExecState& state, JSDOMGlobalObject& globalObject, U&& value) +{ + return JSConverter<T>::convertNewlyCreated(state, globalObject, std::forward<U>(value)); +} + +template<typename T, typename U> inline JSC::JSValue toJSNewlyCreated(JSC::ExecState& state, JSDOMGlobalObject& globalObject, JSC::ThrowScope& throwScope, ExceptionOr<U>&& value) +{ + if (UNLIKELY(value.hasException())) { + propagateException(state, throwScope, value.releaseException()); + return { }; + } + + return toJSNewlyCreated<T>(state, globalObject, value.releaseReturnValue()); +} + + +template<typename T> struct DefaultConverter { + using ReturnType = typename T::ImplementationType; +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertBoolean.h b/Source/WebCore/bindings/js/JSDOMConvertBoolean.h new file mode 100644 index 000000000..853be0c7e --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertBoolean.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "IDLTypes.h" +#include "JSDOMConvertBase.h" + +namespace WebCore { + +template<> struct Converter<IDLBoolean> : DefaultConverter<IDLBoolean> { + static bool convert(JSC::ExecState& state, JSC::JSValue value) + { + return value.toBoolean(&state); + } +}; + +template<> struct JSConverter<IDLBoolean> { + static constexpr bool needsState = false; + static constexpr bool needsGlobalObject = false; + + static JSC::JSValue convert(bool value) + { + return JSC::jsBoolean(value); + } +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertBufferSource.h b/Source/WebCore/bindings/js/JSDOMConvertBufferSource.h new file mode 100644 index 000000000..dc45fc129 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertBufferSource.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "BufferSource.h" +#include "JSDOMConvertInterface.h" +#include "JSDOMWrapperCache.h" +#include "JSDynamicDowncast.h" +#include <runtime/JSTypedArrays.h> + +namespace WebCore { + +// FIXME: It is wrong that we treat buffer related types as interfaces, they should be their own IDL type. + +// Add adaptors to make ArrayBuffer / ArrayBufferView / typed arrays act like normal interfaces. + +template<typename ImplementationClass> struct JSDOMWrapperConverterTraits; + +template<> struct JSDOMWrapperConverterTraits<JSC::ArrayBuffer> { + using WrapperClass = JSC::JSArrayBuffer; + using ToWrappedReturnType = JSC::ArrayBuffer*; +}; + +template<> struct JSDOMWrapperConverterTraits<JSC::ArrayBufferView> { + using WrapperClass = JSC::JSArrayBufferView; + using ToWrappedReturnType = RefPtr<ArrayBufferView>; +}; + +template<typename Adaptor> struct JSDOMWrapperConverterTraits<JSC::GenericTypedArrayView<Adaptor>> { + using WrapperClass = JSC::JSGenericTypedArrayView<Adaptor>; + using ToWrappedReturnType = RefPtr<JSC::GenericTypedArrayView<Adaptor>>; +}; + + +inline RefPtr<JSC::Int8Array> toPossiblySharedInt8Array(JSC::VM& vm, JSC::JSValue value) { return JSC::toPossiblySharedNativeTypedView<JSC::Int8Adaptor>(vm, value); } +inline RefPtr<JSC::Int16Array> toPossiblySharedInt16Array(JSC::VM& vm, JSC::JSValue value) { return JSC::toPossiblySharedNativeTypedView<JSC::Int16Adaptor>(vm, value); } +inline RefPtr<JSC::Int32Array> toPossiblySharedInt32Array(JSC::VM& vm, JSC::JSValue value) { return JSC::toPossiblySharedNativeTypedView<JSC::Int32Adaptor>(vm, value); } +inline RefPtr<JSC::Uint8Array> toPossiblySharedUint8Array(JSC::VM& vm, JSC::JSValue value) { return JSC::toPossiblySharedNativeTypedView<JSC::Uint8Adaptor>(vm, value); } +inline RefPtr<JSC::Uint8ClampedArray> toPossiblySharedUint8ClampedArray(JSC::VM& vm, JSC::JSValue value) { return JSC::toPossiblySharedNativeTypedView<JSC::Uint8ClampedAdaptor>(vm, value); } +inline RefPtr<JSC::Uint16Array> toPossiblySharedUint16Array(JSC::VM& vm, JSC::JSValue value) { return JSC::toPossiblySharedNativeTypedView<JSC::Uint16Adaptor>(vm, value); } +inline RefPtr<JSC::Uint32Array> toPossiblySharedUint32Array(JSC::VM& vm, JSC::JSValue value) { return JSC::toPossiblySharedNativeTypedView<JSC::Uint32Adaptor>(vm, value); } +inline RefPtr<JSC::Float32Array> toPossiblySharedFloat32Array(JSC::VM& vm, JSC::JSValue value) { return JSC::toPossiblySharedNativeTypedView<JSC::Float32Adaptor>(vm, value); } +inline RefPtr<JSC::Float64Array> toPossiblySharedFloat64Array(JSC::VM& vm, JSC::JSValue value) { return JSC::toPossiblySharedNativeTypedView<JSC::Float64Adaptor>(vm, value); } + +inline RefPtr<JSC::Int8Array> toUnsharedInt8Array(JSC::VM& vm, JSC::JSValue value) { return JSC::toUnsharedNativeTypedView<JSC::Int8Adaptor>(vm, value); } +inline RefPtr<JSC::Int16Array> toUnsharedInt16Array(JSC::VM& vm, JSC::JSValue value) { return JSC::toUnsharedNativeTypedView<JSC::Int16Adaptor>(vm, value); } +inline RefPtr<JSC::Int32Array> toUnsharedInt32Array(JSC::VM& vm, JSC::JSValue value) { return JSC::toUnsharedNativeTypedView<JSC::Int32Adaptor>(vm, value); } +inline RefPtr<JSC::Uint8Array> toUnsharedUint8Array(JSC::VM& vm, JSC::JSValue value) { return JSC::toUnsharedNativeTypedView<JSC::Uint8Adaptor>(vm, value); } +inline RefPtr<JSC::Uint8ClampedArray> toUnsharedUint8ClampedArray(JSC::VM& vm, JSC::JSValue value) { return JSC::toUnsharedNativeTypedView<JSC::Uint8ClampedAdaptor>(vm, value); } +inline RefPtr<JSC::Uint16Array> toUnsharedUint16Array(JSC::VM& vm, JSC::JSValue value) { return JSC::toUnsharedNativeTypedView<JSC::Uint16Adaptor>(vm, value); } +inline RefPtr<JSC::Uint32Array> toUnsharedUint32Array(JSC::VM& vm, JSC::JSValue value) { return JSC::toUnsharedNativeTypedView<JSC::Uint32Adaptor>(vm, value); } +inline RefPtr<JSC::Float32Array> toUnsharedFloat32Array(JSC::VM& vm, JSC::JSValue value) { return JSC::toUnsharedNativeTypedView<JSC::Float32Adaptor>(vm, value); } +inline RefPtr<JSC::Float64Array> toUnsharedFloat64Array(JSC::VM& vm, JSC::JSValue value) { return JSC::toUnsharedNativeTypedView<JSC::Float64Adaptor>(vm, value); } + +inline JSC::JSValue toJS(JSC::ExecState* state, JSDOMGlobalObject* globalObject, JSC::ArrayBuffer& buffer) +{ + if (auto result = getCachedWrapper(globalObject->world(), buffer)) + return result; + + // The JSArrayBuffer::create function will register the wrapper in finishCreation. + return JSC::JSArrayBuffer::create(state->vm(), globalObject->arrayBufferStructure(buffer.sharingMode()), &buffer); +} + +inline JSC::JSValue toJS(JSC::ExecState* state, JSC::JSGlobalObject* globalObject, JSC::ArrayBufferView& view) +{ + return view.wrap(state, globalObject); +} + +inline JSC::JSValue toJS(JSC::ExecState* state, JSDOMGlobalObject* globalObject, JSC::ArrayBuffer* buffer) +{ + if (!buffer) + return JSC::jsNull(); + return toJS(state, globalObject, *buffer); +} + +inline JSC::JSValue toJS(JSC::ExecState* state, JSC::JSGlobalObject* globalObject, JSC::ArrayBufferView* view) +{ + if (!view) + return JSC::jsNull(); + return toJS(state, globalObject, *view); +} + +inline RefPtr<JSC::ArrayBufferView> toPossiblySharedArrayBufferView(JSC::VM& vm, JSC::JSValue value) +{ + auto* wrapper = jsDynamicDowncast<JSC::JSArrayBufferView*>(vm, value); + if (!wrapper) + return nullptr; + return wrapper->possiblySharedImpl(); +} + +inline RefPtr<JSC::ArrayBufferView> toUnsharedArrayBufferView(JSC::VM& vm, JSC::JSValue value) +{ + auto result = toPossiblySharedArrayBufferView(vm, value); + if (!result || result->isShared()) + return nullptr; + return result; +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertCallbacks.h b/Source/WebCore/bindings/js/JSDOMConvertCallbacks.h new file mode 100644 index 000000000..3c1397aeb --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertCallbacks.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "IDLTypes.h" +#include "JSDOMConvertBase.h" + +namespace WebCore { + +template<typename T> struct Converter<IDLCallbackFunction<T>> : DefaultConverter<IDLCallbackFunction<T>> { + template<typename ExceptionThrower = DefaultExceptionThrower> + static RefPtr<T> convert(JSC::ExecState& state, JSC::JSValue value, JSDOMGlobalObject& globalObject, ExceptionThrower&& exceptionThrower = ExceptionThrower()) + { + JSC::VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (!value.isFunction()) { + exceptionThrower(state, scope); + return nullptr; + } + + return T::create(JSC::asObject(value), &globalObject); + } +}; + +template<typename T> struct JSConverter<IDLCallbackFunction<T>> { + static constexpr bool needsState = false; + static constexpr bool needsGlobalObject = false; + + template <typename U> + static JSC::JSValue convert(const U& value) + { + return toJS(Detail::getPtrOrRef(value)); + } + + template<typename U> + static JSC::JSValue convertNewlyCreated(U&& value) + { + return toJSNewlyCreated(std::forward<U>(value)); + } +}; + + +template<typename T> struct Converter<IDLCallbackInterface<T>> : DefaultConverter<IDLCallbackInterface<T>> { + template<typename ExceptionThrower = DefaultExceptionThrower> + static RefPtr<T> convert(JSC::ExecState& state, JSC::JSValue value, JSDOMGlobalObject& globalObject, ExceptionThrower&& exceptionThrower = ExceptionThrower()) + { + JSC::VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (!value.isObject()) { + exceptionThrower(state, scope); + return nullptr; + } + + return T::create(JSC::asObject(value), &globalObject); + } +}; + +template<typename T> struct JSConverter<IDLCallbackInterface<T>> { + static constexpr bool needsState = false; + static constexpr bool needsGlobalObject = false; + + template <typename U> + static JSC::JSValue convert(const U& value) + { + return toJS(Detail::getPtrOrRef(value)); + } + + template<typename U> + static JSC::JSValue convertNewlyCreated(U&& value) + { + return toJSNewlyCreated(std::forward<U>(value)); + } +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertDate.cpp b/Source/WebCore/bindings/js/JSDOMConvertDate.cpp new file mode 100644 index 000000000..c019a6e5b --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertDate.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2004-2011, 2013, 2016 Apple Inc. All rights reserved. + * Copyright (C) 2007 Samuel Weinig <sam@webkit.org> + * Copyright (C) 2013 Michael Pruett <michael@68k.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "JSDOMConvertDate.h" + +#include <heap/HeapInlines.h> +#include <runtime/DateInstance.h> +#include <runtime/JSCJSValueInlines.h> +#include <runtime/JSGlobalObject.h> + +using namespace JSC; + +namespace WebCore { + +// FIXME: This should get passed a global object rather than getting it out of the ExecState. +JSValue jsDate(ExecState& state, double value) +{ + return DateInstance::create(state.vm(), state.lexicalGlobalObject()->dateStructure(), value); +} + +double valueToDate(ExecState& state, JSValue value) +{ + if (value.isNumber()) + return value.asNumber(); + if (!value.inherits(state.vm(), DateInstance::info())) + return std::numeric_limits<double>::quiet_NaN(); + return static_cast<DateInstance*>(value.toObject(&state))->internalNumber(); +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertDate.h b/Source/WebCore/bindings/js/JSDOMConvertDate.h new file mode 100644 index 000000000..4314de6e4 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertDate.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "IDLTypes.h" +#include "JSDOMConvertBase.h" + +namespace WebCore { + +JSC::JSValue jsDate(JSC::ExecState&, double value); +double valueToDate(JSC::ExecState&, JSC::JSValue); // NaN if the value can't be converted to a date. + +template<> struct Converter<IDLDate> : DefaultConverter<IDLDate> { + static double convert(JSC::ExecState& state, JSC::JSValue value) + { + return valueToDate(state, value); + } +}; + +template<> struct JSConverter<IDLDate> { + static constexpr bool needsState = true; + static constexpr bool needsGlobalObject = false; + + // FIXME: This should be taking a JSDOMGlobalObject and passing it to jsDate. + static JSC::JSValue convert(JSC::ExecState& state, double value) + { + return jsDate(state, value); + } +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertDictionary.h b/Source/WebCore/bindings/js/JSDOMConvertDictionary.h new file mode 100644 index 000000000..19fceff83 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertDictionary.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "IDLTypes.h" +#include "JSDOMConvertBase.h" + +namespace WebCore { + +// Specialized by generated code for IDL dictionary conversion. +template<typename T> T convertDictionary(JSC::ExecState&, JSC::JSValue); + + +template<typename T> struct Converter<IDLDictionary<T>> : DefaultConverter<IDLDictionary<T>> { + using ReturnType = T; + + static ReturnType convert(JSC::ExecState& state, JSC::JSValue value) + { + return convertDictionary<T>(state, value); + } +}; + +template<typename T> struct JSConverter<IDLDictionary<T>> { + static constexpr bool needsState = true; + static constexpr bool needsGlobalObject = true; + + static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject& globalObject, const T& dictionary) + { + return convertDictionaryToJS(state, globalObject, dictionary); + } +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertEnumeration.h b/Source/WebCore/bindings/js/JSDOMConvertEnumeration.h new file mode 100644 index 000000000..ec43133c2 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertEnumeration.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "IDLTypes.h" +#include "JSDOMConvertBase.h" + +namespace WebCore { + +// Specialized by generated code for IDL enumeration conversion. +template<typename T> std::optional<T> parseEnumeration(JSC::ExecState&, JSC::JSValue); +template<typename T> T convertEnumeration(JSC::ExecState&, JSC::JSValue); +template<typename T> const char* expectedEnumerationValues(); + +// Specialized by generated code for IDL enumeration conversion. +template<typename T> JSC::JSString* convertEnumerationToJS(JSC::ExecState&, T); + + +template<typename T> struct Converter<IDLEnumeration<T>> : DefaultConverter<IDLEnumeration<T>> { + static T convert(JSC::ExecState& state, JSC::JSValue value) + { + return convertEnumeration<T>(state, value); + } +}; + +template<typename T> struct JSConverter<IDLEnumeration<T>> { + static constexpr bool needsState = true; + static constexpr bool needsGlobalObject = false; + + static JSC::JSValue convert(JSC::ExecState& exec, T value) + { + return convertEnumerationToJS(exec, value); + } +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertEventListener.h b/Source/WebCore/bindings/js/JSDOMConvertEventListener.h new file mode 100644 index 000000000..e55f32c3c --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertEventListener.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "IDLTypes.h" +#include "JSDOMConvertBase.h" + +namespace WebCore { + +template<typename T> struct Converter<IDLEventListener<T>> : DefaultConverter<IDLEventListener<T>> { + using ReturnType = RefPtr<T>; + + static ReturnType convert(JSC::ExecState& state, JSC::JSValue value, JSC::JSObject& thisObject) + { + auto scope = DECLARE_THROW_SCOPE(state.vm()); + + auto listener = T::create(value, thisObject, false, currentWorld(&state)); + if (!listener) + throwTypeError(&state, scope); + + return listener; + } +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertIndexedDB.h b/Source/WebCore/bindings/js/JSDOMConvertIndexedDB.h new file mode 100644 index 000000000..78d7e3763 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertIndexedDB.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBBindingUtilities.h" +#include "IDLTypes.h" +#include "JSDOMConvertBase.h" + +namespace WebCore { + +template<> struct JSConverter<IDLIDBKey> { + static constexpr bool needsState = true; + static constexpr bool needsGlobalObject = true; + + template <typename U> + static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject& globalObject, U&& value) + { + return toJS(state, globalObject, std::forward<U>(value)); + } +}; + +template<> struct JSConverter<IDLIDBKeyData> { + static constexpr bool needsState = true; + static constexpr bool needsGlobalObject = true; + + template <typename U> + static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject& globalObject, U&& value) + { + return toJS(&state, &globalObject, std::forward<U>(value)); + } +}; + +template<> struct JSConverter<IDLIDBValue> { + static constexpr bool needsState = true; + static constexpr bool needsGlobalObject = true; + + template <typename U> + static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject& globalObject, U&& value) + { + return toJS(&state, &globalObject, std::forward<U>(value)); + } +}; + +} // namespace WebCore + +#endif diff --git a/Source/WebCore/bindings/js/JSDOMConvertInterface.h b/Source/WebCore/bindings/js/JSDOMConvertInterface.h new file mode 100644 index 000000000..6c0b5eefe --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertInterface.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "IDLTypes.h" +#include "JSDOMConvertBase.h" +#include "JSDOMExceptionHandling.h" + +namespace WebCore { + +template<typename ImplementationClass> struct JSDOMWrapperConverterTraits; + +template<typename T> struct Converter<IDLInterface<T>> : DefaultConverter<IDLInterface<T>> { + using ReturnType = typename JSDOMWrapperConverterTraits<T>::ToWrappedReturnType; + using WrapperType = typename JSDOMWrapperConverterTraits<T>::WrapperClass; + + template<typename ExceptionThrower = DefaultExceptionThrower> + static ReturnType convert(JSC::ExecState& state, JSC::JSValue value, ExceptionThrower&& exceptionThrower = ExceptionThrower()) + { + auto& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + ReturnType object = WrapperType::toWrapped(vm, value); + if (UNLIKELY(!object)) + exceptionThrower(state, scope); + return object; + } +}; + +namespace Detail { + +template <typename T> inline T* getPtrOrRef(const T* p) { return const_cast<T*>(p); } +template <typename T> inline T& getPtrOrRef(const T& p) { return const_cast<T&>(p); } +template <typename T> inline T* getPtrOrRef(const RefPtr<T>& p) { return p.get(); } +template <typename T> inline T& getPtrOrRef(const Ref<T>& p) { return p.get(); } + +} + +template<typename T> struct JSConverter<IDLInterface<T>> { + static constexpr bool needsState = true; + static constexpr bool needsGlobalObject = true; + + template <typename U> + static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject& globalObject, const U& value) + { + return toJS(&state, &globalObject, Detail::getPtrOrRef(value)); + } + + template<typename U> + static JSC::JSValue convertNewlyCreated(JSC::ExecState& state, JSDOMGlobalObject& globalObject, U&& value) + { + return toJSNewlyCreated(&state, &globalObject, std::forward<U>(value)); + } +}; + + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertJSON.h b/Source/WebCore/bindings/js/JSDOMConvertJSON.h new file mode 100644 index 000000000..2f1b4d2b4 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertJSON.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "IDLTypes.h" +#include "JSDOMConvertBase.h" +#include <runtime/JSONObject.h> + +namespace WebCore { + +template<> struct Converter<IDLJSON> : DefaultConverter<IDLJSON> { + static String convert(JSC::ExecState& state, JSC::JSValue value) + { + return JSC::JSONStringify(&state, value, 0); + } +}; + +template<> struct JSConverter<IDLJSON> { + static constexpr bool needsState = true; + static constexpr bool needsGlobalObject = false; + + static JSC::JSValue convert(JSC::ExecState& state, const String& value) + { + return JSC::JSONParse(&state, value); + } +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertNull.h b/Source/WebCore/bindings/js/JSDOMConvertNull.h new file mode 100644 index 000000000..262d75106 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertNull.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "IDLTypes.h" +#include "JSDOMConvertBase.h" + +namespace WebCore { + +template<> struct Converter<IDLNull> : DefaultConverter<IDLNull> { + static std::nullptr_t convert(JSC::ExecState&, JSC::JSValue) + { + return nullptr; + } +}; + +template<> struct JSConverter<IDLNull> { + static constexpr bool needsState = false; + static constexpr bool needsGlobalObject = false; + + static JSC::JSValue convert(std::nullptr_t) + { + return JSC::jsNull(); + } +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertNullable.h b/Source/WebCore/bindings/js/JSDOMConvertNullable.h new file mode 100644 index 000000000..c42c83150 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertNullable.h @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "IDLTypes.h" +#include "JSDOMConvertAny.h" +#include "JSDOMConvertInterface.h" +#include "JSDOMConvertNumbers.h" +#include "JSDOMConvertStrings.h" + +namespace WebCore { + +namespace Detail { + +template<typename IDLType> +struct NullableConversionType; + +template<typename IDLType> +struct NullableConversionType { + using Type = typename IDLNullable<IDLType>::ImplementationType; +}; + +template<typename T> +struct NullableConversionType<IDLInterface<T>> { + using Type = typename Converter<IDLInterface<T>>::ReturnType; +}; + +template<> +struct NullableConversionType<IDLAny> { + using Type = typename Converter<IDLAny>::ReturnType; +}; + +} + +template<typename T> struct Converter<IDLNullable<T>> : DefaultConverter<IDLNullable<T>> { + using ReturnType = typename Detail::NullableConversionType<T>::Type; + + // 1. If Type(V) is not Object, and the conversion to an IDL value is being performed + // due to V being assigned to an attribute whose type is a nullable callback function + // that is annotated with [TreatNonObjectAsNull], then return the IDL nullable type T? + // value null. + // + // NOTE: Handled elsewhere. + // + // 2. Otherwise, if V is null or undefined, then return the IDL nullable type T? value null. + // 3. Otherwise, return the result of converting V using the rules for the inner IDL type T. + + static ReturnType convert(JSC::ExecState& state, JSC::JSValue value) + { + if (value.isUndefinedOrNull()) + return T::nullValue(); + return Converter<T>::convert(state, value); + } + static ReturnType convert(JSC::ExecState& state, JSC::JSValue value, JSC::JSObject& thisObject) + { + if (value.isUndefinedOrNull()) + return T::nullValue(); + return Converter<T>::convert(state, value, thisObject); + } + static ReturnType convert(JSC::ExecState& state, JSC::JSValue value, JSDOMGlobalObject& globalObject) + { + if (value.isUndefinedOrNull()) + return T::nullValue(); + return Converter<T>::convert(state, value, globalObject); + } + static ReturnType convert(JSC::ExecState& state, JSC::JSValue value, IntegerConversionConfiguration configuration) + { + if (value.isUndefinedOrNull()) + return T::nullValue(); + return Converter<T>::convert(state, value, configuration); + } + static ReturnType convert(JSC::ExecState& state, JSC::JSValue value, StringConversionConfiguration configuration) + { + if (value.isUndefinedOrNull()) + return T::nullValue(); + return Converter<T>::convert(state, value, configuration); + } + template<typename ExceptionThrower = DefaultExceptionThrower> + static ReturnType convert(JSC::ExecState& state, JSC::JSValue value, ExceptionThrower&& exceptionThrower) + { + if (value.isUndefinedOrNull()) + return T::nullValue(); + return Converter<T>::convert(state, value, std::forward<ExceptionThrower>(exceptionThrower)); + } + template<typename ExceptionThrower = DefaultExceptionThrower> + static ReturnType convert(JSC::ExecState& state, JSC::JSValue value, JSC::JSObject& thisObject, ExceptionThrower&& exceptionThrower) + { + if (value.isUndefinedOrNull()) + return T::nullValue(); + return Converter<T>::convert(state, value, thisObject, std::forward<ExceptionThrower>(exceptionThrower)); + } + template<typename ExceptionThrower = DefaultExceptionThrower> + static ReturnType convert(JSC::ExecState& state, JSC::JSValue value, JSDOMGlobalObject& globalObject, ExceptionThrower&& exceptionThrower) + { + if (value.isUndefinedOrNull()) + return T::nullValue(); + return Converter<T>::convert(state, value, globalObject, std::forward<ExceptionThrower>(exceptionThrower)); + } +}; + +template<typename T> struct JSConverter<IDLNullable<T>> { + using ImplementationType = typename IDLNullable<T>::ImplementationType; + + static constexpr bool needsState = JSConverter<T>::needsState; + static constexpr bool needsGlobalObject = JSConverter<T>::needsGlobalObject; + + template<typename U> + static JSC::JSValue convert(U&& value) + { + if (T::isNullValue(value)) + return JSC::jsNull(); + return JSConverter<T>::convert(T::extractValueFromNullable(value)); + } + template<typename U> + static JSC::JSValue convert(JSC::ExecState& state, U&& value) + { + if (T::isNullValue(value)) + return JSC::jsNull(); + return JSConverter<T>::convert(state, T::extractValueFromNullable(value)); + } + template<typename U> + static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject& globalObject, U&& value) + { + if (T::isNullValue(value)) + return JSC::jsNull(); + return JSConverter<T>::convert(state, globalObject, T::extractValueFromNullable(value)); + } + + template<typename U> + static JSC::JSValue convertNewlyCreated(JSC::ExecState& state, JSDOMGlobalObject& globalObject, U&& value) + { + if (T::isNullValue(value)) + return JSC::jsNull(); + return JSConverter<T>::convert(state, globalObject, T::extractValueFromNullable(value)); + } +}; + + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertNumbers.cpp b/Source/WebCore/bindings/js/JSDOMConvertNumbers.cpp new file mode 100644 index 000000000..ff1f97011 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertNumbers.cpp @@ -0,0 +1,348 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2004-2011, 2013, 2016 Apple Inc. All rights reserved. + * Copyright (C) 2007 Samuel Weinig <sam@webkit.org> + * Copyright (C) 2013 Michael Pruett <michael@68k.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "JSDOMConvertNumbers.h" + +#include "JSDOMExceptionHandling.h" +#include <heap/HeapInlines.h> +#include <runtime/JSCJSValueInlines.h> +#include <wtf/MathExtras.h> +#include <wtf/text/WTFString.h> + +using namespace JSC; + +namespace WebCore { + +static const int32_t kMaxInt32 = 0x7fffffff; +static const int32_t kMinInt32 = -kMaxInt32 - 1; +static const uint32_t kMaxUInt32 = 0xffffffffU; +static const int64_t kJSMaxInteger = 0x20000000000000LL - 1; // 2^53 - 1, largest integer exactly representable in ECMAScript. + +static String rangeErrorString(double value, double min, double max) +{ + return makeString("Value ", String::numberToStringECMAScript(value), " is outside the range [", String::numberToStringECMAScript(min), ", ", String::numberToStringECMAScript(max), "]"); +} + +static double enforceRange(ExecState& state, double x, double minimum, double maximum) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (std::isnan(x) || std::isinf(x)) { + throwTypeError(&state, scope, rangeErrorString(x, minimum, maximum)); + return 0; + } + x = trunc(x); + if (x < minimum || x > maximum) { + throwTypeError(&state, scope, rangeErrorString(x, minimum, maximum)); + return 0; + } + return x; +} + +template <typename T> +struct IntTypeLimits { +}; + +template <> +struct IntTypeLimits<int8_t> { + static const int8_t minValue = -128; + static const int8_t maxValue = 127; + static const unsigned numberOfValues = 256; // 2^8 +}; + +template <> +struct IntTypeLimits<uint8_t> { + static const uint8_t maxValue = 255; + static const unsigned numberOfValues = 256; // 2^8 +}; + +template <> +struct IntTypeLimits<int16_t> { + static const short minValue = -32768; + static const short maxValue = 32767; + static const unsigned numberOfValues = 65536; // 2^16 +}; + +template <> +struct IntTypeLimits<uint16_t> { + static const unsigned short maxValue = 65535; + static const unsigned numberOfValues = 65536; // 2^16 +}; + +template <typename T> +static inline T toSmallerInt(ExecState& state, JSValue value, IntegerConversionConfiguration configuration) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + static_assert(std::is_signed<T>::value && std::is_integral<T>::value, "Should only be used for signed integral types"); + + typedef IntTypeLimits<T> LimitsTrait; + // Fast path if the value is already a 32-bit signed integer in the right range. + if (value.isInt32()) { + int32_t d = value.asInt32(); + if (d >= LimitsTrait::minValue && d <= LimitsTrait::maxValue) + return static_cast<T>(d); + switch (configuration) { + case IntegerConversionConfiguration::Normal: + break; + case IntegerConversionConfiguration::EnforceRange: + throwTypeError(&state, scope); + return 0; + case IntegerConversionConfiguration::Clamp: + return d < LimitsTrait::minValue ? LimitsTrait::minValue : LimitsTrait::maxValue; + } + d %= LimitsTrait::numberOfValues; + return static_cast<T>(d > LimitsTrait::maxValue ? d - LimitsTrait::numberOfValues : d); + } + + double x = value.toNumber(&state); + RETURN_IF_EXCEPTION(scope, 0); + + switch (configuration) { + case IntegerConversionConfiguration::Normal: + break; + case IntegerConversionConfiguration::EnforceRange: + return enforceRange(state, x, LimitsTrait::minValue, LimitsTrait::maxValue); + case IntegerConversionConfiguration::Clamp: + return std::isnan(x) ? 0 : clampTo<T>(x); + } + + if (std::isnan(x) || std::isinf(x) || !x) + return 0; + + x = x < 0 ? -floor(fabs(x)) : floor(fabs(x)); + x = fmod(x, LimitsTrait::numberOfValues); + + return static_cast<T>(x > LimitsTrait::maxValue ? x - LimitsTrait::numberOfValues : x); +} + +template <typename T> +static inline T toSmallerUInt(ExecState& state, JSValue value, IntegerConversionConfiguration configuration) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + static_assert(std::is_unsigned<T>::value && std::is_integral<T>::value, "Should only be used for unsigned integral types"); + + typedef IntTypeLimits<T> LimitsTrait; + // Fast path if the value is already a 32-bit unsigned integer in the right range. + if (value.isUInt32()) { + uint32_t d = value.asUInt32(); + if (d <= LimitsTrait::maxValue) + return static_cast<T>(d); + switch (configuration) { + case IntegerConversionConfiguration::Normal: + return static_cast<T>(d); + case IntegerConversionConfiguration::EnforceRange: + throwTypeError(&state, scope); + return 0; + case IntegerConversionConfiguration::Clamp: + return LimitsTrait::maxValue; + } + } + + double x = value.toNumber(&state); + RETURN_IF_EXCEPTION(scope, 0); + + switch (configuration) { + case IntegerConversionConfiguration::Normal: + break; + case IntegerConversionConfiguration::EnforceRange: + return enforceRange(state, x, 0, LimitsTrait::maxValue); + case IntegerConversionConfiguration::Clamp: + return std::isnan(x) ? 0 : clampTo<T>(x); + } + + if (std::isnan(x) || std::isinf(x) || !x) + return 0; + + x = x < 0 ? -floor(fabs(x)) : floor(fabs(x)); + return static_cast<T>(fmod(x, LimitsTrait::numberOfValues)); +} + +int8_t toInt8EnforceRange(JSC::ExecState& state, JSValue value) +{ + return toSmallerInt<int8_t>(state, value, IntegerConversionConfiguration::EnforceRange); +} + +uint8_t toUInt8EnforceRange(JSC::ExecState& state, JSValue value) +{ + return toSmallerUInt<uint8_t>(state, value, IntegerConversionConfiguration::EnforceRange); +} + +int8_t toInt8Clamp(JSC::ExecState& state, JSValue value) +{ + return toSmallerInt<int8_t>(state, value, IntegerConversionConfiguration::Clamp); +} + +uint8_t toUInt8Clamp(JSC::ExecState& state, JSValue value) +{ + return toSmallerUInt<uint8_t>(state, value, IntegerConversionConfiguration::Clamp); +} + +// http://www.w3.org/TR/WebIDL/#es-byte +int8_t toInt8(ExecState& state, JSValue value) +{ + return toSmallerInt<int8_t>(state, value, IntegerConversionConfiguration::Normal); +} + +// http://www.w3.org/TR/WebIDL/#es-octet +uint8_t toUInt8(ExecState& state, JSValue value) +{ + return toSmallerUInt<uint8_t>(state, value, IntegerConversionConfiguration::Normal); +} + +int16_t toInt16EnforceRange(ExecState& state, JSValue value) +{ + return toSmallerInt<int16_t>(state, value, IntegerConversionConfiguration::EnforceRange); +} + +uint16_t toUInt16EnforceRange(ExecState& state, JSValue value) +{ + return toSmallerUInt<uint16_t>(state, value, IntegerConversionConfiguration::EnforceRange); +} + +int16_t toInt16Clamp(ExecState& state, JSValue value) +{ + return toSmallerInt<int16_t>(state, value, IntegerConversionConfiguration::Clamp); +} + +uint16_t toUInt16Clamp(ExecState& state, JSValue value) +{ + return toSmallerUInt<uint16_t>(state, value, IntegerConversionConfiguration::Clamp); +} + +// http://www.w3.org/TR/WebIDL/#es-short +int16_t toInt16(ExecState& state, JSValue value) +{ + return toSmallerInt<int16_t>(state, value, IntegerConversionConfiguration::Normal); +} + +// http://www.w3.org/TR/WebIDL/#es-unsigned-short +uint16_t toUInt16(ExecState& state, JSValue value) +{ + return toSmallerUInt<uint16_t>(state, value, IntegerConversionConfiguration::Normal); +} + +// http://www.w3.org/TR/WebIDL/#es-long +int32_t toInt32EnforceRange(ExecState& state, JSValue value) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (value.isInt32()) + return value.asInt32(); + + double x = value.toNumber(&state); + RETURN_IF_EXCEPTION(scope, 0); + return enforceRange(state, x, kMinInt32, kMaxInt32); +} + +int32_t toInt32Clamp(ExecState& state, JSValue value) +{ + if (value.isInt32()) + return value.asInt32(); + + double x = value.toNumber(&state); + return std::isnan(x) ? 0 : clampTo<int32_t>(x); +} + +uint32_t toUInt32Clamp(ExecState& state, JSValue value) +{ + if (value.isUInt32()) + return value.asUInt32(); + + double x = value.toNumber(&state); + return std::isnan(x) ? 0 : clampTo<uint32_t>(x); +} + +// http://www.w3.org/TR/WebIDL/#es-unsigned-long +uint32_t toUInt32EnforceRange(ExecState& state, JSValue value) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (value.isUInt32()) + return value.asUInt32(); + + double x = value.toNumber(&state); + RETURN_IF_EXCEPTION(scope, 0); + return enforceRange(state, x, 0, kMaxUInt32); +} + +int64_t toInt64EnforceRange(ExecState& state, JSC::JSValue value) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + double x = value.toNumber(&state); + RETURN_IF_EXCEPTION(scope, 0); + return enforceRange(state, x, -kJSMaxInteger, kJSMaxInteger); +} + +uint64_t toUInt64EnforceRange(ExecState& state, JSC::JSValue value) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + double x = value.toNumber(&state); + RETURN_IF_EXCEPTION(scope, 0); + return enforceRange(state, x, 0, kJSMaxInteger); +} + +int64_t toInt64Clamp(ExecState& state, JSC::JSValue value) +{ + double x = value.toNumber(&state); + return std::isnan(x) ? 0 : static_cast<int64_t>(std::min<double>(std::max<double>(x, -kJSMaxInteger), kJSMaxInteger)); +} + +uint64_t toUInt64Clamp(ExecState& state, JSC::JSValue value) +{ + double x = value.toNumber(&state); + return std::isnan(x) ? 0 : static_cast<uint64_t>(std::min<double>(std::max<double>(x, 0), kJSMaxInteger)); +} + +// http://www.w3.org/TR/WebIDL/#es-long-long +int64_t toInt64(ExecState& state, JSValue value) +{ + double x = value.toNumber(&state); + + // Map NaNs and +/-Infinity to 0; convert finite values modulo 2^64. + unsigned long long n; + doubleToInteger(x, n); + return n; +} + +// http://www.w3.org/TR/WebIDL/#es-unsigned-long-long +uint64_t toUInt64(ExecState& state, JSValue value) +{ + double x = value.toNumber(&state); + + // Map NaNs and +/-Infinity to 0; convert finite values modulo 2^64. + unsigned long long n; + doubleToInteger(x, n); + return n; +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertNumbers.h b/Source/WebCore/bindings/js/JSDOMConvertNumbers.h new file mode 100644 index 000000000..b79ed05eb --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertNumbers.h @@ -0,0 +1,424 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "IDLTypes.h" +#include "JSDOMConvertBase.h" +#include "JSDOMExceptionHandling.h" +#include <runtime/JSCJSValueInlines.h> + +namespace WebCore { + +enum class IntegerConversionConfiguration { Normal, EnforceRange, Clamp }; + +template<typename T> typename Converter<T>::ReturnType convert(JSC::ExecState&, JSC::JSValue, IntegerConversionConfiguration); + +template<typename T> inline typename Converter<T>::ReturnType convert(JSC::ExecState& state, JSC::JSValue value, IntegerConversionConfiguration configuration) +{ + return Converter<T>::convert(state, value, configuration); +} + +// The following functions convert values to integers as per the WebIDL specification. +// The conversion fails if the value cannot be converted to a number or, if EnforceRange is specified, +// the value is outside the range of the destination integer type. + +WEBCORE_EXPORT int8_t toInt8EnforceRange(JSC::ExecState&, JSC::JSValue); +WEBCORE_EXPORT uint8_t toUInt8EnforceRange(JSC::ExecState&, JSC::JSValue); +WEBCORE_EXPORT int16_t toInt16EnforceRange(JSC::ExecState&, JSC::JSValue); +WEBCORE_EXPORT uint16_t toUInt16EnforceRange(JSC::ExecState&, JSC::JSValue); +WEBCORE_EXPORT int32_t toInt32EnforceRange(JSC::ExecState&, JSC::JSValue); +WEBCORE_EXPORT uint32_t toUInt32EnforceRange(JSC::ExecState&, JSC::JSValue); +WEBCORE_EXPORT int64_t toInt64EnforceRange(JSC::ExecState&, JSC::JSValue); +WEBCORE_EXPORT uint64_t toUInt64EnforceRange(JSC::ExecState&, JSC::JSValue); + +WEBCORE_EXPORT int8_t toInt8Clamp(JSC::ExecState&, JSC::JSValue); +WEBCORE_EXPORT uint8_t toUInt8Clamp(JSC::ExecState&, JSC::JSValue); +WEBCORE_EXPORT int16_t toInt16Clamp(JSC::ExecState&, JSC::JSValue); +WEBCORE_EXPORT uint16_t toUInt16Clamp(JSC::ExecState&, JSC::JSValue); +WEBCORE_EXPORT int32_t toInt32Clamp(JSC::ExecState&, JSC::JSValue); +WEBCORE_EXPORT uint32_t toUInt32Clamp(JSC::ExecState&, JSC::JSValue); +WEBCORE_EXPORT int64_t toInt64Clamp(JSC::ExecState&, JSC::JSValue); +WEBCORE_EXPORT uint64_t toUInt64Clamp(JSC::ExecState&, JSC::JSValue); + +WEBCORE_EXPORT int8_t toInt8(JSC::ExecState&, JSC::JSValue); +WEBCORE_EXPORT uint8_t toUInt8(JSC::ExecState&, JSC::JSValue); +WEBCORE_EXPORT int16_t toInt16(JSC::ExecState&, JSC::JSValue); +WEBCORE_EXPORT uint16_t toUInt16(JSC::ExecState&, JSC::JSValue); +WEBCORE_EXPORT int64_t toInt64(JSC::ExecState&, JSC::JSValue); +WEBCORE_EXPORT uint64_t toUInt64(JSC::ExecState&, JSC::JSValue); + + +// MARK: - +// MARK: Integer types + +template<> struct Converter<IDLByte> : DefaultConverter<IDLByte> { + static int8_t convert(JSC::ExecState& state, JSC::JSValue value, IntegerConversionConfiguration configuration = IntegerConversionConfiguration::Normal) + { + switch (configuration) { + case IntegerConversionConfiguration::Normal: + break; + case IntegerConversionConfiguration::EnforceRange: + return toInt8EnforceRange(state, value); + case IntegerConversionConfiguration::Clamp: + return toInt8Clamp(state, value); + } + return toInt8(state, value); + } +}; + +template<> struct JSConverter<IDLByte> { + using Type = typename IDLByte::ImplementationType; + + static constexpr bool needsState = false; + static constexpr bool needsGlobalObject = false; + + static JSC::JSValue convert(Type value) + { + return JSC::jsNumber(value); + } +}; + +template<> struct Converter<IDLOctet> : DefaultConverter<IDLOctet> { + static uint8_t convert(JSC::ExecState& state, JSC::JSValue value, IntegerConversionConfiguration configuration = IntegerConversionConfiguration::Normal) + { + switch (configuration) { + case IntegerConversionConfiguration::Normal: + break; + case IntegerConversionConfiguration::EnforceRange: + return toUInt8EnforceRange(state, value); + case IntegerConversionConfiguration::Clamp: + return toUInt8Clamp(state, value); + } + return toUInt8(state, value); + } +}; + +template<> struct JSConverter<IDLOctet> { + using Type = typename IDLOctet::ImplementationType; + + static constexpr bool needsState = false; + static constexpr bool needsGlobalObject = false; + + static JSC::JSValue convert(Type value) + { + return JSC::jsNumber(value); + } +}; + +template<> struct Converter<IDLShort> : DefaultConverter<IDLShort> { + static int16_t convert(JSC::ExecState& state, JSC::JSValue value, IntegerConversionConfiguration configuration = IntegerConversionConfiguration::Normal) + { + switch (configuration) { + case IntegerConversionConfiguration::Normal: + break; + case IntegerConversionConfiguration::EnforceRange: + return toInt16EnforceRange(state, value); + case IntegerConversionConfiguration::Clamp: + return toInt16Clamp(state, value); + } + return toInt16(state, value); + } +}; + +template<> struct JSConverter<IDLShort> { + using Type = typename IDLShort::ImplementationType; + + static constexpr bool needsState = false; + static constexpr bool needsGlobalObject = false; + + static JSC::JSValue convert(Type value) + { + return JSC::jsNumber(value); + } +}; + +template<> struct Converter<IDLUnsignedShort> : DefaultConverter<IDLUnsignedShort> { + static uint16_t convert(JSC::ExecState& state, JSC::JSValue value, IntegerConversionConfiguration configuration = IntegerConversionConfiguration::Normal) + { + switch (configuration) { + case IntegerConversionConfiguration::Normal: + break; + case IntegerConversionConfiguration::EnforceRange: + return toUInt16EnforceRange(state, value); + case IntegerConversionConfiguration::Clamp: + return toUInt16Clamp(state, value); + } + return toUInt16(state, value); + } +}; + +template<> struct JSConverter<IDLUnsignedShort> { + using Type = typename IDLUnsignedShort::ImplementationType; + + static constexpr bool needsState = false; + static constexpr bool needsGlobalObject = false; + + static JSC::JSValue convert(Type value) + { + return JSC::jsNumber(value); + } +}; + +template<> struct Converter<IDLLong> : DefaultConverter<IDLLong> { + static inline int32_t convert(JSC::ExecState&, JSC::ThrowScope&, double number) + { + return JSC::toInt32(number); + } + + static int32_t convert(JSC::ExecState& state, JSC::JSValue value, IntegerConversionConfiguration configuration = IntegerConversionConfiguration::Normal) + { + switch (configuration) { + case IntegerConversionConfiguration::Normal: + break; + case IntegerConversionConfiguration::EnforceRange: + return toInt32EnforceRange(state, value); + case IntegerConversionConfiguration::Clamp: + return toInt32Clamp(state, value); + } + return value.toInt32(&state); + } +}; + +template<> struct JSConverter<IDLLong> { + using Type = typename IDLLong::ImplementationType; + + static constexpr bool needsState = false; + static constexpr bool needsGlobalObject = false; + + static JSC::JSValue convert(Type value) + { + return JSC::jsNumber(value); + } +}; + +template<> struct Converter<IDLUnsignedLong> : DefaultConverter<IDLUnsignedLong> { + static uint32_t convert(JSC::ExecState& state, JSC::JSValue value, IntegerConversionConfiguration configuration = IntegerConversionConfiguration::Normal) + { + switch (configuration) { + case IntegerConversionConfiguration::Normal: + break; + case IntegerConversionConfiguration::EnforceRange: + return toUInt32EnforceRange(state, value); + case IntegerConversionConfiguration::Clamp: + return toUInt32Clamp(state, value); + } + return value.toUInt32(&state); + } +}; + +template<> struct JSConverter<IDLUnsignedLong> { + using Type = typename IDLUnsignedLong::ImplementationType; + + static constexpr bool needsState = false; + static constexpr bool needsGlobalObject = false; + + static JSC::JSValue convert(Type value) + { + return JSC::jsNumber(value); + } +}; + +template<> struct Converter<IDLLongLong> : DefaultConverter<IDLLongLong> { + static int64_t convert(JSC::ExecState& state, JSC::JSValue value, IntegerConversionConfiguration configuration = IntegerConversionConfiguration::Normal) + { + if (value.isInt32()) + return value.asInt32(); + + switch (configuration) { + case IntegerConversionConfiguration::Normal: + break; + case IntegerConversionConfiguration::EnforceRange: + return toInt64EnforceRange(state, value); + case IntegerConversionConfiguration::Clamp: + return toInt64Clamp(state, value); + } + return toInt64(state, value); + } +}; + +template<> struct JSConverter<IDLLongLong> { + using Type = typename IDLLongLong::ImplementationType; + + static constexpr bool needsState = false; + static constexpr bool needsGlobalObject = false; + + static JSC::JSValue convert(Type value) + { + return JSC::jsNumber(value); + } +}; + +template<> struct Converter<IDLUnsignedLongLong> : DefaultConverter<IDLUnsignedLongLong> { + static uint64_t convert(JSC::ExecState& state, JSC::JSValue value, IntegerConversionConfiguration configuration = IntegerConversionConfiguration::Normal) + { + if (value.isUInt32()) + return value.asUInt32(); + + switch (configuration) { + case IntegerConversionConfiguration::Normal: + break; + case IntegerConversionConfiguration::EnforceRange: + return toUInt64EnforceRange(state, value); + case IntegerConversionConfiguration::Clamp: + return toUInt64Clamp(state, value); + } + return toUInt64(state, value); + } +}; + +template<> struct JSConverter<IDLUnsignedLongLong> { + using Type = typename IDLUnsignedLongLong::ImplementationType; + + static constexpr bool needsState = false; + static constexpr bool needsGlobalObject = false; + + static JSC::JSValue convert(Type value) + { + return JSC::jsNumber(value); + } +}; + +// MARK: - +// MARK: Floating point types + +template<> struct Converter<IDLFloat> : DefaultConverter<IDLFloat> { + + static inline float convert(JSC::ExecState& state, JSC::ThrowScope& scope, double number) + { + if (UNLIKELY(!std::isfinite(number))) + throwNonFiniteTypeError(state, scope); + return static_cast<float>(number); + } + + static float convert(JSC::ExecState& state, JSC::JSValue value) + { + JSC::VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + double number = value.toNumber(&state); + if (UNLIKELY(!std::isfinite(number))) + throwNonFiniteTypeError(state, scope); + return static_cast<float>(number); + } +}; + +template<> struct JSConverter<IDLFloat> { + using Type = typename IDLFloat::ImplementationType; + + static constexpr bool needsState = false; + static constexpr bool needsGlobalObject = false; + + static JSC::JSValue convert(Type value) + { + return JSC::jsNumber(value); + } +}; + +template<> struct Converter<IDLUnrestrictedFloat> : DefaultConverter<IDLUnrestrictedFloat> { + static inline float convert(JSC::ExecState&, JSC::ThrowScope&, double number) + { + return static_cast<float>(number); + } + + static float convert(JSC::ExecState& state, JSC::JSValue value) + { + return static_cast<float>(value.toNumber(&state)); + } +}; + +template<> struct JSConverter<IDLUnrestrictedFloat> { + using Type = typename IDLUnrestrictedFloat::ImplementationType; + + static constexpr bool needsState = false; + static constexpr bool needsGlobalObject = false; + + static JSC::JSValue convert(Type value) + { + return JSC::jsNumber(value); + } +}; + +template<> struct Converter<IDLDouble> : DefaultConverter<IDLDouble> { + static inline double convert(JSC::ExecState& state, JSC::ThrowScope& scope, double number) + { + if (UNLIKELY(!std::isfinite(number))) + throwNonFiniteTypeError(state, scope); + return number; + } + + static double convert(JSC::ExecState& state, JSC::JSValue value) + { + JSC::VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + double number = value.toNumber(&state); + if (UNLIKELY(!std::isfinite(number))) + throwNonFiniteTypeError(state, scope); + return number; + } +}; + +template<> struct JSConverter<IDLDouble> { + using Type = typename IDLDouble::ImplementationType; + + static constexpr bool needsState = false; + static constexpr bool needsGlobalObject = false; + + static JSC::JSValue convert(Type value) + { + return JSC::jsNumber(value); + } +}; + +template<> struct Converter<IDLUnrestrictedDouble> : DefaultConverter<IDLUnrestrictedDouble> { + static inline double convert(JSC::ExecState&, JSC::ThrowScope&, double number) + { + return number; + } + + static double convert(JSC::ExecState& state, JSC::JSValue value) + { + return value.toNumber(&state); + } +}; + +template<> struct JSConverter<IDLUnrestrictedDouble> { + using Type = typename IDLUnrestrictedDouble::ImplementationType; + + static constexpr bool needsState = false; + static constexpr bool needsGlobalObject = false; + + static JSC::JSValue convert(Type value) + { + return JSC::jsNumber(value); + } + + // Add overload for MediaTime. + static JSC::JSValue convert(MediaTime value) + { + return JSC::jsNumber(value.toDouble()); + } +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertObject.h b/Source/WebCore/bindings/js/JSDOMConvertObject.h new file mode 100644 index 000000000..379eb42b8 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertObject.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "IDLTypes.h" +#include "JSDOMConvertBase.h" + +namespace WebCore { + +template<> struct Converter<IDLObject> : DefaultConverter<IDLObject> { + template<typename ExceptionThrower = DefaultExceptionThrower> + static JSC::Strong<JSC::JSObject> convert(JSC::ExecState& state, JSC::JSValue value, ExceptionThrower&& exceptionThrower = ExceptionThrower()) + { + JSC::VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (!value.isObject()) { + exceptionThrower(state, scope); + return { }; + } + + return { vm, JSC::asObject(value) }; + } +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertRecord.h b/Source/WebCore/bindings/js/JSDOMConvertRecord.h new file mode 100644 index 000000000..db1dabf8d --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertRecord.h @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "IDLTypes.h" +#include "JSDOMConvertStrings.h" +#include <runtime/ObjectConstructor.h> + +namespace WebCore { + +namespace Detail { + +template<typename IDLStringType> +struct IdentifierConverter; + +template<> struct IdentifierConverter<IDLDOMString> { + static String convert(JSC::ExecState&, const JSC::Identifier& identifier) + { + return identifier.string(); + } +}; + +template<> struct IdentifierConverter<IDLByteString> { + static String convert(JSC::ExecState& state, const JSC::Identifier& identifier) + { + return identifierToByteString(state, identifier); + } +}; + +template<> struct IdentifierConverter<IDLUSVString> { + static String convert(JSC::ExecState& state, const JSC::Identifier& identifier) + { + return identifierToUSVString(state, identifier); + } +}; + +} + +template<typename K, typename V> struct Converter<IDLRecord<K, V>> : DefaultConverter<IDLRecord<K, V>> { + using ReturnType = typename IDLRecord<K, V>::ImplementationType; + using KeyType = typename K::ImplementationType; + using ValueType = typename V::ImplementationType; + + static ReturnType convert(JSC::ExecState& state, JSC::JSValue value) + { + auto& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + // 1. Let result be a new empty instance of record<K, V>. + // 2. If Type(O) is Undefined or Null, return result. + if (value.isUndefinedOrNull()) + return { }; + + // 3. If Type(O) is not Object, throw a TypeError. + if (!value.isObject()) { + throwTypeError(&state, scope); + return { }; + } + + JSC::JSObject* object = JSC::asObject(value); + + ReturnType result; + + // 4. Let keys be ? O.[[OwnPropertyKeys]](). + JSC::PropertyNameArray keys(&vm, JSC::PropertyNameMode::Strings); + object->getOwnPropertyNames(object, &state, keys, JSC::EnumerationMode()); + RETURN_IF_EXCEPTION(scope, { }); + + // 5. Repeat, for each element key of keys in List order: + for (auto& key : keys) { + // 1. Let desc be ? O.[[GetOwnProperty]](key). + JSC::PropertyDescriptor descriptor; + bool didGetDescriptor = object->getOwnPropertyDescriptor(&state, key, descriptor); + RETURN_IF_EXCEPTION(scope, { }); + + if (!didGetDescriptor) + continue; + + // 2. If desc is not undefined and desc.[[Enumerable]] is true: + + // FIXME: Do we need to check for enumerable / undefined, or is this handled by the default + // enumeration mode? + + if (!descriptor.value().isUndefined() && descriptor.enumerable()) { + // 1. Let typedKey be key converted to an IDL value of type K. + auto typedKey = Detail::IdentifierConverter<K>::convert(state, key); + + // 2. Let value be ? Get(O, key). + auto subValue = object->get(&state, key); + RETURN_IF_EXCEPTION(scope, { }); + + // 3. Let typedValue be value converted to an IDL value of type V. + auto typedValue = Converter<V>::convert(state, subValue); + RETURN_IF_EXCEPTION(scope, { }); + + // 4. If typedKey is already a key in result, set its value to typedValue. + // Note: This can happen when O is a proxy object. + // FIXME: Handle this case. + + // 5. Otherwise, append to result a mapping (typedKey, typedValue). + result.append({ typedKey, typedValue }); + } + } + + // 6. Return result. + return result; + } +}; + +template<typename K, typename V> struct JSConverter<IDLRecord<K, V>> { + static constexpr bool needsState = true; + static constexpr bool needsGlobalObject = true; + + template<typename MapType> + static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject& globalObject, const MapType& map) + { + auto& vm = state.vm(); + + // 1. Let result be ! ObjectCreate(%ObjectPrototype%). + auto result = constructEmptyObject(&state); + + // 2. Repeat, for each mapping (key, value) in D: + for (const auto& keyValuePair : map) { + // 1. Let esKey be key converted to an ECMAScript value. + // Note, this step is not required, as we need the key to be + // an Identifier, not a JSValue. + + // 2. Let esValue be value converted to an ECMAScript value. + auto esValue = toJS<V>(state, globalObject, keyValuePair.value); + + // 3. Let created be ! CreateDataProperty(result, esKey, esValue). + bool created = result->putDirect(vm, JSC::Identifier::fromString(&vm, keyValuePair.key), esValue); + + // 4. Assert: created is true. + ASSERT_UNUSED(created, created); + } + + // 3. Return result. + return result; + } +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertSequences.h b/Source/WebCore/bindings/js/JSDOMConvertSequences.h new file mode 100644 index 000000000..f42f45992 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertSequences.h @@ -0,0 +1,317 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "IDLTypes.h" +#include "JSDOMConvertBase.h" +#include <runtime/IteratorOperations.h> +#include <runtime/JSArray.h> +#include <runtime/JSGlobalObjectInlines.h> + +namespace WebCore { + +namespace Detail { + +template<typename IDLType> +struct GenericSequenceConverter { + using ReturnType = Vector<typename IDLType::ImplementationType>; + + static ReturnType convert(JSC::ExecState& state, JSC::JSObject* jsObject) + { + ReturnType result; + forEachInIterable(&state, jsObject, [&result](JSC::VM& vm, JSC::ExecState* state, JSC::JSValue jsValue) { + auto scope = DECLARE_THROW_SCOPE(vm); + + auto convertedValue = Converter<IDLType>::convert(*state, jsValue); + if (UNLIKELY(scope.exception())) + return; + result.append(WTFMove(convertedValue)); + }); + return result; + } +}; + +// Specialization for numeric types +// FIXME: This is only implemented for the IDLFloatingPointTypes and IDLLong. To add +// support for more numeric types, add an overload of Converter<IDLType>::convert that +// takes an ExecState, ThrowScope, double as its arguments. +template<typename IDLType> +struct NumericSequenceConverter { + using GenericConverter = GenericSequenceConverter<IDLType>; + using ReturnType = typename GenericConverter::ReturnType; + + static ReturnType convert(JSC::ExecState& state, JSC::JSValue value) + { + auto& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (!value.isObject()) { + throwSequenceTypeError(state, scope); + return { }; + } + + JSC::JSObject* object = JSC::asObject(value); + if (!JSC::isJSArray(object)) + return GenericConverter::convert(state, object); + + JSC::JSArray* array = JSC::asArray(object); + if (!array->globalObject()->isArrayIteratorProtocolFastAndNonObservable()) + return GenericConverter::convert(state, object); + + unsigned length = array->length(); + + ReturnType result; + if (!result.tryReserveCapacity(length)) { + // FIXME: Is the right exception to throw? + throwTypeError(&state, scope); + return { }; + } + + JSC::IndexingType indexingType = array->indexingType() & JSC::IndexingShapeMask; + + if (indexingType == JSC::ContiguousShape) { + for (unsigned i = 0; i < length; i++) { + auto indexValue = array->butterfly()->contiguous()[i].get(); + if (!indexValue) + result.uncheckedAppend(0); + else { + auto convertedValue = Converter<IDLType>::convert(state, indexValue); + RETURN_IF_EXCEPTION(scope, { }); + + result.uncheckedAppend(convertedValue); + } + } + return result; + } + + if (indexingType == JSC::Int32Shape) { + for (unsigned i = 0; i < length; i++) { + auto indexValue = array->butterfly()->contiguousInt32()[i].get(); + ASSERT(!indexValue || indexValue.isInt32()); + if (!indexValue) + result.uncheckedAppend(0); + else + result.uncheckedAppend(indexValue.asInt32()); + } + return result; + } + + if (indexingType == JSC::DoubleShape) { + for (unsigned i = 0; i < length; i++) { + auto doubleValue = array->butterfly()->contiguousDouble()[i]; + if (std::isnan(doubleValue)) + result.uncheckedAppend(0); + else { + auto convertedValue = Converter<IDLType>::convert(state, scope, doubleValue); + RETURN_IF_EXCEPTION(scope, { }); + + result.uncheckedAppend(convertedValue); + } + } + return result; + } + + for (unsigned i = 0; i < length; i++) { + auto indexValue = array->getDirectIndex(&state, i); + RETURN_IF_EXCEPTION(scope, { }); + + if (!indexValue) + result.uncheckedAppend(0); + else { + auto convertedValue = Converter<IDLType>::convert(state, indexValue); + RETURN_IF_EXCEPTION(scope, { }); + + result.uncheckedAppend(convertedValue); + } + } + return result; + } +}; + +template<typename IDLType> +struct SequenceConverter { + using GenericConverter = GenericSequenceConverter<IDLType>; + using ReturnType = typename GenericConverter::ReturnType; + + static ReturnType convert(JSC::ExecState& state, JSC::JSValue value) + { + auto& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (!value.isObject()) { + throwSequenceTypeError(state, scope); + return { }; + } + + JSC::JSObject* object = JSC::asObject(value); + if (!JSC::isJSArray(object)) + return GenericConverter::convert(state, object); + + JSC::JSArray* array = JSC::asArray(object); + if (!array->globalObject()->isArrayIteratorProtocolFastAndNonObservable()) + return GenericConverter::convert(state, object); + + unsigned length = array->length(); + + ReturnType result; + if (!result.tryReserveCapacity(length)) { + // FIXME: Is the right exception to throw? + throwTypeError(&state, scope); + return { }; + } + + JSC::IndexingType indexingType = array->indexingType() & JSC::IndexingShapeMask; + + if (indexingType == JSC::ContiguousShape) { + for (unsigned i = 0; i < length; i++) { + auto indexValue = array->butterfly()->contiguous()[i].get(); + if (!indexValue) + indexValue = JSC::jsUndefined(); + + auto convertedValue = Converter<IDLType>::convert(state, indexValue); + RETURN_IF_EXCEPTION(scope, { }); + + result.uncheckedAppend(convertedValue); + } + return result; + } + + for (unsigned i = 0; i < length; i++) { + auto indexValue = array->getDirectIndex(&state, i); + RETURN_IF_EXCEPTION(scope, { }); + + if (!indexValue) + indexValue = JSC::jsUndefined(); + + auto convertedValue = Converter<IDLType>::convert(state, indexValue); + RETURN_IF_EXCEPTION(scope, { }); + + result.uncheckedAppend(convertedValue); + } + return result; + } +}; + +template<> +struct SequenceConverter<IDLLong> { + using ReturnType = typename GenericSequenceConverter<IDLLong>::ReturnType; + + static ReturnType convert(JSC::ExecState& state, JSC::JSValue value) + { + return NumericSequenceConverter<IDLLong>::convert(state, value); + } +}; + +template<> +struct SequenceConverter<IDLFloat> { + using ReturnType = typename GenericSequenceConverter<IDLFloat>::ReturnType; + + static ReturnType convert(JSC::ExecState& state, JSC::JSValue value) + { + return NumericSequenceConverter<IDLFloat>::convert(state, value); + } +}; + +template<> +struct SequenceConverter<IDLUnrestrictedFloat> { + using ReturnType = typename GenericSequenceConverter<IDLUnrestrictedFloat>::ReturnType; + + static ReturnType convert(JSC::ExecState& state, JSC::JSValue value) + { + return NumericSequenceConverter<IDLUnrestrictedFloat>::convert(state, value); + } +}; + +template<> +struct SequenceConverter<IDLDouble> { + using ReturnType = typename GenericSequenceConverter<IDLDouble>::ReturnType; + + static ReturnType convert(JSC::ExecState& state, JSC::JSValue value) + { + return NumericSequenceConverter<IDLDouble>::convert(state, value); + } +}; + +template<> +struct SequenceConverter<IDLUnrestrictedDouble> { + using ReturnType = typename GenericSequenceConverter<IDLUnrestrictedDouble>::ReturnType; + + static ReturnType convert(JSC::ExecState& state, JSC::JSValue value) + { + return NumericSequenceConverter<IDLUnrestrictedDouble>::convert(state, value); + } +}; + +} + +template<typename T> struct Converter<IDLSequence<T>> : DefaultConverter<IDLSequence<T>> { + using ReturnType = typename Detail::SequenceConverter<T>::ReturnType; + + static ReturnType convert(JSC::ExecState& state, JSC::JSValue value) + { + return Detail::SequenceConverter<T>::convert(state, value); + } +}; + +template<typename T> struct JSConverter<IDLSequence<T>> { + static constexpr bool needsState = true; + static constexpr bool needsGlobalObject = true; + + template<typename U, size_t inlineCapacity> + static JSC::JSValue convert(JSC::ExecState& exec, JSDOMGlobalObject& globalObject, const Vector<U, inlineCapacity>& vector) + { + JSC::MarkedArgumentBuffer list; + for (auto& element : vector) + list.append(toJS<T>(exec, globalObject, element)); + return JSC::constructArray(&exec, nullptr, &globalObject, list); + } +}; + +template<typename T> struct Converter<IDLFrozenArray<T>> : DefaultConverter<IDLFrozenArray<T>> { + using ReturnType = typename Detail::SequenceConverter<T>::ReturnType; + + static ReturnType convert(JSC::ExecState& state, JSC::JSValue value) + { + return Detail::SequenceConverter<T>::convert(state, value); + } +}; + +template<typename T> struct JSConverter<IDLFrozenArray<T>> { + static constexpr bool needsState = true; + static constexpr bool needsGlobalObject = true; + + template<typename U, size_t inlineCapacity> + static JSC::JSValue convert(JSC::ExecState& exec, JSDOMGlobalObject& globalObject, const Vector<U, inlineCapacity>& vector) + { + JSC::MarkedArgumentBuffer list; + for (auto& element : vector) + list.append(toJS<T>(exec, globalObject, element)); + auto* array = JSC::constructArray(&exec, nullptr, &globalObject, list); + return JSC::objectConstructorFreeze(&exec, array); + } +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertSerializedScriptValue.h b/Source/WebCore/bindings/js/JSDOMConvertSerializedScriptValue.h new file mode 100644 index 000000000..10b69f9ac --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertSerializedScriptValue.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "IDLTypes.h" +#include "JSDOMConvertStrings.h" + +namespace WebCore { + +template<typename T> struct Converter<IDLSerializedScriptValue<T>> : DefaultConverter<IDLSerializedScriptValue<T>> { + static RefPtr<T> convert(JSC::ExecState& state, JSC::JSValue value) + { + return T::create(state, value); + } +}; + +template<typename T> struct JSConverter<IDLSerializedScriptValue<T>> { + static constexpr bool needsState = true; + static constexpr bool needsGlobalObject = true; + + static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject& globalObject, RefPtr<T> value) + { + return value ? value->deserialize(state, &globalObject) : JSC::jsNull(); + } +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertStrings.cpp b/Source/WebCore/bindings/js/JSDOMConvertStrings.cpp new file mode 100644 index 000000000..6c95f6680 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertStrings.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2004-2011, 2013, 2016 Apple Inc. All rights reserved. + * Copyright (C) 2007 Samuel Weinig <sam@webkit.org> + * Copyright (C) 2013 Michael Pruett <michael@68k.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "JSDOMConvertStrings.h" + +#include "JSDOMExceptionHandling.h" +#include <heap/HeapInlines.h> +#include <runtime/JSCJSValueInlines.h> +#include <wtf/text/StringBuilder.h> +#include <wtf/unicode/CharacterNames.h> + +using namespace JSC; + +namespace WebCore { + +static inline String stringToByteString(ExecState& state, JSC::ThrowScope& scope, String&& string) +{ + if (!string.containsOnlyLatin1()) { + throwTypeError(&state, scope); + return { }; + } + + return string; +} + +String identifierToByteString(ExecState& state, const Identifier& identifier) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto string = identifier.string(); + return stringToByteString(state, scope, WTFMove(string)); +} + +String valueToByteString(ExecState& state, JSValue value) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto string = value.toWTFString(&state); + RETURN_IF_EXCEPTION(scope, { }); + + return stringToByteString(state, scope, WTFMove(string)); +} + +static inline bool hasUnpairedSurrogate(StringView string) +{ + // Fast path for 8-bit strings; they can't have any surrogates. + if (string.is8Bit()) + return false; + for (auto codePoint : string.codePoints()) { + if (U_IS_SURROGATE(codePoint)) + return true; + } + return false; +} + +static inline String stringToUSVString(String&& string) +{ + // Fast path for the case where there are no unpaired surrogates. + if (!hasUnpairedSurrogate(string)) + return string; + + // Slow path: http://heycam.github.io/webidl/#dfn-obtain-unicode + // Replaces unpaired surrogates with the replacement character. + StringBuilder result; + result.reserveCapacity(string.length()); + StringView view { string }; + for (auto codePoint : view.codePoints()) { + if (U_IS_SURROGATE(codePoint)) + result.append(replacementCharacter); + else + result.append(codePoint); + } + return result.toString(); +} + +String identifierToUSVString(ExecState&, const Identifier& identifier) +{ + auto string = identifier.string(); + return stringToUSVString(WTFMove(string)); +} + +String valueToUSVString(ExecState& state, JSValue value) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto string = value.toWTFString(&state); + RETURN_IF_EXCEPTION(scope, { }); + + return stringToUSVString(WTFMove(string)); +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertStrings.h b/Source/WebCore/bindings/js/JSDOMConvertStrings.h new file mode 100644 index 000000000..dd9bfad77 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertStrings.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "IDLTypes.h" +#include "JSDOMConvertBase.h" +#include "JSDOMExceptionHandling.h" + +namespace WebCore { + +enum class StringConversionConfiguration { Normal, TreatNullAsEmptyString }; + +template<typename T> typename Converter<T>::ReturnType convert(JSC::ExecState&, JSC::JSValue, StringConversionConfiguration); + +template<typename T> inline typename Converter<T>::ReturnType convert(JSC::ExecState& state, JSC::JSValue value, StringConversionConfiguration configuration) +{ + return Converter<T>::convert(state, value, configuration); +} + +WEBCORE_EXPORT String identifierToByteString(JSC::ExecState&, const JSC::Identifier&); +WEBCORE_EXPORT String valueToByteString(JSC::ExecState&, JSC::JSValue); +WEBCORE_EXPORT String identifierToUSVString(JSC::ExecState&, const JSC::Identifier&); +WEBCORE_EXPORT String valueToUSVString(JSC::ExecState&, JSC::JSValue); + +inline String propertyNameToString(JSC::PropertyName propertyName) +{ + ASSERT(!propertyName.isSymbol()); + return propertyName.uid() ? propertyName.uid() : propertyName.publicName(); +} + +inline AtomicString propertyNameToAtomicString(JSC::PropertyName propertyName) +{ + return AtomicString(propertyName.uid() ? propertyName.uid() : propertyName.publicName()); +} + +// MARK: - +// MARK: String types + +template<> struct Converter<IDLDOMString> : DefaultConverter<IDLDOMString> { + static String convert(JSC::ExecState& state, JSC::JSValue value, StringConversionConfiguration configuration = StringConversionConfiguration::Normal) + { + if (configuration == StringConversionConfiguration::TreatNullAsEmptyString && value.isNull()) + return emptyString(); + return value.toWTFString(&state); + } +}; + +template<> struct JSConverter<IDLDOMString> { + static constexpr bool needsState = true; + static constexpr bool needsGlobalObject = false; + + static JSC::JSValue convert(JSC::ExecState& state, const String& value) + { + return JSC::jsStringWithCache(&state, value); + } +}; + +template<> struct Converter<IDLByteString> : DefaultConverter<IDLByteString> { + static String convert(JSC::ExecState& state, JSC::JSValue value, StringConversionConfiguration configuration = StringConversionConfiguration::Normal) + { + if (configuration == StringConversionConfiguration::TreatNullAsEmptyString && value.isNull()) + return emptyString(); + return valueToByteString(state, value); + } +}; + +template<> struct JSConverter<IDLByteString> { + static constexpr bool needsState = true; + static constexpr bool needsGlobalObject = false; + + static JSC::JSValue convert(JSC::ExecState& state, const String& value) + { + return JSC::jsStringWithCache(&state, value); + } +}; + +template<> struct Converter<IDLUSVString> : DefaultConverter<IDLUSVString> { + static String convert(JSC::ExecState& state, JSC::JSValue value, StringConversionConfiguration configuration = StringConversionConfiguration::Normal) + { + if (configuration == StringConversionConfiguration::TreatNullAsEmptyString && value.isNull()) + return emptyString(); + return valueToUSVString(state, value); + } +}; + +template<> struct JSConverter<IDLUSVString> { + static constexpr bool needsState = true; + static constexpr bool needsGlobalObject = false; + + static JSC::JSValue convert(JSC::ExecState& state, const String& value) + { + return JSC::jsStringWithCache(&state, value); + } +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertUnion.h b/Source/WebCore/bindings/js/JSDOMConvertUnion.h new file mode 100644 index 000000000..6a2501464 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertUnion.h @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "IDLTypes.h" +#include "JSDOMBinding.h" +#include "JSDOMConvertBase.h" +#include <runtime/IteratorOperations.h> + +namespace WebCore { + +template<typename ReturnType, typename T, bool enabled> +struct ConditionalConverter; + +template<typename ReturnType, typename T> +struct ConditionalConverter<ReturnType, T, true> { + static std::optional<ReturnType> convert(JSC::ExecState& state, JSC::JSValue value) + { + return ReturnType(Converter<T>::convert(state, value)); + } +}; + +template<typename ReturnType, typename T> +struct ConditionalConverter<ReturnType, T, false> { + static std::optional<ReturnType> convert(JSC::ExecState&, JSC::JSValue) + { + return std::nullopt; + } +}; + +namespace Detail { + +template<typename List, bool condition> +struct ConditionalFront; + +template<typename List> +struct ConditionalFront<List, true> { + using type = brigand::front<List>; +}; + +template<typename List> +struct ConditionalFront<List, false> { + using type = void; +}; + +} + +template<typename List, bool condition> +using ConditionalFront = typename Detail::ConditionalFront<List, condition>::type; + +template<typename... T> struct Converter<IDLUnion<T...>> : DefaultConverter<IDLUnion<T...>> { + using Type = IDLUnion<T...>; + using TypeList = typename Type::TypeList; + using ReturnType = typename Type::ImplementationType; + + using NumericTypeList = brigand::filter<TypeList, IsIDLNumber<brigand::_1>>; + static constexpr size_t numberOfNumericTypes = brigand::size<NumericTypeList>::value; + static_assert(numberOfNumericTypes == 0 || numberOfNumericTypes == 1, "There can be 0 or 1 numeric types in an IDLUnion."); + using NumericType = ConditionalFront<NumericTypeList, numberOfNumericTypes != 0>; + + // FIXME: This should also check for IDLEnumeration<T>. + using StringTypeList = brigand::filter<TypeList, std::is_base_of<IDLString, brigand::_1>>; + static constexpr size_t numberOfStringTypes = brigand::size<StringTypeList>::value; + static_assert(numberOfStringTypes == 0 || numberOfStringTypes == 1, "There can be 0 or 1 string types in an IDLUnion."); + using StringType = ConditionalFront<StringTypeList, numberOfStringTypes != 0>; + + using SequenceTypeList = brigand::filter<TypeList, IsIDLSequence<brigand::_1>>; + static constexpr size_t numberOfSequenceTypes = brigand::size<SequenceTypeList>::value; + static_assert(numberOfSequenceTypes == 0 || numberOfSequenceTypes == 1, "There can be 0 or 1 sequence types in an IDLUnion."); + using SequenceType = ConditionalFront<SequenceTypeList, numberOfSequenceTypes != 0>; + + using FrozenArrayTypeList = brigand::filter<TypeList, IsIDLFrozenArray<brigand::_1>>; + static constexpr size_t numberOfFrozenArrayTypes = brigand::size<FrozenArrayTypeList>::value; + static_assert(numberOfFrozenArrayTypes == 0 || numberOfFrozenArrayTypes == 1, "There can be 0 or 1 FrozenArray types in an IDLUnion."); + using FrozenArrayType = ConditionalFront<FrozenArrayTypeList, numberOfFrozenArrayTypes != 0>; + + using DictionaryTypeList = brigand::filter<TypeList, IsIDLDictionary<brigand::_1>>; + static constexpr size_t numberOfDictionaryTypes = brigand::size<DictionaryTypeList>::value; + static_assert(numberOfDictionaryTypes == 0 || numberOfDictionaryTypes == 1, "There can be 0 or 1 dictionary types in an IDLUnion."); + static constexpr bool hasDictionaryType = numberOfDictionaryTypes != 0; + using DictionaryType = ConditionalFront<DictionaryTypeList, hasDictionaryType>; + + using RecordTypeList = brigand::filter<TypeList, IsIDLRecord<brigand::_1>>; + static constexpr size_t numberOfRecordTypes = brigand::size<RecordTypeList>::value; + static_assert(numberOfRecordTypes == 0 || numberOfRecordTypes == 1, "There can be 0 or 1 record types in an IDLUnion."); + static constexpr bool hasRecordType = numberOfRecordTypes != 0; + using RecordType = ConditionalFront<RecordTypeList, hasRecordType>; + + static constexpr bool hasObjectType = (numberOfSequenceTypes + numberOfFrozenArrayTypes + numberOfDictionaryTypes + numberOfRecordTypes) > 0; + + using InterfaceTypeList = brigand::filter<TypeList, IsIDLInterface<brigand::_1>>; + + static ReturnType convert(JSC::ExecState& state, JSC::JSValue value) + { + JSC::VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + // 1. If the union type includes a nullable type and V is null or undefined, then return the IDL value null. + constexpr bool hasNullType = brigand::any<TypeList, std::is_same<IDLNull, brigand::_1>>::value; + if (hasNullType) { + if (value.isUndefinedOrNull()) + return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, IDLNull, hasNullType>::convert(state, value).value()); + } + + // 2. Let types be the flattened member types of the union type. + // NOTE: Union is expected to be pre-flattented. + + // 3. If V is null or undefined then: + if (hasDictionaryType || hasRecordType) { + if (value.isUndefinedOrNull()) { + // 1. If types includes a dictionary type, then return the result of converting V to that dictionary type. + if (hasDictionaryType) + return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, DictionaryType, hasDictionaryType>::convert(state, value).value()); + + // 2. If types includes a record type, then return the result of converting V to that record type. + if (hasRecordType) + return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, RecordType, hasRecordType>::convert(state, value).value()); + } + } + + // 4. If V is a platform object, then: + // 1. If types includes an interface type that V implements, then return the IDL value that is a reference to the object V. + // 2. If types includes object, then return the IDL value that is a reference to the object V. + // (FIXME: Add support for object and step 4.2) + if (brigand::any<TypeList, IsIDLInterface<brigand::_1>>::value) { + std::optional<ReturnType> returnValue; + brigand::for_each<InterfaceTypeList>([&](auto&& type) { + if (returnValue) + return; + + using Type = typename WTF::RemoveCVAndReference<decltype(type)>::type::type; + using ImplementationType = typename Type::ImplementationType; + using RawType = typename Type::RawType; + using WrapperType = typename JSDOMWrapperConverterTraits<RawType>::WrapperClass; + + auto castedValue = WrapperType::toWrapped(vm, value); + if (!castedValue) + return; + + returnValue = ReturnType(ImplementationType(castedValue)); + }); + + if (returnValue) + return WTFMove(returnValue.value()); + } + + // FIXME: Add support for steps 5 - 10. + + // 11. If V is any kind of object, then: + if (hasObjectType) { + if (value.isCell()) { + JSC::JSCell* cell = value.asCell(); + if (cell->isObject()) { + // FIXME: We should be able to optimize the following code by making use + // of the fact that we have proved that the value is an object. + + // 1. If types includes a sequence type, then: + // 1. Let method be the result of GetMethod(V, @@iterator). + // 2. ReturnIfAbrupt(method). + // 3. If method is not undefined, return the result of creating a + // sequence of that type from V and method. + constexpr bool hasSequenceType = numberOfSequenceTypes != 0; + if (hasSequenceType) { + bool hasIterator = JSC::hasIteratorMethod(state, value); + RETURN_IF_EXCEPTION(scope, ReturnType()); + if (hasIterator) + return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, SequenceType, hasSequenceType>::convert(state, value).value()); + } + + // 2. If types includes a frozen array type, then: + // 1. Let method be the result of GetMethod(V, @@iterator). + // 2. ReturnIfAbrupt(method). + // 3. If method is not undefined, return the result of creating a + // frozen array of that type from V and method. + constexpr bool hasFrozenArrayType = numberOfFrozenArrayTypes != 0; + if (hasFrozenArrayType) { + bool hasIterator = JSC::hasIteratorMethod(state, value); + RETURN_IF_EXCEPTION(scope, ReturnType()); + if (hasIterator) + return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, FrozenArrayType, hasFrozenArrayType>::convert(state, value).value()); + } + + // 3. If types includes a dictionary type, then return the result of + // converting V to that dictionary type. + if (hasDictionaryType) + return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, DictionaryType, hasDictionaryType>::convert(state, value).value()); + + // 4. If types includes a record type, then return the result of converting V to that record type. + if (hasRecordType) + return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, RecordType, hasRecordType>::convert(state, value).value()); + + // 5. If types includes a callback interface type, then return the result of converting V to that interface type. + // (FIXME: Add support for callback interface type and step 12.5) + // 6. If types includes object, then return the IDL value that is a reference to the object V. + // (FIXME: Add support for object and step 12.6) + } + } + } + + // 12. If V is a Boolean value, then: + // 1. If types includes a boolean, then return the result of converting V to boolean. + constexpr bool hasBooleanType = brigand::any<TypeList, std::is_same<IDLBoolean, brigand::_1>>::value; + if (hasBooleanType) { + if (value.isBoolean()) + return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, IDLBoolean, hasBooleanType>::convert(state, value).value()); + } + + // 13. If V is a Number value, then: + // 1. If types includes a numeric type, then return the result of converting V to that numeric type. + constexpr bool hasNumericType = brigand::size<NumericTypeList>::value != 0; + if (hasNumericType) { + if (value.isNumber()) + return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, NumericType, hasNumericType>::convert(state, value).value()); + } + + // 14. If types includes a string type, then return the result of converting V to that type. + constexpr bool hasStringType = brigand::size<StringTypeList>::value != 0; + if (hasStringType) + return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, StringType, hasStringType>::convert(state, value).value()); + + // 15. If types includes a numeric type, then return the result of converting V to that numeric type. + if (hasNumericType) + return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, NumericType, hasNumericType>::convert(state, value).value()); + + // 16. If types includes a boolean, then return the result of converting V to boolean. + if (hasBooleanType) + return std::move<WTF::CheckMoveParameter>(ConditionalConverter<ReturnType, IDLBoolean, hasBooleanType>::convert(state, value).value()); + + // 17. Throw a TypeError. + throwTypeError(&state, scope); + return ReturnType(); + } +}; + +template<typename... T> struct JSConverter<IDLUnion<T...>> { + using Type = IDLUnion<T...>; + using TypeList = typename Type::TypeList; + using ImplementationType = typename Type::ImplementationType; + + static constexpr bool needsState = true; + static constexpr bool needsGlobalObject = true; + + using Sequence = brigand::make_sequence<brigand::ptrdiff_t<0>, WTF::variant_size<ImplementationType>::value>; + + static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject& globalObject, const ImplementationType& variant) + { + auto index = variant.index(); + + std::optional<JSC::JSValue> returnValue; + brigand::for_each<Sequence>([&](auto&& type) { + using I = typename WTF::RemoveCVAndReference<decltype(type)>::type::type; + if (I::value == index) { + ASSERT(!returnValue); + returnValue = toJS<brigand::at<TypeList, I>>(state, globalObject, WTF::get<I::value>(variant)); + } + }); + + ASSERT(returnValue); + return returnValue.value(); + } +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertVariadic.h b/Source/WebCore/bindings/js/JSDOMConvertVariadic.h new file mode 100644 index 000000000..79b2b9d55 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertVariadic.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "IDLTypes.h" +#include "JSDOMConvertBase.h" + +namespace WebCore { + +namespace Detail { + +template<typename IDLType> +struct VariadicConverterBase; + +template<typename IDLType> +struct VariadicConverterBase { + using Item = typename IDLType::ImplementationType; + + static std::optional<Item> convert(JSC::ExecState& state, JSC::JSValue value) + { + auto& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto result = Converter<IDLType>::convert(state, value); + RETURN_IF_EXCEPTION(scope, std::nullopt); + + return WTFMove(result); + } +}; + +template<typename T> +struct VariadicConverterBase<IDLInterface<T>> { + using Item = std::reference_wrapper<T>; + + static std::optional<Item> convert(JSC::ExecState& state, JSC::JSValue value) + { + auto* result = Converter<IDLInterface<T>>::convert(state, value); + if (!result) + return std::nullopt; + return std::optional<Item>(*result); + } +}; + +template<typename IDLType> +struct VariadicConverter : VariadicConverterBase<IDLType> { + using Item = typename VariadicConverterBase<IDLType>::Item; + using Container = Vector<Item>; + + struct Result { + size_t argumentIndex; + std::optional<Container> arguments; + }; +}; + +} + +template<typename IDLType> typename Detail::VariadicConverter<IDLType>::Result convertVariadicArguments(JSC::ExecState& state, size_t startIndex) +{ + size_t length = state.argumentCount(); + if (startIndex > length) + return { 0, std::nullopt }; + + typename Detail::VariadicConverter<IDLType>::Container result; + result.reserveInitialCapacity(length - startIndex); + + for (size_t i = startIndex; i < length; ++i) { + auto value = Detail::VariadicConverter<IDLType>::convert(state, state.uncheckedArgument(i)); + if (!value) + return { i, std::nullopt }; + result.uncheckedAppend(WTFMove(*value)); + } + + return { length, WTFMove(result) }; +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMConvertWebGL.h b/Source/WebCore/bindings/js/JSDOMConvertWebGL.h new file mode 100644 index 000000000..c2740d529 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertWebGL.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#if ENABLE(WEBGL) + +#include "IDLTypes.h" +#include "JSDOMConvertBase.h" + +namespace WebCore { + +template<> struct JSConverter<IDLWebGLAny> { + static constexpr bool needsState = true; + static constexpr bool needsGlobalObject = true; + + static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject& globalObject, const WebGLAny& value) + { + return convertToJSValue(state, globalObject, value); + } +}; + +} // namespace WebCore + +#endif diff --git a/Source/WebCore/bindings/js/JSDOMConvertXPathNSResolver.h b/Source/WebCore/bindings/js/JSDOMConvertXPathNSResolver.h new file mode 100644 index 000000000..94df3f45a --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMConvertXPathNSResolver.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "IDLTypes.h" +#include "JSDOMConvertBase.h" + +namespace WebCore { + +template<typename T> struct Converter<IDLXPathNSResolver<T>> : DefaultConverter<IDLXPathNSResolver<T>> { + using ReturnType = RefPtr<T>; + using WrapperType = typename JSDOMWrapperConverterTraits<T>::WrapperClass; + + template<typename ExceptionThrower = DefaultExceptionThrower> + static ReturnType convert(JSC::ExecState& state, JSC::JSValue value, ExceptionThrower&& exceptionThrower = ExceptionThrower()) + { + JSC::VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + ReturnType object = WrapperType::toWrapped(vm, state, value); + if (UNLIKELY(!object)) + exceptionThrower(state, scope); + return object; + } +}; + +template<typename T> struct JSConverter<IDLXPathNSResolver<T>> { + static constexpr bool needsState = true; + static constexpr bool needsGlobalObject = true; + + template <typename U> + static JSC::JSValue convert(JSC::ExecState& state, JSDOMGlobalObject& globalObject, const U& value) + { + return toJS(&state, &globalObject, Detail::getPtrOrRef(value)); + } + + template<typename U> + static JSC::JSValue convertNewlyCreated(JSC::ExecState& state, JSDOMGlobalObject& globalObject, U&& value) + { + return toJSNewlyCreated(&state, &globalObject, std::forward<U>(value)); + } +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMExceptionHandling.cpp b/Source/WebCore/bindings/js/JSDOMExceptionHandling.cpp new file mode 100644 index 000000000..585553d16 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMExceptionHandling.cpp @@ -0,0 +1,404 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2004-2011, 2013, 2016 Apple Inc. All rights reserved. + * Copyright (C) 2007 Samuel Weinig <sam@webkit.org> + * Copyright (C) 2013 Michael Pruett <michael@68k.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "JSDOMExceptionHandling.h" + +#include "CachedScript.h" +#include "DOMWindow.h" +#include "ExceptionCodeDescription.h" +#include "ExceptionHeaders.h" +#include "ExceptionInterfaces.h" +#include "JSDOMPromise.h" +#include "JSDOMWindow.h" +#include "JSDynamicDowncast.h" +#include "JSExceptionBase.h" +#include <inspector/ScriptCallStack.h> +#include <inspector/ScriptCallStackFactory.h> +#include <runtime/ErrorHandlingScope.h> +#include <runtime/Exception.h> +#include <runtime/ExceptionHelpers.h> +#include <wtf/text/StringBuilder.h> + +#if ENABLE(INDEXED_DATABASE) +#include "IDBDatabaseException.h" +#endif + +using namespace JSC; + +namespace WebCore { + +void reportException(ExecState* exec, JSValue exceptionValue, CachedScript* cachedScript) +{ + VM& vm = exec->vm(); + RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock()); + auto* exception = jsDynamicDowncast<JSC::Exception*>(vm, exceptionValue); + if (!exception) { + exception = vm.lastException(); + if (!exception) + exception = JSC::Exception::create(exec->vm(), exceptionValue, JSC::Exception::DoNotCaptureStack); + } + + reportException(exec, exception, cachedScript); +} + +String retrieveErrorMessage(ExecState& state, VM& vm, JSValue exception, CatchScope& catchScope) +{ + if (auto* exceptionBase = toExceptionBase(vm, exception)) + return exceptionBase->toString(); + + // FIXME: <http://webkit.org/b/115087> Web Inspector: WebCore::reportException should not evaluate JavaScript handling exceptions + // If this is a custom exception object, call toString on it to try and get a nice string representation for the exception. + String errorMessage; + if (auto* error = jsDynamicDowncast<ErrorInstance*>(vm, exception)) + errorMessage = error->sanitizedToString(&state); + else + errorMessage = exception.toWTFString(&state); + + // We need to clear any new exception that may be thrown in the toString() call above. + // reportException() is not supposed to be making new exceptions. + catchScope.clearException(); + vm.clearLastException(); + return errorMessage; +} + +void reportException(ExecState* exec, JSC::Exception* exception, CachedScript* cachedScript, ExceptionDetails* exceptionDetails) +{ + VM& vm = exec->vm(); + auto scope = DECLARE_CATCH_SCOPE(vm); + + RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock()); + if (isTerminatedExecutionException(vm, exception)) + return; + + ErrorHandlingScope errorScope(exec->vm()); + + auto callStack = Inspector::createScriptCallStackFromException(exec, exception, Inspector::ScriptCallStack::maxCallStackSizeToCapture); + scope.clearException(); + vm.clearLastException(); + + auto* globalObject = jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()); + if (auto* window = jsDynamicDowncast<JSDOMWindow*>(vm, globalObject)) { + if (!window->wrapped().isCurrentlyDisplayedInFrame()) + return; + } + + int lineNumber = 0; + int columnNumber = 0; + String exceptionSourceURL; + if (auto* callFrame = callStack->firstNonNativeCallFrame()) { + lineNumber = callFrame->lineNumber(); + columnNumber = callFrame->columnNumber(); + exceptionSourceURL = callFrame->sourceURL(); + } + + auto errorMessage = retrieveErrorMessage(*exec, vm, exception->value(), scope); + globalObject->scriptExecutionContext()->reportException(errorMessage, lineNumber, columnNumber, exceptionSourceURL, exception, callStack->size() ? callStack.ptr() : nullptr, cachedScript); + + if (exceptionDetails) { + exceptionDetails->message = errorMessage; + exceptionDetails->lineNumber = lineNumber; + exceptionDetails->columnNumber = columnNumber; + exceptionDetails->sourceURL = exceptionSourceURL; + } +} + +void reportCurrentException(ExecState* exec) +{ + VM& vm = exec->vm(); + auto scope = DECLARE_CATCH_SCOPE(vm); + auto* exception = scope.exception(); + scope.clearException(); + reportException(exec, exception); +} + +static JSValue createDOMException(ExecState* exec, ExceptionCode ec, const String* message = nullptr) +{ + if (!ec || ec == ExistingExceptionError) + return jsUndefined(); + + // FIXME: Handle other WebIDL exception types. + if (ec == TypeError) { + if (!message || message->isEmpty()) + return createTypeError(exec); + return createTypeError(exec, *message); + } + + if (ec == RangeError) { + if (!message || message->isEmpty()) + return createRangeError(exec, ASCIILiteral("Bad value")); + return createRangeError(exec, *message); + } + + if (ec == StackOverflowError) + return createStackOverflowError(exec); + + // FIXME: All callers to createDOMException need to pass in the correct global object. + // For now, we're going to assume the lexicalGlobalObject. Which is wrong in cases like this: + // frames[0].document.createElement(null, null); // throws an exception which should have the subframe's prototypes. + JSDOMGlobalObject* globalObject = deprecatedGlobalObjectForPrototype(exec); + + ExceptionCodeDescription description(ec); + + CString messageCString; + if (message) + messageCString = message->utf8(); + if (message && !message->isEmpty()) { + // It is safe to do this because the char* contents of the CString are copied into a new WTF::String before the CString is destroyed. + description.description = messageCString.data(); + } + + JSValue errorObject; + switch (description.type) { + case DOMCoreExceptionType: +#if ENABLE(INDEXED_DATABASE) + case IDBDatabaseExceptionType: +#endif + errorObject = toJS(exec, globalObject, DOMCoreException::create(description)); + break; + case FileExceptionType: + errorObject = toJS(exec, globalObject, FileException::create(description)); + break; + case SQLExceptionType: + errorObject = toJS(exec, globalObject, SQLException::create(description)); + break; + case SVGExceptionType: + errorObject = toJS(exec, globalObject, SVGException::create(description)); + break; + case XPathExceptionType: + errorObject = toJS(exec, globalObject, XPathException::create(description)); + break; + } + + ASSERT(errorObject); + addErrorInfo(exec, asObject(errorObject), true); + return errorObject; +} + +JSValue createDOMException(ExecState* exec, ExceptionCode ec, const String& message) +{ + return createDOMException(exec, ec, &message); +} + +JSValue createDOMException(ExecState& state, Exception&& exception) +{ + return createDOMException(&state, exception.code(), exception.releaseMessage()); +} + +void propagateExceptionSlowPath(JSC::ExecState& state, JSC::ThrowScope& throwScope, Exception&& exception) +{ + ASSERT(!throwScope.exception()); + throwException(&state, throwScope, createDOMException(state, WTFMove(exception))); +} + +static EncodedJSValue throwTypeError(JSC::ExecState& state, JSC::ThrowScope& scope, const String& errorMessage) +{ + return throwVMTypeError(&state, scope, errorMessage); +} + +static void appendArgumentMustBe(StringBuilder& builder, unsigned argumentIndex, const char* argumentName, const char* interfaceName, const char* functionName) +{ + builder.appendLiteral("Argument "); + builder.appendNumber(argumentIndex + 1); + builder.appendLiteral(" ('"); + builder.append(argumentName); + builder.appendLiteral("') to "); + if (!functionName) { + builder.appendLiteral("the "); + builder.append(interfaceName); + builder.appendLiteral(" constructor"); + } else { + builder.append(interfaceName); + builder.append('.'); + builder.append(functionName); + } + builder.appendLiteral(" must be "); +} + +JSC::EncodedJSValue reportDeprecatedGetterError(JSC::ExecState& state, const char* interfaceName, const char* attributeName) +{ + auto& context = *jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject())->scriptExecutionContext(); + context.addConsoleMessage(MessageSource::JS, MessageLevel::Error, makeString("Deprecated attempt to access property '", attributeName, "' on a non-", interfaceName, " object.")); + return JSValue::encode(jsUndefined()); +} + +void reportDeprecatedSetterError(JSC::ExecState& state, const char* interfaceName, const char* attributeName) +{ + auto& context = *jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject())->scriptExecutionContext(); + context.addConsoleMessage(MessageSource::JS, MessageLevel::Error, makeString("Deprecated attempt to set property '", attributeName, "' on a non-", interfaceName, " object.")); +} + +void throwNotSupportedError(JSC::ExecState& state, JSC::ThrowScope& scope) +{ + ASSERT(!scope.exception()); + throwException(&state, scope, createDOMException(&state, NOT_SUPPORTED_ERR)); +} + +void throwNotSupportedError(JSC::ExecState& state, JSC::ThrowScope& scope, const char* message) +{ + ASSERT(!scope.exception()); + String messageString(message); + throwException(&state, scope, createDOMException(&state, NOT_SUPPORTED_ERR, &messageString)); +} + +void throwInvalidStateError(JSC::ExecState& state, JSC::ThrowScope& scope, const char* message) +{ + ASSERT(!scope.exception()); + String messageString(message); + throwException(&state, scope, createDOMException(&state, INVALID_STATE_ERR, &messageString)); +} + +void throwSecurityError(JSC::ExecState& state, JSC::ThrowScope& scope, const String& message) +{ + ASSERT(!scope.exception()); + throwException(&state, scope, createDOMException(&state, SECURITY_ERR, message)); +} + +JSC::EncodedJSValue throwArgumentMustBeEnumError(JSC::ExecState& state, JSC::ThrowScope& scope, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedValues) +{ + StringBuilder builder; + appendArgumentMustBe(builder, argumentIndex, argumentName, functionInterfaceName, functionName); + builder.appendLiteral("one of: "); + builder.append(expectedValues); + return throwVMTypeError(&state, scope, builder.toString()); +} + +JSC::EncodedJSValue throwArgumentMustBeFunctionError(JSC::ExecState& state, JSC::ThrowScope& scope, unsigned argumentIndex, const char* argumentName, const char* interfaceName, const char* functionName) +{ + StringBuilder builder; + appendArgumentMustBe(builder, argumentIndex, argumentName, interfaceName, functionName); + builder.appendLiteral("a function"); + return throwVMTypeError(&state, scope, builder.toString()); +} + +JSC::EncodedJSValue throwArgumentTypeError(JSC::ExecState& state, JSC::ThrowScope& scope, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedType) +{ + StringBuilder builder; + appendArgumentMustBe(builder, argumentIndex, argumentName, functionInterfaceName, functionName); + builder.appendLiteral("an instance of "); + builder.append(expectedType); + return throwVMTypeError(&state, scope, builder.toString()); +} + +void throwArrayElementTypeError(JSC::ExecState& state, JSC::ThrowScope& scope) +{ + throwTypeError(state, scope, ASCIILiteral("Invalid Array element type")); +} + +void throwAttributeTypeError(JSC::ExecState& state, JSC::ThrowScope& scope, const char* interfaceName, const char* attributeName, const char* expectedType) +{ + throwTypeError(state, scope, makeString("The ", interfaceName, '.', attributeName, " attribute must be an instance of ", expectedType)); +} + +JSC::EncodedJSValue throwRequiredMemberTypeError(JSC::ExecState& state, JSC::ThrowScope& scope, const char* memberName, const char* dictionaryName, const char* expectedType) +{ + StringBuilder builder; + builder.appendLiteral("Member "); + builder.append(dictionaryName); + builder.append('.'); + builder.append(memberName); + builder.appendLiteral(" is required and must be an instance of "); + builder.append(expectedType); + return throwVMTypeError(&state, scope, builder.toString()); +} + +JSC::EncodedJSValue throwConstructorScriptExecutionContextUnavailableError(JSC::ExecState& state, JSC::ThrowScope& scope, const char* interfaceName) +{ + return throwVMError(&state, scope, createReferenceError(&state, makeString(interfaceName, " constructor associated execution context is unavailable"))); +} + +void throwSequenceTypeError(JSC::ExecState& state, JSC::ThrowScope& scope) +{ + throwTypeError(state, scope, ASCIILiteral("Value is not a sequence")); +} + +void throwNonFiniteTypeError(ExecState& state, JSC::ThrowScope& scope) +{ + throwTypeError(&state, scope, ASCIILiteral("The provided value is non-finite")); +} + +String makeGetterTypeErrorMessage(const char* interfaceName, const char* attributeName) +{ + return makeString("The ", interfaceName, '.', attributeName, " getter can only be used on instances of ", interfaceName); +} + +JSC::EncodedJSValue throwGetterTypeError(JSC::ExecState& state, JSC::ThrowScope& scope, const char* interfaceName, const char* attributeName) +{ + return throwVMTypeError(&state, scope, makeGetterTypeErrorMessage(interfaceName, attributeName)); +} + +JSC::EncodedJSValue rejectPromiseWithGetterTypeError(JSC::ExecState& state, const char* interfaceName, const char* attributeName) +{ + return createRejectedPromiseWithTypeError(state, makeGetterTypeErrorMessage(interfaceName, attributeName)); +} + +bool throwSetterTypeError(JSC::ExecState& state, JSC::ThrowScope& scope, const char* interfaceName, const char* attributeName) +{ + throwTypeError(state, scope, makeString("The ", interfaceName, '.', attributeName, " setter can only be used on instances of ", interfaceName)); + return false; +} + +String makeThisTypeErrorMessage(const char* interfaceName, const char* functionName) +{ + return makeString("Can only call ", interfaceName, '.', functionName, " on instances of ", interfaceName); +} + +EncodedJSValue throwThisTypeError(JSC::ExecState& state, JSC::ThrowScope& scope, const char* interfaceName, const char* functionName) +{ + return throwTypeError(state, scope, makeThisTypeErrorMessage(interfaceName, functionName)); +} + +JSC::EncodedJSValue rejectPromiseWithThisTypeError(DeferredPromise& promise, const char* interfaceName, const char* methodName) +{ + promise.reject(TypeError, makeThisTypeErrorMessage(interfaceName, methodName)); + return JSValue::encode(jsUndefined()); +} + +JSC::EncodedJSValue rejectPromiseWithThisTypeError(JSC::ExecState& state, const char* interfaceName, const char* methodName) +{ + return createRejectedPromiseWithTypeError(state, makeThisTypeErrorMessage(interfaceName, methodName)); +} + +void throwDOMSyntaxError(JSC::ExecState& state, JSC::ThrowScope& scope) +{ + ASSERT(!scope.exception()); + throwException(&state, scope, createDOMException(&state, SYNTAX_ERR)); +} + +void throwDataCloneError(JSC::ExecState& state, JSC::ThrowScope& scope) +{ + ASSERT(!scope.exception()); + throwException(&state, scope, createDOMException(&state, DATA_CLONE_ERR)); +} + +void throwIndexSizeError(JSC::ExecState& state, JSC::ThrowScope& scope) +{ + ASSERT(!scope.exception()); + throwException(&state, scope, createDOMException(&state, INDEX_SIZE_ERR)); +} + +void throwTypeMismatchError(JSC::ExecState& state, JSC::ThrowScope& scope) +{ + ASSERT(!scope.exception()); + throwException(&state, scope, createDOMException(&state, TYPE_MISMATCH_ERR)); +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMExceptionHandling.h b/Source/WebCore/bindings/js/JSDOMExceptionHandling.h new file mode 100644 index 000000000..0300213b2 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMExceptionHandling.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2003-2006, 2008-2009, 2013, 2016 Apple Inc. All rights reserved. + * Copyright (C) 2007 Samuel Weinig <sam@webkit.org> + * Copyright (C) 2009 Google, Inc. All rights reserved. + * Copyright (C) 2012 Ericsson AB. All rights reserved. + * Copyright (C) 2013 Michael Pruett <michael@68k.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "ExceptionCode.h" +#include "ExceptionOr.h" +#include <runtime/Error.h> + +namespace JSC { +class CatchScope; +} + +namespace WebCore { + +class CachedScript; +class DeferredPromise; +class JSDOMGlobalObject; + +struct ExceptionDetails { + String message; + int lineNumber { 0 }; + int columnNumber { 0 }; + String sourceURL; +}; + +WEBCORE_EXPORT JSC::EncodedJSValue reportDeprecatedGetterError(JSC::ExecState&, const char* interfaceName, const char* attributeName); +WEBCORE_EXPORT void reportDeprecatedSetterError(JSC::ExecState&, const char* interfaceName, const char* attributeName); + +void throwAttributeTypeError(JSC::ExecState&, JSC::ThrowScope&, const char* interfaceName, const char* attributeName, const char* expectedType); +WEBCORE_EXPORT bool throwSetterTypeError(JSC::ExecState&, JSC::ThrowScope&, const char* interfaceName, const char* attributeName); + +void throwArrayElementTypeError(JSC::ExecState&, JSC::ThrowScope&); +void throwDataCloneError(JSC::ExecState&, JSC::ThrowScope&); +void throwDOMSyntaxError(JSC::ExecState&, JSC::ThrowScope&); // Not the same as a JavaScript syntax error. +void throwIndexSizeError(JSC::ExecState&, JSC::ThrowScope&); +void throwInvalidStateError(JSC::ExecState&, JSC::ThrowScope&, const char* message); +WEBCORE_EXPORT void throwNonFiniteTypeError(JSC::ExecState&, JSC::ThrowScope&); +void throwNotSupportedError(JSC::ExecState&, JSC::ThrowScope&); +void throwNotSupportedError(JSC::ExecState&, JSC::ThrowScope&, const char* message); +void throwSecurityError(JSC::ExecState&, JSC::ThrowScope&, const String& message); +WEBCORE_EXPORT void throwSequenceTypeError(JSC::ExecState&, JSC::ThrowScope&); +void throwTypeMismatchError(JSC::ExecState&, JSC::ThrowScope&); + +WEBCORE_EXPORT JSC::EncodedJSValue throwArgumentMustBeEnumError(JSC::ExecState&, JSC::ThrowScope&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedValues); +JSC::EncodedJSValue throwArgumentMustBeFunctionError(JSC::ExecState&, JSC::ThrowScope&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName); +WEBCORE_EXPORT JSC::EncodedJSValue throwArgumentTypeError(JSC::ExecState&, JSC::ThrowScope&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedType); +WEBCORE_EXPORT JSC::EncodedJSValue throwRequiredMemberTypeError(JSC::ExecState&, JSC::ThrowScope&, const char* memberName, const char* dictionaryName, const char* expectedType); +JSC::EncodedJSValue throwConstructorScriptExecutionContextUnavailableError(JSC::ExecState&, JSC::ThrowScope&, const char* interfaceName); + +String makeGetterTypeErrorMessage(const char* interfaceName, const char* attributeName); +String makeThisTypeErrorMessage(const char* interfaceName, const char* attributeName); + +WEBCORE_EXPORT JSC::EncodedJSValue throwGetterTypeError(JSC::ExecState&, JSC::ThrowScope&, const char* interfaceName, const char* attributeName); +WEBCORE_EXPORT JSC::EncodedJSValue throwThisTypeError(JSC::ExecState&, JSC::ThrowScope&, const char* interfaceName, const char* functionName); + +WEBCORE_EXPORT JSC::EncodedJSValue rejectPromiseWithGetterTypeError(JSC::ExecState&, const char* interfaceName, const char* attributeName); +WEBCORE_EXPORT JSC::EncodedJSValue rejectPromiseWithThisTypeError(DeferredPromise&, const char* interfaceName, const char* operationName); +WEBCORE_EXPORT JSC::EncodedJSValue rejectPromiseWithThisTypeError(JSC::ExecState&, const char* interfaceName, const char* operationName); + +String retrieveErrorMessage(JSC::ExecState&, JSC::VM&, JSC::JSValue exception, JSC::CatchScope&); +WEBCORE_EXPORT void reportException(JSC::ExecState*, JSC::JSValue exception, CachedScript* = nullptr); +WEBCORE_EXPORT void reportException(JSC::ExecState*, JSC::Exception*, CachedScript* = nullptr, ExceptionDetails* = nullptr); +void reportCurrentException(JSC::ExecState*); + +JSC::JSValue createDOMException(JSC::ExecState&, Exception&&); +JSC::JSValue createDOMException(JSC::ExecState*, ExceptionCode, const String&); + +// Convert a DOM implementation exception into a JavaScript exception in the execution state. +WEBCORE_EXPORT void propagateExceptionSlowPath(JSC::ExecState&, JSC::ThrowScope&, Exception&&); + +ALWAYS_INLINE void propagateException(JSC::ExecState& state, JSC::ThrowScope& throwScope, Exception&& exception) +{ + if (throwScope.exception()) + return; + propagateExceptionSlowPath(state, throwScope, WTFMove(exception)); +} + +inline void propagateException(JSC::ExecState& state, JSC::ThrowScope& throwScope, ExceptionOr<void>&& value) +{ + if (UNLIKELY(value.hasException())) + propagateException(state, throwScope, value.releaseException()); +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMFormDataCustom.cpp b/Source/WebCore/bindings/js/JSDOMFormDataCustom.cpp deleted file mode 100644 index 6d371b309..000000000 --- a/Source/WebCore/bindings/js/JSDOMFormDataCustom.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "JSDOMFormData.h" - -#include "DOMFormData.h" -#include "HTMLFormElement.h" -#include "JSBlob.h" -#include "JSHTMLFormElement.h" -#include <runtime/Error.h> - -using namespace JSC; - -namespace WebCore { - -static HTMLFormElement* toHTMLFormElement(JSC::JSValue value) -{ - return value.inherits(JSHTMLFormElement::info()) ? &jsCast<JSHTMLFormElement*>(asObject(value))->impl() : 0; -} - -EncodedJSValue JSC_HOST_CALL JSDOMFormDataConstructor::constructJSDOMFormData(ExecState* exec) -{ - JSDOMFormDataConstructor* jsConstructor = jsCast<JSDOMFormDataConstructor*>(exec->callee()); - - HTMLFormElement* form = 0; - if (exec->argumentCount() > 0) - form = toHTMLFormElement(exec->argument(0)); - RefPtr<DOMFormData> domFormData = DOMFormData::create(form); - return JSValue::encode(asObject(toJS(exec, jsConstructor->globalObject(), domFormData.get()))); -} - -JSValue JSDOMFormData::append(ExecState* exec) -{ - if (exec->argumentCount() >= 2) { - String name = exec->argument(0).toString(exec)->value(exec); - JSValue value = exec->argument(1); - if (value.inherits(JSBlob::info())) { - String filename; - if (exec->argumentCount() >= 3 && !exec->argument(2).isUndefinedOrNull()) - filename = exec->argument(2).toString(exec)->value(exec); - impl().append(name, toBlob(value), filename); - } else - impl().append(name, value.toString(exec)->value(exec)); - } - - return jsUndefined(); -} - -} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp b/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp index 27bd7894f..933650611 100644 --- a/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp +++ b/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -28,23 +28,42 @@ #include "JSDOMGlobalObject.h" #include "Document.h" +#include "JSDOMPromise.h" #include "JSDOMWindow.h" #include "JSEventListener.h" +#include "JSMediaStream.h" +#include "JSMediaStreamTrack.h" +#include "JSRTCIceCandidate.h" +#include "JSRTCSessionDescription.h" +#include "JSReadableStream.h" +#include "JSReadableStreamPrivateConstructors.h" #include "JSWorkerGlobalScope.h" +#include "RuntimeEnabledFeatures.h" +#include "StructuredClone.h" +#include "WebCoreJSClientData.h" #include "WorkerGlobalScope.h" +#include <builtins/BuiltinNames.h> using namespace JSC; namespace WebCore { -const ClassInfo JSDOMGlobalObject::s_info = { "DOMGlobalObject", &JSGlobalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSDOMGlobalObject) }; +EncodedJSValue JSC_HOST_CALL makeThisTypeErrorForBuiltins(ExecState*); +EncodedJSValue JSC_HOST_CALL makeGetterTypeErrorForBuiltins(ExecState*); -JSDOMGlobalObject::JSDOMGlobalObject(VM& vm, Structure* structure, PassRefPtr<DOMWrapperWorld> world, const GlobalObjectMethodTable* globalObjectMethodTable) +const ClassInfo JSDOMGlobalObject::s_info = { "DOMGlobalObject", &JSGlobalObject::s_info, 0, CREATE_METHOD_TABLE(JSDOMGlobalObject) }; + +JSDOMGlobalObject::JSDOMGlobalObject(VM& vm, Structure* structure, Ref<DOMWrapperWorld>&& world, const GlobalObjectMethodTable* globalObjectMethodTable) : JSGlobalObject(vm, structure, globalObjectMethodTable) , m_currentEvent(0) - , m_world(world) + , m_world(WTFMove(world)) + , m_worldIsNormal(m_world->isNormal()) + , m_builtinInternalFunctions(vm) +{ +} + +JSDOMGlobalObject::~JSDOMGlobalObject() { - ASSERT(m_world); } void JSDOMGlobalObject::destroy(JSCell* cell) @@ -52,33 +71,118 @@ void JSDOMGlobalObject::destroy(JSCell* cell) static_cast<JSDOMGlobalObject*>(cell)->JSDOMGlobalObject::~JSDOMGlobalObject(); } +EncodedJSValue JSC_HOST_CALL makeThisTypeErrorForBuiltins(ExecState* execState) +{ + ASSERT(execState); + ASSERT(execState->argumentCount() == 2); + VM& vm = execState->vm(); + auto scope = DECLARE_CATCH_SCOPE(vm); + + auto interfaceName = execState->uncheckedArgument(0).getString(execState); + ASSERT_UNUSED(scope, !scope.exception()); + auto functionName = execState->uncheckedArgument(1).getString(execState); + ASSERT(!scope.exception()); + return JSValue::encode(createTypeError(execState, makeThisTypeErrorMessage(interfaceName.utf8().data(), functionName.utf8().data()))); +} + +EncodedJSValue JSC_HOST_CALL makeGetterTypeErrorForBuiltins(ExecState* execState) +{ + ASSERT(execState); + ASSERT(execState->argumentCount() == 2); + VM& vm = execState->vm(); + auto scope = DECLARE_CATCH_SCOPE(vm); + + auto interfaceName = execState->uncheckedArgument(0).getString(execState); + ASSERT_UNUSED(scope, !scope.exception()); + auto attributeName = execState->uncheckedArgument(1).getString(execState); + ASSERT(!scope.exception()); + return JSValue::encode(createTypeError(execState, makeGetterTypeErrorMessage(interfaceName.utf8().data(), attributeName.utf8().data()))); +} + +void JSDOMGlobalObject::addBuiltinGlobals(VM& vm) +{ + m_builtinInternalFunctions.initialize(*this); + +#if ENABLE(READABLE_STREAM_API) + JSObject* privateReadableStreamDefaultControllerConstructor = createReadableStreamDefaultControllerPrivateConstructor(vm, *this); +#if ENABLE(READABLE_BYTE_STREAM_API) + JSObject* privateReadableByteStreamControllerConstructor = createReadableByteStreamControllerPrivateConstructor(vm, *this); +#endif + JSObject* privateReadableStreamDefaultReaderConstructor = createReadableStreamDefaultReaderPrivateConstructor(vm, *this); + + ASSERT(!constructors(NoLockingNecessary).get(privateReadableStreamDefaultControllerConstructor->info()).get()); +#if ENABLE(READABLE_BYTE_STREAM_API) + ASSERT(!constructors(NoLockingNecessary).get(privateReadableByteStreamControllerConstructor->info()).get()); +#endif + ASSERT(!constructors(NoLockingNecessary).get(privateReadableStreamDefaultReaderConstructor->info()).get()); + JSC::WriteBarrier<JSC::JSObject> temp; + { + auto locker = lockDuringMarking(vm.heap, m_gcLock); + constructors(locker).add(privateReadableStreamDefaultControllerConstructor->info(), temp).iterator->value.set(vm, this, privateReadableStreamDefaultControllerConstructor); +#if ENABLE(READABLE_BYTE_STREAM_API) + constructors(locker).add(privateReadableByteStreamControllerConstructor->info(), temp).iterator->value.set(vm, this, privateReadableByteStreamControllerConstructor); +#endif + constructors(locker).add(privateReadableStreamDefaultReaderConstructor->info(), temp).iterator->value.set(vm, this, privateReadableStreamDefaultReaderConstructor); + } +#endif + JSVMClientData& clientData = *static_cast<JSVMClientData*>(vm.clientData); + JSDOMGlobalObject::GlobalPropertyInfo staticGlobals[] = { + JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().makeThisTypeErrorPrivateName(), + JSFunction::create(vm, this, 2, String(), makeThisTypeErrorForBuiltins), DontDelete | ReadOnly), + JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().makeGetterTypeErrorPrivateName(), + JSFunction::create(vm, this, 2, String(), makeGetterTypeErrorForBuiltins), DontDelete | ReadOnly), + JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().structuredCloneArrayBufferPrivateName(), + JSFunction::create(vm, this, 1, String(), structuredCloneArrayBuffer), DontDelete | ReadOnly), + JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().structuredCloneArrayBufferViewPrivateName(), + JSFunction::create(vm, this, 1, String(), structuredCloneArrayBufferView), DontDelete | ReadOnly), + JSDOMGlobalObject::GlobalPropertyInfo(vm.propertyNames->builtinNames().ArrayBufferPrivateName(), getDirect(vm, vm.propertyNames->ArrayBuffer), DontDelete | ReadOnly), +#if ENABLE(READABLE_STREAM_API) || ENABLE(WRITABLE_STREAM_API) + JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().streamClosedPrivateName(), jsNumber(1), DontDelete | ReadOnly), + JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().streamClosingPrivateName(), jsNumber(2), DontDelete | ReadOnly), + JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().streamErroredPrivateName(), jsNumber(3), DontDelete | ReadOnly), + JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().streamReadablePrivateName(), jsNumber(4), DontDelete | ReadOnly), + JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().streamWaitingPrivateName(), jsNumber(5), DontDelete | ReadOnly), + JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().streamWritablePrivateName(), jsNumber(6), DontDelete | ReadOnly), +#endif +#if ENABLE(READABLE_STREAM_API) + JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().ReadableStreamDefaultControllerPrivateName(), privateReadableStreamDefaultControllerConstructor, DontDelete | ReadOnly), +#if ENABLE(READABLE_BYTE_STREAM_API) + JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().ReadableByteStreamControllerPrivateName(), privateReadableByteStreamControllerConstructor, DontDelete | ReadOnly), +#endif + JSDOMGlobalObject::GlobalPropertyInfo(clientData.builtinNames().ReadableStreamDefaultReaderPrivateName(), privateReadableStreamDefaultReaderConstructor, DontDelete | ReadOnly), +#endif + }; + addStaticGlobals(staticGlobals, WTF_ARRAY_LENGTH(staticGlobals)); +} + void JSDOMGlobalObject::finishCreation(VM& vm) { Base::finishCreation(vm); - ASSERT(inherits(info())); + ASSERT(inherits(vm, info())); -#if ENABLE(REMOTE_INSPECTOR) - setRemoteDebuggingEnabled(false); -#endif + addBuiltinGlobals(vm); + + RELEASE_ASSERT(classInfo()); } void JSDOMGlobalObject::finishCreation(VM& vm, JSObject* thisValue) { Base::finishCreation(vm, thisValue); - ASSERT(inherits(info())); + ASSERT(inherits(vm, info())); -#if ENABLE(REMOTE_INSPECTOR) - setRemoteDebuggingEnabled(false); -#endif + addBuiltinGlobals(vm); + + RELEASE_ASSERT(classInfo()); } ScriptExecutionContext* JSDOMGlobalObject::scriptExecutionContext() const { - if (inherits(JSDOMWindowBase::info())) + if (inherits(vm(), JSDOMWindowBase::info())) return jsCast<const JSDOMWindowBase*>(this)->scriptExecutionContext(); - if (inherits(JSWorkerGlobalScopeBase::info())) + if (inherits(vm(), JSWorkerGlobalScopeBase::info())) return jsCast<const JSWorkerGlobalScopeBase*>(this)->scriptExecutionContext(); - ASSERT_NOT_REACHED(); + dataLog("Unexpected global object: ", JSValue(this), "\n"); + RELEASE_ASSERT_NOT_REACHED(); return 0; } @@ -86,17 +190,22 @@ void JSDOMGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor) { JSDOMGlobalObject* thisObject = jsCast<JSDOMGlobalObject*>(cell); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); Base::visitChildren(thisObject, visitor); - - JSDOMStructureMap::iterator end = thisObject->structures().end(); - for (JSDOMStructureMap::iterator it = thisObject->structures().begin(); it != end; ++it) - visitor.append(&it->value); - - JSDOMConstructorMap::iterator end2 = thisObject->constructors().end(); - for (JSDOMConstructorMap::iterator it2 = thisObject->constructors().begin(); it2 != end2; ++it2) - visitor.append(&it2->value); + + { + auto locker = holdLock(thisObject->m_gcLock); + + for (auto& structure : thisObject->structures(locker).values()) + visitor.append(structure); + + for (auto& constructor : thisObject->constructors(locker).values()) + visitor.append(constructor); + + for (auto& deferredPromise : thisObject->deferredPromises(locker)) + deferredPromise->visitAggregate(visitor); + } + + thisObject->m_builtinInternalFunctions.visit(visitor); } void JSDOMGlobalObject::setCurrentEvent(Event* currentEvent) @@ -116,14 +225,14 @@ JSDOMGlobalObject* toJSDOMGlobalObject(Document* document, JSC::ExecState* exec) JSDOMGlobalObject* toJSDOMGlobalObject(ScriptExecutionContext* scriptExecutionContext, JSC::ExecState* exec) { - if (scriptExecutionContext->isDocument()) - return toJSDOMGlobalObject(toDocument(scriptExecutionContext), exec); + if (is<Document>(*scriptExecutionContext)) + return toJSDOMGlobalObject(downcast<Document>(scriptExecutionContext), exec); - if (scriptExecutionContext->isWorkerGlobalScope()) - return static_cast<WorkerGlobalScope*>(scriptExecutionContext)->script()->workerGlobalScopeWrapper(); + if (is<WorkerGlobalScope>(*scriptExecutionContext)) + return downcast<WorkerGlobalScope>(*scriptExecutionContext).script()->workerGlobalScopeWrapper(); ASSERT_NOT_REACHED(); - return 0; + return nullptr; } JSDOMGlobalObject* toJSDOMGlobalObject(Document* document, DOMWrapperWorld& world) @@ -133,14 +242,14 @@ JSDOMGlobalObject* toJSDOMGlobalObject(Document* document, DOMWrapperWorld& worl JSDOMGlobalObject* toJSDOMGlobalObject(ScriptExecutionContext* scriptExecutionContext, DOMWrapperWorld& world) { - if (scriptExecutionContext->isDocument()) - return toJSDOMGlobalObject(toDocument(scriptExecutionContext), world); + if (is<Document>(*scriptExecutionContext)) + return toJSDOMGlobalObject(downcast<Document>(scriptExecutionContext), world); - if (scriptExecutionContext->isWorkerGlobalScope()) - return static_cast<WorkerGlobalScope*>(scriptExecutionContext)->script()->workerGlobalScopeWrapper(); + if (is<WorkerGlobalScope>(*scriptExecutionContext)) + return downcast<WorkerGlobalScope>(*scriptExecutionContext).script()->workerGlobalScopeWrapper(); ASSERT_NOT_REACHED(); - return 0; + return nullptr; } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMGlobalObject.h b/Source/WebCore/bindings/js/JSDOMGlobalObject.h index 6eab99967..456d953ba 100644 --- a/Source/WebCore/bindings/js/JSDOMGlobalObject.h +++ b/Source/WebCore/bindings/js/JSDOMGlobalObject.h @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -24,15 +24,17 @@ * */ -#ifndef JSDOMGlobalObject_h -#define JSDOMGlobalObject_h +#pragma once #include "PlatformExportMacros.h" +#include "WebCoreJSBuiltinInternals.h" +#include <heap/LockDuringMarking.h> #include <runtime/JSGlobalObject.h> -#include <runtime/Operations.h> +#include <runtime/StructureInlines.h> namespace WebCore { + class DeferredPromise; class Document; class Event; class DOMWrapperWorld; @@ -40,20 +42,25 @@ namespace WebCore { typedef HashMap<const JSC::ClassInfo*, JSC::WriteBarrier<JSC::Structure>> JSDOMStructureMap; typedef HashMap<const JSC::ClassInfo*, JSC::WriteBarrier<JSC::JSObject>> JSDOMConstructorMap; + typedef HashSet<DeferredPromise*> DeferredPromiseSet; - class JSDOMGlobalObject : public JSC::JSGlobalObject { + class WEBCORE_EXPORT JSDOMGlobalObject : public JSC::JSGlobalObject { typedef JSC::JSGlobalObject Base; protected: struct JSDOMGlobalObjectData; - JSDOMGlobalObject(JSC::VM&, JSC::Structure*, PassRefPtr<DOMWrapperWorld>, const JSC::GlobalObjectMethodTable* = 0); + JSDOMGlobalObject(JSC::VM&, JSC::Structure*, Ref<DOMWrapperWorld>&&, const JSC::GlobalObjectMethodTable* = 0); static void destroy(JSC::JSCell*); void finishCreation(JSC::VM&); void finishCreation(JSC::VM&, JSC::JSObject*); public: - JSDOMStructureMap& structures() { return m_structures; } - JSDOMConstructorMap& constructors() { return m_constructors; } + Lock& gcLock() { return m_gcLock; } + + JSDOMStructureMap& structures(const AbstractLocker&) { return m_structures; } + JSDOMConstructorMap& constructors(const AbstractLocker&) { return m_constructors; } + + DeferredPromiseSet& deferredPromises(const AbstractLocker&) { return m_deferredPromises; } ScriptExecutionContext* scriptExecutionContext() const; @@ -65,13 +72,19 @@ namespace WebCore { static void visitChildren(JSC::JSCell*, JSC::SlotVisitor&); - DOMWrapperWorld& world() { return *m_world; } + DOMWrapperWorld& world() { return m_world.get(); } + bool worldIsNormal() const { return m_worldIsNormal; } + static ptrdiff_t offsetOfWorldIsNormal() { return OBJECT_OFFSETOF(JSDOMGlobalObject, m_worldIsNormal); } + + JSBuiltinInternalFunctions& builtinInternalFunctions() { return m_builtinInternalFunctions; } protected: - static WEBKIT_EXPORTDATA const JSC::ClassInfo s_info; + static const JSC::ClassInfo s_info; public: - static const JSC::ClassInfo* info() { return &s_info; } + ~JSDOMGlobalObject(); + + static constexpr const JSC::ClassInfo* info() { return &s_info; } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSValue prototype) { @@ -81,20 +94,31 @@ namespace WebCore { protected: JSDOMStructureMap m_structures; JSDOMConstructorMap m_constructors; + DeferredPromiseSet m_deferredPromises; Event* m_currentEvent; - RefPtr<DOMWrapperWorld> m_world; + Ref<DOMWrapperWorld> m_world; + uint8_t m_worldIsNormal; + Lock m_gcLock; + + private: + void addBuiltinGlobals(JSC::VM&); + friend void JSBuiltinInternalFunctions::initialize(JSDOMGlobalObject&); + + JSBuiltinInternalFunctions m_builtinInternalFunctions; }; template<class ConstructorClass> - inline JSC::JSObject* getDOMConstructor(JSC::VM& vm, const JSDOMGlobalObject* globalObject) + inline JSC::JSObject* getDOMConstructor(JSC::VM& vm, const JSDOMGlobalObject& globalObject) { - if (JSC::JSObject* constructor = const_cast<JSDOMGlobalObject*>(globalObject)->constructors().get(ConstructorClass::info()).get()) + if (JSC::JSObject* constructor = const_cast<JSDOMGlobalObject&>(globalObject).constructors(NoLockingNecessary).get(ConstructorClass::info()).get()) return constructor; - JSC::JSObject* constructor = ConstructorClass::create(vm, ConstructorClass::createStructure(vm, const_cast<JSDOMGlobalObject*>(globalObject), globalObject->objectPrototype()), const_cast<JSDOMGlobalObject*>(globalObject)); - ASSERT(!const_cast<JSDOMGlobalObject*>(globalObject)->constructors().contains(ConstructorClass::info())); + JSC::JSObject* constructor = ConstructorClass::create(vm, ConstructorClass::createStructure(vm, const_cast<JSDOMGlobalObject&>(globalObject), ConstructorClass::prototypeForStructure(vm, globalObject)), const_cast<JSDOMGlobalObject&>(globalObject)); + ASSERT(!const_cast<JSDOMGlobalObject&>(globalObject).constructors(NoLockingNecessary).contains(ConstructorClass::info())); JSC::WriteBarrier<JSC::JSObject> temp; - const_cast<JSDOMGlobalObject*>(globalObject)->constructors().add(ConstructorClass::info(), temp).iterator->value.set(vm, globalObject, constructor); + JSDOMGlobalObject& mutableGlobalObject = const_cast<JSDOMGlobalObject&>(globalObject); + auto locker = JSC::lockDuringMarking(vm.heap, mutableGlobalObject.gcLock()); + mutableGlobalObject.constructors(locker).add(ConstructorClass::info(), temp).iterator->value.set(vm, &globalObject, constructor); return constructor; } @@ -105,5 +129,3 @@ namespace WebCore { JSDOMGlobalObject* toJSDOMGlobalObject(ScriptExecutionContext*, DOMWrapperWorld&); } // namespace WebCore - -#endif // JSDOMGlobalObject_h diff --git a/Source/WebCore/bindings/js/JSDOMGlobalObjectTask.cpp b/Source/WebCore/bindings/js/JSDOMGlobalObjectTask.cpp index 847dbd164..0be269683 100644 --- a/Source/WebCore/bindings/js/JSDOMGlobalObjectTask.cpp +++ b/Source/WebCore/bindings/js/JSDOMGlobalObjectTask.cpp @@ -38,9 +38,9 @@ namespace WebCore { class JSGlobalObjectCallback final : public RefCounted<JSGlobalObjectCallback>, private ActiveDOMCallback { public: - static PassRefPtr<JSGlobalObjectCallback> create(JSDOMGlobalObject* globalObject, PassRefPtr<Microtask> task) + static Ref<JSGlobalObjectCallback> create(JSDOMGlobalObject* globalObject, Ref<Microtask>&& task) { - return adoptRef(new JSGlobalObjectCallback(globalObject, task)); + return adoptRef(*new JSGlobalObjectCallback(globalObject, WTFMove(task))); } void call() @@ -48,8 +48,10 @@ public: if (!canInvokeCallback()) return; - Ref<JSGlobalObjectCallback> protect(*this); - JSLockHolder lock(m_globalObject->vm()); + Ref<JSGlobalObjectCallback> protectedThis(*this); + VM& vm = m_globalObject->vm(); + JSLockHolder lock(vm); + auto scope = DECLARE_THROW_SCOPE(vm); ExecState* exec = m_globalObject->globalExec(); @@ -60,37 +62,32 @@ public: // When on the main thread (e.g. the document's thread), we need to make sure to // push the current ExecState on to the JSMainThreadExecState stack. - if (context->isDocument()) { - JSMainThreadExecState currentState(exec); - m_task->run(exec); - } else + if (context->isDocument()) + JSMainThreadExecState::runTask(exec, m_task); + else m_task->run(exec); + ASSERT_UNUSED(scope, !scope.exception()); } private: - JSGlobalObjectCallback(JSDOMGlobalObject* globalObject, PassRefPtr<Microtask> task) + JSGlobalObjectCallback(JSDOMGlobalObject* globalObject, Ref<Microtask>&& task) : ActiveDOMCallback(globalObject->scriptExecutionContext()) , m_globalObject(globalObject->vm(), globalObject) - , m_task(task) + , m_task(WTFMove(task)) { } Strong<JSDOMGlobalObject> m_globalObject; - RefPtr<Microtask> m_task; + Ref<Microtask> m_task; }; -JSGlobalObjectTask::JSGlobalObjectTask(JSDOMGlobalObject* globalObject, PassRefPtr<Microtask> task) - : m_callback(JSGlobalObjectCallback::create(globalObject, task)) -{ -} - -JSGlobalObjectTask::~JSGlobalObjectTask() -{ -} - -void JSGlobalObjectTask::performTask(ScriptExecutionContext*) +JSGlobalObjectTask::JSGlobalObjectTask(JSDOMGlobalObject* globalObject, Ref<Microtask>&& task) + : ScriptExecutionContext::Task({ }) { - m_callback->call(); + RefPtr<JSGlobalObjectCallback> callback = JSGlobalObjectCallback::create(globalObject, WTFMove(task)); + m_task = [callback] (ScriptExecutionContext&) { + callback->call(); + }; } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMGlobalObjectTask.h b/Source/WebCore/bindings/js/JSDOMGlobalObjectTask.h index 3cb93f311..cc0ffb0e1 100644 --- a/Source/WebCore/bindings/js/JSDOMGlobalObjectTask.h +++ b/Source/WebCore/bindings/js/JSDOMGlobalObjectTask.h @@ -23,33 +23,16 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSDOMGlobalObjectTask_h -#define JSDOMGlobalObjectTask_h +#pragma once #include "JSDOMGlobalObject.h" #include "ScriptExecutionContext.h" namespace WebCore { -class JSGlobalObjectCallback; - -class JSGlobalObjectTask final : public ScriptExecutionContext::Task { +class JSGlobalObjectTask : public ScriptExecutionContext::Task { public: - static PassOwnPtr<JSGlobalObjectTask> create(JSDOMGlobalObject* globalObject, PassRefPtr<JSC::Microtask> task) - { - return adoptPtr(new JSGlobalObjectTask(globalObject, task)); - } - - virtual ~JSGlobalObjectTask(); - -private: - JSGlobalObjectTask(JSDOMGlobalObject*, PassRefPtr<JSC::Microtask>); - - virtual void performTask(ScriptExecutionContext*) override; - - RefPtr<JSGlobalObjectCallback> m_callback; + JSGlobalObjectTask(JSDOMGlobalObject*, Ref<JSC::Microtask>&&); }; } // namespace WebCore - -#endif // JSDOMGlobalObjectTask_h diff --git a/Source/WebCore/bindings/js/JSDOMIterator.cpp b/Source/WebCore/bindings/js/JSDOMIterator.cpp new file mode 100644 index 000000000..45ef3a755 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMIterator.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 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. ``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 + * 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 "JSDOMIterator.h" + +#include <builtins/BuiltinNames.h> +#include <runtime/ArrayPrototype.h> + +namespace WebCore { + +void addValueIterableMethods(JSC::JSGlobalObject& globalObject, JSC::JSObject& prototype) +{ + JSC::ArrayPrototype* arrayPrototype = globalObject.arrayPrototype(); + ASSERT(arrayPrototype); + + JSC::ExecState* state = globalObject.globalExec(); + ASSERT(state); + JSC::VM& vm = state->vm(); + + auto copyProperty = [&] (const JSC::Identifier& arrayIdentifier, const JSC::Identifier& otherIdentifier, unsigned attributes = 0) { + JSC::JSValue value = arrayPrototype->getDirect(vm, arrayIdentifier); + ASSERT(value); + prototype.putDirect(vm, otherIdentifier, value, attributes); + }; + + copyProperty(vm.propertyNames->builtinNames().entriesPrivateName(), vm.propertyNames->builtinNames().entriesPublicName()); + copyProperty(vm.propertyNames->builtinNames().forEachPrivateName(), vm.propertyNames->builtinNames().forEachPublicName()); + copyProperty(vm.propertyNames->builtinNames().keysPrivateName(), vm.propertyNames->builtinNames().keysPublicName()); + copyProperty(vm.propertyNames->builtinNames().valuesPrivateName(), vm.propertyNames->builtinNames().valuesPublicName()); + copyProperty(vm.propertyNames->builtinNames().valuesPrivateName(), vm.propertyNames->builtinNames().iteratorSymbol(), JSC::DontEnum); +} + +} diff --git a/Source/WebCore/bindings/js/JSDOMIterator.h b/Source/WebCore/bindings/js/JSDOMIterator.h new file mode 100644 index 000000000..101749ab9 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMIterator.h @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2016 Canon, Inc. All rights reserved. + * Copyright (C) 2016 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 CANON INC. ``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 CANON INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "JSDOMConvert.h" +#include <runtime/IteratorPrototype.h> +#include <runtime/JSDestructibleObject.h> +#include <type_traits> + +namespace WebCore { + +void addValueIterableMethods(JSC::JSGlobalObject&, JSC::JSObject&); + +enum class JSDOMIteratorType { Set, Map }; + +// struct IteratorTraits { +// static constexpr JSDOMIteratorType type = [Map|Set]; +// using KeyType = [IDLType|void]; +// using ValueType = [IDLType]; +// }; + +template<typename T, typename U = void> using EnableIfMap = typename std::enable_if<T::type == JSDOMIteratorType::Map, U>::type; +template<typename T, typename U = void> using EnableIfSet = typename std::enable_if<T::type == JSDOMIteratorType::Set, U>::type; + +template<typename JSWrapper, typename IteratorTraits> class JSDOMIteratorPrototype : public JSC::JSNonFinalObject { +public: + using Base = JSC::JSNonFinalObject; + using DOMWrapped = typename JSWrapper::DOMWrapped; + + static JSDOMIteratorPrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure) + { + JSDOMIteratorPrototype* prototype = new (NotNull, JSC::allocateCell<JSDOMIteratorPrototype>(vm.heap)) JSDOMIteratorPrototype(vm, structure); + prototype->finishCreation(vm, globalObject); + return prototype; + } + + DECLARE_INFO; + + static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) + { + return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); + } + + static JSC::EncodedJSValue JSC_HOST_CALL next(JSC::ExecState*); + +private: + JSDOMIteratorPrototype(JSC::VM& vm, JSC::Structure* structure) : Base(vm, structure) { } + + void finishCreation(JSC::VM&, JSC::JSGlobalObject*); +}; + +enum class IterationKind { Key, Value, KeyValue }; + +template<typename JSWrapper, typename IteratorTraits> class JSDOMIterator : public JSDOMObject { +public: + using Base = JSDOMObject; + + using Wrapper = JSWrapper; + using Traits = IteratorTraits; + + using DOMWrapped = typename Wrapper::DOMWrapped; + using Prototype = JSDOMIteratorPrototype<Wrapper, Traits>; + + DECLARE_INFO; + + static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) + { + return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); + } + + static JSDOMIterator* create(JSC::VM& vm, JSC::Structure* structure, JSWrapper& iteratedObject, IterationKind kind) + { + JSDOMIterator* instance = new (NotNull, JSC::allocateCell<JSDOMIterator>(vm.heap)) JSDOMIterator(structure, iteratedObject, kind); + instance->finishCreation(vm); + return instance; + } + + static Prototype* createPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject) + { + return Prototype::create(vm, globalObject, Prototype::createStructure(vm, globalObject, globalObject->iteratorPrototype())); + } + + JSC::JSValue next(JSC::ExecState&); + +private: + JSDOMIterator(JSC::Structure* structure, JSWrapper& iteratedObject, IterationKind kind) + : Base(structure, *iteratedObject.globalObject()) + , m_iterator(iteratedObject.wrapped().createIterator()) + , m_kind(kind) + { + } + + template<typename IteratorValue, typename T = Traits> EnableIfMap<T, JSC::JSValue> asJS(JSC::ExecState&, IteratorValue&); + template<typename IteratorValue, typename T = Traits> EnableIfSet<T, JSC::JSValue> asJS(JSC::ExecState&, IteratorValue&); + + static void destroy(JSC::JSCell*); + + std::optional<typename DOMWrapped::Iterator> m_iterator; + IterationKind m_kind; +}; + +inline JSC::JSValue jsPair(JSC::ExecState& state, JSDOMGlobalObject& globalObject, JSC::JSValue value1, JSC::JSValue value2) +{ + JSC::MarkedArgumentBuffer arguments; + arguments.append(value1); + arguments.append(value2); + return constructArray(&state, nullptr, &globalObject, arguments); +} + +template<typename FirstType, typename SecondType, typename T, typename U> +inline JSC::JSValue jsPair(JSC::ExecState& state, JSDOMGlobalObject& globalObject, const T& value1, const U& value2) +{ + return jsPair(state, globalObject, toJS<FirstType>(state, globalObject, value1), toJS<SecondType>(state, globalObject, value2)); +} + +template<typename JSIterator> JSC::JSValue iteratorCreate(typename JSIterator::Wrapper&, IterationKind); +template<typename JSIterator> JSC::JSValue iteratorForEach(JSC::ExecState&, typename JSIterator::Wrapper&, JSC::ThrowScope&); + +template<typename JSIterator> JSC::JSValue iteratorCreate(typename JSIterator::Wrapper& thisObject, IterationKind kind) +{ + ASSERT(thisObject.globalObject()); + JSDOMGlobalObject& globalObject = *thisObject.globalObject(); + return JSIterator::create(globalObject.vm(), getDOMStructure<JSIterator>(globalObject.vm(), globalObject), thisObject, kind); +} + +template<typename JSWrapper, typename IteratorTraits> +template<typename IteratorValue, typename T> inline EnableIfMap<T, JSC::JSValue> JSDOMIterator<JSWrapper, IteratorTraits>::asJS(JSC::ExecState& state, IteratorValue& value) +{ + ASSERT(value); + + switch (m_kind) { + case IterationKind::Key: + return toJS<typename Traits::KeyType>(state, *globalObject(), value->key); + case IterationKind::Value: + return toJS<typename Traits::ValueType>(state, *globalObject(), value->value); + case IterationKind::KeyValue: + return jsPair<typename Traits::KeyType, typename Traits::ValueType>(state, *globalObject(), value->key, value->value); + }; + + ASSERT_NOT_REACHED(); + return { }; +} + +template<typename JSWrapper, typename IteratorTraits> +template<typename IteratorValue, typename T> inline EnableIfSet<T, JSC::JSValue> JSDOMIterator<JSWrapper, IteratorTraits>::asJS(JSC::ExecState& state, IteratorValue& value) +{ + ASSERT(value); + + auto globalObject = this->globalObject(); + auto result = toJS<typename Traits::ValueType>(state, *globalObject, value); + + switch (m_kind) { + case IterationKind::Key: + case IterationKind::Value: + return result; + case IterationKind::KeyValue: + return jsPair(state, *globalObject, result, result); + }; + + ASSERT_NOT_REACHED(); + return { }; +} + +template<typename JSIterator, typename IteratorValue> EnableIfMap<typename JSIterator::Traits> appendForEachArguments(JSC::ExecState& state, JSDOMGlobalObject& globalObject, JSC::MarkedArgumentBuffer& arguments, IteratorValue& value) +{ + ASSERT(value); + arguments.append(toJS<typename JSIterator::Traits::ValueType>(state, globalObject, value->value)); + arguments.append(toJS<typename JSIterator::Traits::KeyType>(state, globalObject, value->key)); +} + +template<typename JSIterator, typename IteratorValue> EnableIfSet<typename JSIterator::Traits> appendForEachArguments(JSC::ExecState& state, JSDOMGlobalObject& globalObject, JSC::MarkedArgumentBuffer& arguments, IteratorValue& value) +{ + ASSERT(value); + auto argument = toJS<typename JSIterator::Traits::ValueType>(state, globalObject, value); + arguments.append(argument); + arguments.append(argument); +} + +template<typename JSIterator> JSC::JSValue iteratorForEach(JSC::ExecState& state, typename JSIterator::Wrapper& thisObject, JSC::ThrowScope& scope) +{ + JSC::JSValue callback = state.argument(0); + JSC::JSValue thisValue = state.argument(1); + + JSC::CallData callData; + JSC::CallType callType = JSC::getCallData(callback, callData); + if (callType == JSC::CallType::None) + return throwTypeError(&state, scope, ASCIILiteral("Cannot call callback")); + + auto iterator = thisObject.wrapped().createIterator(); + while (auto value = iterator.next()) { + JSC::MarkedArgumentBuffer arguments; + appendForEachArguments<JSIterator>(state, *thisObject.globalObject(), arguments, value); + arguments.append(&thisObject); + JSC::call(&state, callback, callType, callData, thisValue, arguments); + if (UNLIKELY(scope.exception())) + break; + } + return JSC::jsUndefined(); +} + +template<typename JSWrapper, typename IteratorTraits> +void JSDOMIterator<JSWrapper, IteratorTraits>::destroy(JSCell* cell) +{ + JSDOMIterator<JSWrapper, IteratorTraits>* thisObject = static_cast<JSDOMIterator<JSWrapper, IteratorTraits>*>(cell); + thisObject->JSDOMIterator<JSWrapper, IteratorTraits>::~JSDOMIterator(); +} + +template<typename JSWrapper, typename IteratorTraits> +JSC::JSValue JSDOMIterator<JSWrapper, IteratorTraits>::next(JSC::ExecState& state) +{ + if (m_iterator) { + auto iteratorValue = m_iterator->next(); + if (iteratorValue) + return createIteratorResultObject(&state, asJS(state, iteratorValue), false); + m_iterator = std::nullopt; + } + return createIteratorResultObject(&state, JSC::jsUndefined(), true); +} + +template<typename JSWrapper, typename IteratorTraits> +JSC::EncodedJSValue JSC_HOST_CALL JSDOMIteratorPrototype<JSWrapper, IteratorTraits>::next(JSC::ExecState* state) +{ + JSC::VM& vm = state->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto iterator = jsDynamicDowncast<JSDOMIterator<JSWrapper, IteratorTraits>*>(vm, state->thisValue()); + if (!iterator) + return JSC::JSValue::encode(throwTypeError(state, scope, ASCIILiteral("Cannot call next() on a non-Iterator object"))); + + return JSC::JSValue::encode(iterator->next(*state)); +} + +template<typename JSWrapper, typename IteratorTraits> +void JSDOMIteratorPrototype<JSWrapper, IteratorTraits>::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject) +{ + Base::finishCreation(vm); + ASSERT(inherits(vm, info())); + + JSC_NATIVE_INTRINSIC_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->next, next, 0, 0, JSC::NoIntrinsic); +} + +} diff --git a/Source/WebCore/bindings/js/JSDOMMimeTypeArrayCustom.cpp b/Source/WebCore/bindings/js/JSDOMMimeTypeArrayCustom.cpp deleted file mode 100644 index e1c910590..000000000 --- a/Source/WebCore/bindings/js/JSDOMMimeTypeArrayCustom.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) - * Copyright (C) 2008 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include "JSDOMMimeTypeArray.h" - -#include "DOMMimeTypeArray.h" -#include "JSDOMMimeType.h" -#include <wtf/text/AtomicString.h> - -namespace WebCore { - -using namespace JSC; - -bool JSDOMMimeTypeArray::canGetItemsForName(ExecState*, DOMMimeTypeArray* mimeTypeArray, PropertyName propertyName) -{ - return mimeTypeArray->canGetItemsForName(propertyNameToAtomicString(propertyName)); -} - -EncodedJSValue JSDOMMimeTypeArray::nameGetter(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName propertyName) -{ - JSDOMMimeTypeArray* thisObj = jsDynamicCast<JSDOMMimeTypeArray*>(JSValue::decode(slotBase)); - if (!thisObj) - return throwVMTypeError(exec); - return JSValue::encode(toJS(exec, thisObj->globalObject(), thisObj->impl().namedItem(propertyNameToAtomicString(propertyName)))); -} - -} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMNamedConstructor.h b/Source/WebCore/bindings/js/JSDOMNamedConstructor.h new file mode 100644 index 000000000..265e6d3e3 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMNamedConstructor.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2015, 2016 Canon Inc. All rights reserved. + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "JSDOMConstructorWithDocument.h" + +namespace WebCore { + +// FIMXE: Why can't named constructors be used with workers? +template<typename JSClass> class JSDOMNamedConstructor : public JSDOMConstructorWithDocument { +public: + using Base = JSDOMConstructorWithDocument; + + static JSDOMNamedConstructor* create(JSC::VM&, JSC::Structure*, JSDOMGlobalObject&); + static JSC::Structure* createStructure(JSC::VM&, JSC::JSGlobalObject&, JSC::JSValue prototype); + + DECLARE_INFO; + + // Must be defined for each specialization class. + static JSC::JSValue prototypeForStructure(JSC::VM&, const JSDOMGlobalObject&); + +private: + JSDOMNamedConstructor(JSC::Structure* structure, JSDOMGlobalObject& globalObject) + : Base(structure, globalObject) + { + } + + void finishCreation(JSC::VM&, JSDOMGlobalObject&); + static JSC::ConstructType getConstructData(JSC::JSCell*, JSC::ConstructData&); + + // Usually defined for each specialization class. + void initializeProperties(JSC::VM&, JSDOMGlobalObject&) { } + // Must be defined for each specialization class. + static JSC::EncodedJSValue JSC_HOST_CALL construct(JSC::ExecState*); +}; + +template<typename JSClass> inline JSDOMNamedConstructor<JSClass>* JSDOMNamedConstructor<JSClass>::create(JSC::VM& vm, JSC::Structure* structure, JSDOMGlobalObject& globalObject) +{ + JSDOMNamedConstructor* constructor = new (NotNull, JSC::allocateCell<JSDOMNamedConstructor>(vm.heap)) JSDOMNamedConstructor(structure, globalObject); + constructor->finishCreation(vm, globalObject); + return constructor; +} + +template<typename JSClass> inline JSC::Structure* JSDOMNamedConstructor<JSClass>::createStructure(JSC::VM& vm, JSC::JSGlobalObject& globalObject, JSC::JSValue prototype) +{ + return JSC::Structure::create(vm, &globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); +} + +template<typename JSClass> inline void JSDOMNamedConstructor<JSClass>::finishCreation(JSC::VM& vm, JSDOMGlobalObject& globalObject) +{ + Base::finishCreation(globalObject); + ASSERT(inherits(vm, info())); + initializeProperties(vm, globalObject); +} + +template<typename JSClass> inline JSC::ConstructType JSDOMNamedConstructor<JSClass>::getConstructData(JSC::JSCell*, JSC::ConstructData& constructData) +{ + constructData.native.function = construct; + return JSC::ConstructType::Host; +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMPluginArrayCustom.cpp b/Source/WebCore/bindings/js/JSDOMPluginArrayCustom.cpp deleted file mode 100644 index 807f63afe..000000000 --- a/Source/WebCore/bindings/js/JSDOMPluginArrayCustom.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) - * Copyright (C) 2008 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include "JSDOMPluginArray.h" - -#include "DOMPluginArray.h" -#include "JSDOMPlugin.h" -#include <wtf/text/AtomicString.h> - -namespace WebCore { - -using namespace JSC; - -bool JSDOMPluginArray::canGetItemsForName(ExecState*, DOMPluginArray* pluginArray, PropertyName propertyName) -{ - return pluginArray->canGetItemsForName(propertyNameToAtomicString(propertyName)); -} - -EncodedJSValue JSDOMPluginArray::nameGetter(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName propertyName) -{ - JSDOMPluginArray* thisObj = jsCast<JSDOMPluginArray*>(JSValue::decode(slotBase)); - return JSValue::encode(toJS(exec, thisObj->globalObject(), thisObj->impl().namedItem(propertyNameToAtomicString(propertyName)))); -} - -} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMPromise.cpp b/Source/WebCore/bindings/js/JSDOMPromise.cpp index fa5aa95b9..188d20fef 100644 --- a/Source/WebCore/bindings/js/JSDOMPromise.cpp +++ b/Source/WebCore/bindings/js/JSDOMPromise.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,47 +26,200 @@ #include "config.h" #include "JSDOMPromise.h" +#include "ExceptionCode.h" +#include "JSDOMError.h" +#include "JSDOMWindow.h" +#include <builtins/BuiltinNames.h> +#include <runtime/Exception.h> +#include <runtime/JSONObject.h> +#include <runtime/JSPromiseConstructor.h> + using namespace JSC; namespace WebCore { -DeferredWrapper::DeferredWrapper(ExecState* exec, JSDOMGlobalObject* globalObject) - : m_globalObject(exec->vm(), globalObject) - , m_deferred(exec->vm(), JSPromiseDeferred::create(exec, globalObject)) +DeferredPromise::DeferredPromise(JSDOMGlobalObject& globalObject, JSPromiseDeferred& promiseDeferred) + : ActiveDOMCallback(globalObject.scriptExecutionContext()) + , m_deferred(&promiseDeferred) + , m_globalObject(&globalObject) +{ + auto locker = lockDuringMarking(globalObject.vm().heap, globalObject.gcLock()); + globalObject.vm().heap.writeBarrier(&globalObject, &promiseDeferred); + globalObject.deferredPromises(locker).add(this); +} + +DeferredPromise::~DeferredPromise() +{ + clear(); +} + +void DeferredPromise::clear() { + ASSERT(!m_deferred || m_globalObject); + if (m_deferred && m_globalObject) { + auto locker = lockDuringMarking(m_globalObject->vm().heap, m_globalObject->gcLock()); + m_globalObject->deferredPromises(locker).remove(this); + } + m_deferred.clear(); } -JSObject* DeferredWrapper::promise() const +void DeferredPromise::contextDestroyed() { + ActiveDOMCallback::contextDestroyed(); + clear(); +} + +JSC::JSValue DeferredPromise::promise() const +{ + ASSERT(m_deferred); return m_deferred->promise(); } -void DeferredWrapper::resolve(ExecState* exec, JSValue resolution) +void DeferredPromise::callFunction(ExecState& exec, JSValue function, JSValue resolution) { - JSValue deferredResolve = m_deferred->resolve(); + if (!canInvokeCallback()) + return; - CallData resolveCallData; - CallType resolveCallType = getCallData(deferredResolve, resolveCallData); - ASSERT(resolveCallType != CallTypeNone); + CallData callData; + CallType callType = getCallData(function, callData); + ASSERT(callType != CallType::None); MarkedArgumentBuffer arguments; arguments.append(resolution); - call(exec, deferredResolve, resolveCallType, resolveCallData, jsUndefined(), arguments); + call(&exec, function, callType, callData, jsUndefined(), arguments); + + clear(); } -void DeferredWrapper::reject(ExecState* exec, JSValue reason) +void DeferredPromise::reject() { - JSValue deferredReject = m_deferred->reject(); + if (isSuspended()) + return; - CallData rejectCallData; - CallType rejectCallType = getCallData(deferredReject, rejectCallData); - ASSERT(rejectCallType != CallTypeNone); + ASSERT(m_deferred); + ASSERT(m_globalObject); + auto& state = *m_globalObject->globalExec(); + JSC::JSLockHolder locker(&state); + reject(state, JSC::jsUndefined()); +} + +void DeferredPromise::reject(std::nullptr_t) +{ + if (isSuspended()) + return; + + ASSERT(m_deferred); + ASSERT(m_globalObject); + auto& state = *m_globalObject->globalExec(); + JSC::JSLockHolder locker(&state); + reject(state, JSC::jsNull()); +} + +void DeferredPromise::reject(Exception&& exception) +{ + if (isSuspended()) + return; + + ASSERT(m_deferred); + ASSERT(m_globalObject); + auto& state = *m_globalObject->globalExec(); + JSC::JSLockHolder locker(&state); + reject(state, createDOMException(state, WTFMove(exception))); +} + +void DeferredPromise::reject(ExceptionCode ec, const String& message) +{ + if (isSuspended()) + return; + + ASSERT(m_deferred); + ASSERT(m_globalObject); + JSC::ExecState* state = m_globalObject->globalExec(); + JSC::JSLockHolder locker(state); + reject(*state, createDOMException(state, ec, message)); +} + +void DeferredPromise::reject(const JSC::PrivateName& privateName) +{ + if (isSuspended()) + return; + + ASSERT(m_deferred); + ASSERT(m_globalObject); + JSC::ExecState* state = m_globalObject->globalExec(); + JSC::JSLockHolder locker(state); + reject(*state, JSC::Symbol::create(state->vm(), privateName.uid())); +} + +void rejectPromiseWithExceptionIfAny(JSC::ExecState& state, JSDOMGlobalObject& globalObject, JSPromiseDeferred& promiseDeferred) +{ + VM& vm = state.vm(); + auto scope = DECLARE_CATCH_SCOPE(vm); + + if (LIKELY(!scope.exception())) + return; + + JSValue error = scope.exception()->value(); + scope.clearException(); + + DeferredPromise::create(globalObject, promiseDeferred)->reject<IDLAny>(error); +} + +Ref<DeferredPromise> createDeferredPromise(JSC::ExecState& state, JSDOMWindow& domWindow) +{ + JSC::JSPromiseDeferred* deferred = JSC::JSPromiseDeferred::create(&state, &domWindow); + // deferred can only be null in workers. + ASSERT(deferred); + return DeferredPromise::create(domWindow, *deferred); +} + +JSC::EncodedJSValue createRejectedPromiseWithTypeError(JSC::ExecState& state, const String& errorMessage) +{ + ASSERT(state.lexicalGlobalObject()); + auto& globalObject = *state.lexicalGlobalObject(); + + auto promiseConstructor = globalObject.promiseConstructor(); + auto rejectFunction = promiseConstructor->get(&state, state.vm().propertyNames->builtinNames().rejectPrivateName()); + auto rejectionValue = createTypeError(&state, errorMessage); + + CallData callData; + auto callType = getCallData(rejectFunction, callData); + ASSERT(callType != CallType::None); MarkedArgumentBuffer arguments; - arguments.append(reason); + arguments.append(rejectionValue); + + return JSValue::encode(call(&state, rejectFunction, callType, callData, promiseConstructor, arguments)); +} - call(exec, deferredReject, rejectCallType, rejectCallData, jsUndefined(), arguments); +static inline JSC::JSValue parseAsJSON(JSC::ExecState* state, const String& data) +{ + JSC::JSLockHolder lock(state); + return JSC::JSONParse(state, data); +} + +void fulfillPromiseWithJSON(Ref<DeferredPromise>&& promise, const String& data) +{ + JSC::JSValue value = parseAsJSON(promise->globalObject()->globalExec(), data); + if (!value) + promise->reject(SYNTAX_ERR); + else + promise->resolve<IDLAny>(value); +} + +void fulfillPromiseWithArrayBuffer(Ref<DeferredPromise>&& promise, ArrayBuffer* arrayBuffer) +{ + if (!arrayBuffer) { + promise->reject<IDLAny>(createOutOfMemoryError(promise->globalObject()->globalExec())); + return; + } + promise->resolve<IDLInterface<ArrayBuffer>>(*arrayBuffer); +} + +void fulfillPromiseWithArrayBuffer(Ref<DeferredPromise>&& promise, const void* data, size_t length) +{ + fulfillPromiseWithArrayBuffer(WTFMove(promise), ArrayBuffer::tryCreate(data, length).get()); } } diff --git a/Source/WebCore/bindings/js/JSDOMPromise.h b/Source/WebCore/bindings/js/JSDOMPromise.h index d431c4e5d..39530cc6e 100644 --- a/Source/WebCore/bindings/js/JSDOMPromise.h +++ b/Source/WebCore/bindings/js/JSDOMPromise.h @@ -23,87 +23,245 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSDOMPromise_h -#define JSDOMPromise_h +#pragma once -#include "JSCryptoKey.h" -#include "JSCryptoKeyPair.h" -#include "JSDOMBinding.h" +#include "ActiveDOMCallback.h" +#include "JSDOMConvert.h" #include <heap/StrongInlines.h> #include <runtime/JSPromiseDeferred.h> namespace WebCore { -class DeferredWrapper { +class DeferredPromise : public RefCounted<DeferredPromise>, public ActiveDOMCallback { public: - DeferredWrapper(JSC::ExecState*, JSDOMGlobalObject*); + static Ref<DeferredPromise> create(JSDOMGlobalObject& globalObject, JSC::JSPromiseDeferred& deferred) + { + return adoptRef(*new DeferredPromise(globalObject, deferred)); + } - template<class ResolveResultType> - void resolve(const ResolveResultType&); + ~DeferredPromise(); - template<class RejectResultType> - void reject(const RejectResultType&); + template<class IDLType> + void resolve(typename IDLType::ParameterType value) + { + if (isSuspended()) + return; + ASSERT(m_deferred); + ASSERT(m_globalObject); + JSC::ExecState* exec = m_globalObject->globalExec(); + JSC::JSLockHolder locker(exec); + resolve(*exec, toJS<IDLType>(*exec, *m_globalObject.get(), std::forward<typename IDLType::ParameterType>(value))); + } - JSC::JSObject* promise() const; + void resolve() + { + if (isSuspended()) + return; + ASSERT(m_deferred); + ASSERT(m_globalObject); + JSC::ExecState* exec = m_globalObject->globalExec(); + JSC::JSLockHolder locker(exec); + resolve(*exec, JSC::jsUndefined()); + } + + template<class IDLType> + void resolveWithNewlyCreated(typename IDLType::ParameterType value) + { + if (isSuspended()) + return; + ASSERT(m_deferred); + ASSERT(m_globalObject); + JSC::ExecState* exec = m_globalObject->globalExec(); + JSC::JSLockHolder locker(exec); + resolve(*exec, toJSNewlyCreated<IDLType>(*exec, *m_globalObject.get(), std::forward<typename IDLType::ParameterType>(value))); + } + + template<class IDLType> + void reject(typename IDLType::ParameterType value) + { + if (isSuspended()) + return; + ASSERT(m_deferred); + ASSERT(m_globalObject); + JSC::ExecState* exec = m_globalObject->globalExec(); + JSC::JSLockHolder locker(exec); + reject(*exec, toJS<IDLType>(*exec, *m_globalObject.get(), std::forward<typename IDLType::ParameterType>(value))); + } + + void reject(); + void reject(std::nullptr_t); + void reject(Exception&&); + void reject(ExceptionCode, const String& = { }); + void reject(const JSC::PrivateName&); + + template<typename Callback> + void resolveWithCallback(Callback callback) + { + if (isSuspended()) + return; + ASSERT(m_deferred); + ASSERT(m_globalObject); + JSC::ExecState* exec = m_globalObject->globalExec(); + JSC::JSLockHolder locker(exec); + resolve(*exec, callback(*exec, *m_globalObject.get())); + } + + template<typename Callback> + void rejectWithCallback(Callback callback) + { + if (isSuspended()) + return; + ASSERT(m_deferred); + ASSERT(m_globalObject); + JSC::ExecState* exec = m_globalObject->globalExec(); + JSC::JSLockHolder locker(exec); + reject(*exec, callback(*exec, *m_globalObject.get())); + } + + JSC::JSValue promise() const; + + bool isSuspended() { return !m_deferred || !canInvokeCallback(); } // The wrapper world has gone away or active DOM objects have been suspended. + JSDOMGlobalObject* globalObject() { return m_globalObject.get(); } + + void visitAggregate(JSC::SlotVisitor& visitor) { visitor.append(m_deferred); } private: - void resolve(JSC::ExecState*, JSC::JSValue); - void reject(JSC::ExecState*, JSC::JSValue); + DeferredPromise(JSDOMGlobalObject&, JSC::JSPromiseDeferred&); + + void clear(); + void contextDestroyed() override; - JSC::Strong<JSDOMGlobalObject> m_globalObject; - JSC::Strong<JSC::JSPromiseDeferred> m_deferred; + void callFunction(JSC::ExecState&, JSC::JSValue function, JSC::JSValue resolution); + void resolve(JSC::ExecState& state, JSC::JSValue resolution) { callFunction(state, m_deferred->resolve(), resolution); } + void reject(JSC::ExecState& state, JSC::JSValue resolution) { callFunction(state, m_deferred->reject(), resolution); } + + JSC::Weak<JSC::JSPromiseDeferred> m_deferred; + JSC::Weak<JSDOMGlobalObject> m_globalObject; }; -template<class ResolveResultType> -inline void DeferredWrapper::resolve(const ResolveResultType& result) -{ - JSC::ExecState* exec = m_globalObject->globalExec(); - resolve(exec, toJS(exec, m_globalObject.get(), result)); -} +class DOMPromiseBase { +public: + DOMPromiseBase(Ref<DeferredPromise>&& genericPromise) + : m_promiseDeferred(WTFMove(genericPromise)) + { + } -template<class RejectResultType> -inline void DeferredWrapper::reject(const RejectResultType& result) -{ - JSC::ExecState* exec = m_globalObject->globalExec(); - reject(exec, toJS(exec, m_globalObject.get(), result)); -} + DOMPromiseBase(DOMPromiseBase&& promise) + : m_promiseDeferred(WTFMove(promise.m_promiseDeferred)) + { + } -template<> -inline void DeferredWrapper::reject(const std::nullptr_t&) -{ - JSC::ExecState* exec = m_globalObject->globalExec(); - reject(exec, JSC::jsNull()); -} + DOMPromiseBase(const DOMPromiseBase& other) + : m_promiseDeferred(other.m_promiseDeferred.copyRef()) + { + } -template<> -inline void DeferredWrapper::resolve<String>(const String& result) -{ - JSC::ExecState* exec = m_globalObject->globalExec(); - resolve(exec, jsString(exec, result)); -} + DOMPromiseBase& operator=(const DOMPromiseBase& other) + { + m_promiseDeferred = other.m_promiseDeferred.copyRef(); + return *this; + } -template<> -inline void DeferredWrapper::resolve<bool>(const bool& result) -{ - JSC::ExecState* exec = m_globalObject->globalExec(); - resolve(exec, JSC::jsBoolean(result)); -} + DOMPromiseBase& operator=(DOMPromiseBase&& other) + { + m_promiseDeferred = WTFMove(other.m_promiseDeferred); + return *this; + } + + void reject() + { + m_promiseDeferred->reject(); + } + + template<typename... ErrorType> + void reject(ErrorType&&... error) + { + m_promiseDeferred->reject(std::forward<ErrorType>(error)...); + } -template<> -inline void DeferredWrapper::resolve<Vector<unsigned char>>(const Vector<unsigned char>& result) + template<typename IDLType> + void rejectType(typename IDLType::ParameterType value) + { + m_promiseDeferred->reject<IDLType>(std::forward<typename IDLType::ParameterType>(value)); + } + + JSC::JSValue promise() const { return m_promiseDeferred->promise(); }; + +protected: + Ref<DeferredPromise> m_promiseDeferred; +}; + +template<typename IDLType> +class DOMPromise : public DOMPromiseBase { +public: + using DOMPromiseBase::DOMPromiseBase; + using DOMPromiseBase::operator=; + using DOMPromiseBase::promise; + using DOMPromiseBase::reject; + + void resolve(typename IDLType::ParameterType value) + { + m_promiseDeferred->resolve<IDLType>(std::forward<typename IDLType::ParameterType>(value)); + } +}; + +template<> class DOMPromise<void> : public DOMPromiseBase { +public: + using DOMPromiseBase::DOMPromiseBase; + using DOMPromiseBase::operator=; + using DOMPromiseBase::promise; + using DOMPromiseBase::reject; + + void resolve() + { + m_promiseDeferred->resolve(); + } +}; + + +Ref<DeferredPromise> createDeferredPromise(JSC::ExecState&, JSDOMWindow&); + +void fulfillPromiseWithJSON(Ref<DeferredPromise>&&, const String&); +void fulfillPromiseWithArrayBuffer(Ref<DeferredPromise>&&, ArrayBuffer*); +void fulfillPromiseWithArrayBuffer(Ref<DeferredPromise>&&, const void*, size_t); +void rejectPromiseWithExceptionIfAny(JSC::ExecState&, JSDOMGlobalObject&, JSC::JSPromiseDeferred&); +JSC::EncodedJSValue createRejectedPromiseWithTypeError(JSC::ExecState&, const String&); + +using PromiseFunction = void(JSC::ExecState&, Ref<DeferredPromise>&&); + +enum class PromiseExecutionScope { WindowOnly, WindowOrWorker }; + +template<PromiseFunction promiseFunction, PromiseExecutionScope executionScope> +inline JSC::JSValue callPromiseFunction(JSC::ExecState& state) { - JSC::ExecState* exec = m_globalObject->globalExec(); - RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(result.data(), result.size()); - resolve(exec, toJS(exec, m_globalObject.get(), buffer.get())); + JSC::VM& vm = state.vm(); + auto scope = DECLARE_CATCH_SCOPE(vm); + + JSDOMGlobalObject& globalObject = *JSC::jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject()); + JSC::JSPromiseDeferred* promiseDeferred = JSC::JSPromiseDeferred::create(&state, &globalObject); + + // promiseDeferred can be null when terminating a Worker abruptly. + if (executionScope == PromiseExecutionScope::WindowOrWorker && !promiseDeferred) + return JSC::jsUndefined(); + + promiseFunction(state, DeferredPromise::create(globalObject, *promiseDeferred)); + + rejectPromiseWithExceptionIfAny(state, globalObject, *promiseDeferred); + ASSERT_UNUSED(scope, !scope.exception()); + return promiseDeferred->promise(); } -template<> -inline void DeferredWrapper::reject<String>(const String& result) +using BindingPromiseFunction = JSC::EncodedJSValue(JSC::ExecState*, Ref<DeferredPromise>&&); +template<BindingPromiseFunction bindingFunction> +inline void bindingPromiseFunctionAdapter(JSC::ExecState& state, Ref<DeferredPromise>&& promise) { - JSC::ExecState* exec = m_globalObject->globalExec(); - reject(exec, jsString(exec, result)); + bindingFunction(&state, WTFMove(promise)); } +template<BindingPromiseFunction bindingPromiseFunction, PromiseExecutionScope executionScope> +inline JSC::JSValue callPromiseFunction(JSC::ExecState& state) +{ + return callPromiseFunction<bindingPromiseFunctionAdapter<bindingPromiseFunction>, executionScope>(state); } -#endif // JSDOMPromise_h +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMStringMapCustom.cpp b/Source/WebCore/bindings/js/JSDOMStringMapCustom.cpp index 6ff6b9c05..b3cc70d73 100644 --- a/Source/WebCore/bindings/js/JSDOMStringMapCustom.cpp +++ b/Source/WebCore/bindings/js/JSDOMStringMapCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,64 +26,51 @@ #include "config.h" #include "JSDOMStringMap.h" +#include "CustomElementReactionQueue.h" #include "DOMStringMap.h" -#include "Element.h" +#include "JSDOMConvert.h" #include "JSNode.h" +#include <runtime/IdentifierInlines.h> #include <wtf/text/AtomicString.h> using namespace JSC; namespace WebCore { -bool JSDOMStringMap::canGetItemsForName(ExecState*, DOMStringMap* impl, PropertyName propertyName) +bool JSDOMStringMap::deleteProperty(JSCell* cell, ExecState* state, PropertyName propertyName) { - return impl->contains(propertyNameToAtomicString(propertyName)); + CustomElementReactionStack customElementReactionStack; + if (propertyName.isSymbol()) + return Base::deleteProperty(cell, state, propertyName); + return jsCast<JSDOMStringMap*>(cell)->wrapped().deleteItem(propertyNameToString(propertyName)); } -EncodedJSValue JSDOMStringMap::nameGetter(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName propertyName) +bool JSDOMStringMap::deletePropertyByIndex(JSCell* cell, ExecState* state, unsigned index) { - JSDOMStringMap* thisObj = jsCast<JSDOMStringMap*>(JSValue::decode(slotBase)); - return JSValue::encode(jsStringWithCache(exec, thisObj->impl().item(propertyNameToAtomicString(propertyName)))); + return deleteProperty(cell, state, Identifier::from(state, index)); } -void JSDOMStringMap::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) +bool JSDOMStringMap::putDelegate(ExecState* state, PropertyName propertyName, JSValue value, PutPropertySlot&, bool& putResult) { - JSDOMStringMap* thisObject = jsCast<JSDOMStringMap*>(object); - Vector<String> names; - thisObject->m_impl->getNames(names); - size_t length = names.size(); - for (size_t i = 0; i < length; ++i) - propertyNames.add(Identifier(exec, names[i])); + VM& vm = state->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); - Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode); -} - -bool JSDOMStringMap::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) -{ - JSDOMStringMap* thisObject = jsCast<JSDOMStringMap*>(cell); - AtomicString stringName = propertyNameToAtomicString(propertyName); - if (!thisObject->m_impl->contains(stringName)) + if (propertyName.isSymbol()) return false; - ExceptionCode ec = 0; - thisObject->m_impl->deleteItem(stringName, ec); - setDOMException(exec, ec); - return !ec; -} -bool JSDOMStringMap::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned index) -{ - return deleteProperty(cell, exec, Identifier::from(exec, index)); -} + CustomElementReactionStack customElementReactionStack; -bool JSDOMStringMap::putDelegate(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot&) -{ - String stringValue = value.toString(exec)->value(exec); - if (exec->hadException()) - return false; - ExceptionCode ec = 0; - impl().setItem(propertyNameToString(propertyName), stringValue, ec); - setDOMException(exec, ec); - return !ec; + String stringValue = value.toWTFString(state); + RETURN_IF_EXCEPTION(scope, true); + + auto result = wrapped().setItem(propertyNameToString(propertyName), WTFMove(stringValue)); + if (result.hasException()) { + propagateException(*state, scope, result.releaseException()); + return true; + } + + putResult = true; + return true; } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMWindowBase.cpp b/Source/WebCore/bindings/js/JSDOMWindowBase.cpp index c6739780b..45df5a8e0 100644 --- a/Source/WebCore/bindings/js/JSDOMWindowBase.cpp +++ b/Source/WebCore/bindings/js/JSDOMWindowBase.cpp @@ -1,8 +1,9 @@ /* * Copyright (C) 2000 Harri Porten (porten@kde.org) * Copyright (C) 2006 Jon Shier (jshier@iastate.edu) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reseved. + * Copyright (C) 2003-2009, 2014, 2016 Apple Inc. All rights reseved. * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org) + * Copyright (c) 2015 Canon Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,45 +24,60 @@ #include "config.h" #include "JSDOMWindowBase.h" +#include "ActiveDOMCallbackMicrotask.h" #include "Chrome.h" -#include "Console.h" +#include "CommonVM.h" #include "DOMWindow.h" #include "Frame.h" #include "InspectorController.h" +#include "JSDOMBindingSecurity.h" #include "JSDOMGlobalObjectTask.h" #include "JSDOMWindowCustom.h" +#include "JSMainThreadExecState.h" #include "JSNode.h" +#include "Language.h" #include "Logging.h" #include "Page.h" +#include "RuntimeApplicationChecks.h" #include "ScriptController.h" +#include "ScriptModuleLoader.h" #include "SecurityOrigin.h" #include "Settings.h" #include "WebCoreJSClientData.h" +#include <bytecode/CodeBlock.h> +#include <heap/StrongInlines.h> +#include <runtime/JSInternalPromiseDeferred.h> #include <runtime/Microtask.h> #include <wtf/MainThread.h> #if PLATFORM(IOS) #include "ChromeClient.h" -#include "WebSafeGCActivityCallbackIOS.h" -#include "WebSafeIncrementalSweeperIOS.h" #endif using namespace JSC; namespace WebCore { -static bool shouldAllowAccessFrom(const JSGlobalObject* thisObject, ExecState* exec) -{ - return BindingSecurity::shouldAllowAccessToDOMWindow(exec, asJSDOMWindow(thisObject)->impl()); -} - -const ClassInfo JSDOMWindowBase::s_info = { "Window", &JSDOMGlobalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSDOMWindowBase) }; - -const GlobalObjectMethodTable JSDOMWindowBase::s_globalObjectMethodTable = { &shouldAllowAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptExperimentsEnabled, &queueTaskToEventLoop, &shouldInterruptScriptBeforeTimeout }; - -JSDOMWindowBase::JSDOMWindowBase(VM& vm, Structure* structure, PassRefPtr<DOMWindow> window, JSDOMWindowShell* shell) - : JSDOMGlobalObject(vm, structure, &shell->world(), &s_globalObjectMethodTable) - , m_impl(window) +const ClassInfo JSDOMWindowBase::s_info = { "Window", &JSDOMGlobalObject::s_info, 0, CREATE_METHOD_TABLE(JSDOMWindowBase) }; + +const GlobalObjectMethodTable JSDOMWindowBase::s_globalObjectMethodTable = { + &supportsRichSourceInfo, + &shouldInterruptScript, + &javaScriptRuntimeFlags, + &queueTaskToEventLoop, + &shouldInterruptScriptBeforeTimeout, + &moduleLoaderImportModule, + &moduleLoaderResolve, + &moduleLoaderFetch, + nullptr, + &moduleLoaderEvaluate, + &defaultLanguage +}; + +JSDOMWindowBase::JSDOMWindowBase(VM& vm, Structure* structure, RefPtr<DOMWindow>&& window, JSDOMWindowShell* shell) + : JSDOMGlobalObject(vm, structure, shell->world(), &s_globalObjectMethodTable) + , m_windowCloseWatchpoints((window && window->frame()) ? IsWatched : IsInvalidated) + , m_wrapped(WTFMove(window)) , m_shell(shell) { } @@ -69,14 +85,24 @@ JSDOMWindowBase::JSDOMWindowBase(VM& vm, Structure* structure, PassRefPtr<DOMWin void JSDOMWindowBase::finishCreation(VM& vm, JSDOMWindowShell* shell) { Base::finishCreation(vm, shell); - ASSERT(inherits(info())); + ASSERT(inherits(vm, info())); GlobalPropertyInfo staticGlobals[] = { GlobalPropertyInfo(vm.propertyNames->document, jsNull(), DontDelete | ReadOnly), - GlobalPropertyInfo(vm.propertyNames->window, m_shell, DontDelete | ReadOnly) + GlobalPropertyInfo(vm.propertyNames->window, m_shell, DontDelete | ReadOnly), }; - + addStaticGlobals(staticGlobals, WTF_ARRAY_LENGTH(staticGlobals)); + + if (m_wrapped && m_wrapped->frame() && m_wrapped->frame()->settings().needsSiteSpecificQuirks()) + setNeedsSiteSpecificQuirks(true); +} + +void JSDOMWindowBase::visitChildren(JSCell* cell, SlotVisitor& visitor) +{ + JSDOMWindowBase* thisObject = jsCast<JSDOMWindowBase*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + Base::visitChildren(thisObject, visitor); } void JSDOMWindowBase::destroy(JSCell* cell) @@ -86,48 +112,31 @@ void JSDOMWindowBase::destroy(JSCell* cell) void JSDOMWindowBase::updateDocument() { - ASSERT(m_impl->document()); + // Since "document" property is defined as { configurable: false, writable: false, enumerable: true }, + // users cannot change its attributes further. + // Reaching here, the attributes of "document" property should be never changed. + ASSERT(m_wrapped->document()); ExecState* exec = globalExec(); - symbolTablePutWithAttributes(this, exec->vm(), exec->vm().propertyNames->document, toJS(exec, this, m_impl->document()), DontDelete | ReadOnly); + bool shouldThrowReadOnlyError = false; + bool ignoreReadOnlyErrors = true; + bool putResult = false; + symbolTablePutTouchWatchpointSet(this, exec, exec->vm().propertyNames->document, toJS(exec, this, m_wrapped->document()), shouldThrowReadOnlyError, ignoreReadOnlyErrors, putResult); } ScriptExecutionContext* JSDOMWindowBase::scriptExecutionContext() const { - return m_impl->document(); + return m_wrapped->document(); } void JSDOMWindowBase::printErrorMessage(const String& message) const { - printErrorMessageForFrame(impl().frame(), message); -} - -bool JSDOMWindowBase::supportsProfiling(const JSGlobalObject* object) -{ -#if !ENABLE(INSPECTOR) - UNUSED_PARAM(object); - return false; -#else - const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object); - Frame* frame = thisObject->impl().frame(); - if (!frame) - return false; - - Page* page = frame->page(); - if (!page) - return false; - - return page->inspectorController().profilerEnabled(); -#endif // ENABLE(INSPECTOR) + printErrorMessageForFrame(wrapped().frame(), message); } bool JSDOMWindowBase::supportsRichSourceInfo(const JSGlobalObject* object) { -#if !ENABLE(INSPECTOR) - UNUSED_PARAM(object); - return false; -#else const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object); - Frame* frame = thisObject->impl().frame(); + Frame* frame = thisObject->wrapped().frame(); if (!frame) return false; @@ -137,9 +146,7 @@ bool JSDOMWindowBase::supportsRichSourceInfo(const JSGlobalObject* object) bool enabled = page->inspectorController().enabled(); ASSERT(enabled || !thisObject->debugger()); - ASSERT(enabled || !supportsProfiling(thisObject)); return enabled; -#endif } static inline bool shouldInterruptScriptToPreventInfiniteRecursionWhenClosingPage(Page* page) @@ -157,16 +164,16 @@ static inline bool shouldInterruptScriptToPreventInfiniteRecursionWhenClosingPag bool JSDOMWindowBase::shouldInterruptScript(const JSGlobalObject* object) { const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object); - ASSERT(thisObject->impl().frame()); - Page* page = thisObject->impl().frame()->page(); - return shouldInterruptScriptToPreventInfiniteRecursionWhenClosingPage(page) || page->chrome().shouldInterruptJavaScript(); + ASSERT(thisObject->wrapped().frame()); + Page* page = thisObject->wrapped().frame()->page(); + return shouldInterruptScriptToPreventInfiniteRecursionWhenClosingPage(page); } bool JSDOMWindowBase::shouldInterruptScriptBeforeTimeout(const JSGlobalObject* object) { const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object); - ASSERT(thisObject->impl().frame()); - Page* page = thisObject->impl().frame()->page(); + ASSERT(thisObject->wrapped().frame()); + Page* page = thisObject->wrapped().frame()->page(); if (shouldInterruptScriptToPreventInfiniteRecursionWhenClosingPage(page)) return true; @@ -179,85 +186,79 @@ bool JSDOMWindowBase::shouldInterruptScriptBeforeTimeout(const JSGlobalObject* o return JSGlobalObject::shouldInterruptScriptBeforeTimeout(object); } -bool JSDOMWindowBase::javaScriptExperimentsEnabled(const JSGlobalObject* object) +RuntimeFlags JSDOMWindowBase::javaScriptRuntimeFlags(const JSGlobalObject* object) { const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object); - Frame* frame = thisObject->impl().frame(); + Frame* frame = thisObject->wrapped().frame(); if (!frame) - return false; - return frame->settings().javaScriptExperimentsEnabled(); + return RuntimeFlags(); + return frame->settings().javaScriptRuntimeFlags(); } -void JSDOMWindowBase::queueTaskToEventLoop(const JSGlobalObject* object, PassRefPtr<Microtask> task) -{ - const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object); - thisObject->scriptExecutionContext()->postTask(JSGlobalObjectTask::create((JSDOMWindowBase*)thisObject, task)); -} +class JSDOMWindowMicrotaskCallback : public RefCounted<JSDOMWindowMicrotaskCallback> { +public: + static Ref<JSDOMWindowMicrotaskCallback> create(JSDOMWindowBase* globalObject, Ref<JSC::Microtask>&& task) + { + return adoptRef(*new JSDOMWindowMicrotaskCallback(globalObject, WTFMove(task))); + } -void JSDOMWindowBase::willRemoveFromWindowShell() -{ - setCurrentEvent(0); -} + void call() + { + Ref<JSDOMWindowMicrotaskCallback> protectedThis(*this); + VM& vm = m_globalObject->vm(); + JSLockHolder lock(vm); + auto scope = DECLARE_THROW_SCOPE(vm); -JSDOMWindowShell* JSDOMWindowBase::shell() const -{ - return m_shell; -} + ExecState* exec = m_globalObject->globalExec(); -VM* JSDOMWindowBase::commonVM() -{ - ASSERT(isMainThread()); + JSMainThreadExecState::runTask(exec, m_task); -#if !PLATFORM(IOS) - static VM* vm = 0; -#else - VM*& vm = commonVMInternal(); -#endif - if (!vm) { - ScriptController::initializeThreading(); - vm = VM::createLeaked(LargeHeap).leakRef(); -#if PLATFORM(IOS) - PassOwnPtr<WebSafeGCActivityCallback> activityCallback = WebSafeGCActivityCallback::create(&vm->heap); - vm->heap.setActivityCallback(activityCallback); - PassOwnPtr<WebSafeIncrementalSweeper> incrementalSweeper = WebSafeIncrementalSweeper::create(&vm->heap); - vm->heap.setIncrementalSweeper(incrementalSweeper); - vm->makeUsableFromMultipleThreads(); - vm->heap.machineThreads().addCurrentThread(); -#else - vm->exclusiveThread = currentThread(); -#endif // !PLATFORM(IOS) - initNormalWorldClientData(vm); + ASSERT_UNUSED(scope, !scope.exception()); } - return vm; +private: + JSDOMWindowMicrotaskCallback(JSDOMWindowBase* globalObject, Ref<JSC::Microtask>&& task) + : m_globalObject(globalObject->vm(), globalObject) + , m_task(WTFMove(task)) + { + } + + Strong<JSDOMWindowBase> m_globalObject; + Ref<JSC::Microtask> m_task; +}; + +void JSDOMWindowBase::queueTaskToEventLoop(const JSGlobalObject* object, Ref<JSC::Microtask>&& task) +{ + const JSDOMWindowBase* thisObject = static_cast<const JSDOMWindowBase*>(object); + + RefPtr<JSDOMWindowMicrotaskCallback> callback = JSDOMWindowMicrotaskCallback::create((JSDOMWindowBase*)thisObject, WTFMove(task)); + auto microtask = std::make_unique<ActiveDOMCallbackMicrotask>(MicrotaskQueue::mainThreadQueue(), *thisObject->scriptExecutionContext(), [callback]() mutable { + callback->call(); + }); + + MicrotaskQueue::mainThreadQueue().append(WTFMove(microtask)); } -#if PLATFORM(IOS) -bool JSDOMWindowBase::commonVMExists() +void JSDOMWindowBase::willRemoveFromWindowShell() { - return commonVMInternal(); + setCurrentEvent(0); } -VM*& JSDOMWindowBase::commonVMInternal() +JSDOMWindowShell* JSDOMWindowBase::shell() const { - ASSERT(isMainThread()); - static VM* commonVM; - return commonVM; + return m_shell; } -#endif // JSDOMGlobalObject* is ignored, accessing a window in any context will // use that DOMWindow's prototype chain. -JSValue toJS(ExecState* exec, JSDOMGlobalObject*, DOMWindow* domWindow) +JSValue toJS(ExecState* exec, JSDOMGlobalObject*, DOMWindow& domWindow) { return toJS(exec, domWindow); } -JSValue toJS(ExecState* exec, DOMWindow* domWindow) +JSValue toJS(ExecState* exec, DOMWindow& domWindow) { - if (!domWindow) - return jsNull(); - Frame* frame = domWindow->frame(); + Frame* frame = domWindow.frame(); if (!frame) return jsNull(); return frame->script().windowShell(currentWorld(exec)); @@ -270,16 +271,124 @@ JSDOMWindow* toJSDOMWindow(Frame* frame, DOMWrapperWorld& world) return frame->script().windowShell(world)->window(); } -JSDOMWindow* toJSDOMWindow(JSValue value) +JSDOMWindow* toJSDOMWindow(JSC::VM& vm, JSValue value) { if (!value.isObject()) return 0; - const ClassInfo* classInfo = asObject(value)->classInfo(); - if (classInfo == JSDOMWindow::info()) - return jsCast<JSDOMWindow*>(asObject(value)); - if (classInfo == JSDOMWindowShell::info()) - return jsCast<JSDOMWindowShell*>(asObject(value))->window(); + + while (!value.isNull()) { + JSObject* object = asObject(value); + const ClassInfo* classInfo = object->classInfo(vm); + if (classInfo == JSDOMWindow::info()) + return jsCast<JSDOMWindow*>(object); + if (classInfo == JSDOMWindowShell::info()) + return jsCast<JSDOMWindowShell*>(object)->window(); + value = object->getPrototypeDirect(); + } return 0; } +DOMWindow& callerDOMWindow(ExecState* exec) +{ + class GetCallerGlobalObjectFunctor { + public: + GetCallerGlobalObjectFunctor() = default; + + StackVisitor::Status operator()(StackVisitor& visitor) const + { + if (!m_hasSkippedFirstFrame) { + m_hasSkippedFirstFrame = true; + return StackVisitor::Continue; + } + + if (auto* codeBlock = visitor->codeBlock()) + m_globalObject = codeBlock->globalObject(); + else { + ASSERT(visitor->callee()); + // FIXME: Callee is not an object if the caller is Web Assembly. + // Figure out what to do here. We can probably get the global object + // from the top-most Wasm Instance. https://bugs.webkit.org/show_bug.cgi?id=165721 + if (visitor->callee()->isObject()) + m_globalObject = jsCast<JSObject*>(visitor->callee())->globalObject(); + } + return StackVisitor::Done; + } + + JSGlobalObject* globalObject() const { return m_globalObject; } + + private: + mutable bool m_hasSkippedFirstFrame { false }; + mutable JSGlobalObject* m_globalObject { nullptr }; + }; + + GetCallerGlobalObjectFunctor iter; + exec->iterate(iter); + return iter.globalObject() ? asJSDOMWindow(iter.globalObject())->wrapped() : firstDOMWindow(exec); +} + +DOMWindow& activeDOMWindow(ExecState* exec) +{ + return asJSDOMWindow(exec->lexicalGlobalObject())->wrapped(); +} + +DOMWindow& firstDOMWindow(ExecState* exec) +{ + return asJSDOMWindow(exec->vmEntryGlobalObject())->wrapped(); +} + +void JSDOMWindowBase::fireFrameClearedWatchpointsForWindow(DOMWindow* window) +{ + JSC::VM& vm = commonVM(); + JSVMClientData* clientData = static_cast<JSVMClientData*>(vm.clientData); + Vector<Ref<DOMWrapperWorld>> wrapperWorlds; + clientData->getAllWorlds(wrapperWorlds); + for (unsigned i = 0; i < wrapperWorlds.size(); ++i) { + DOMObjectWrapperMap& wrappers = wrapperWorlds[i]->m_wrappers; + auto result = wrappers.find(window); + if (result == wrappers.end()) + continue; + JSC::JSObject* wrapper = result->value.get(); + if (!wrapper) + continue; + JSDOMWindowBase* jsWindow = JSC::jsCast<JSDOMWindowBase*>(wrapper); + jsWindow->m_windowCloseWatchpoints.fireAll(vm, "Frame cleared"); + } +} + + +JSC::JSInternalPromise* JSDOMWindowBase::moduleLoaderResolve(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSModuleLoader* moduleLoader, JSC::JSValue moduleName, JSC::JSValue importerModuleKey, JSC::JSValue scriptFetcher) +{ + JSDOMWindowBase* thisObject = JSC::jsCast<JSDOMWindowBase*>(globalObject); + if (RefPtr<Document> document = thisObject->wrapped().document()) + return document->moduleLoader()->resolve(globalObject, exec, moduleLoader, moduleName, importerModuleKey, scriptFetcher); + JSC::JSInternalPromiseDeferred* deferred = JSC::JSInternalPromiseDeferred::create(exec, globalObject); + return deferred->reject(exec, jsUndefined()); +} + +JSC::JSInternalPromise* JSDOMWindowBase::moduleLoaderFetch(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSModuleLoader* moduleLoader, JSC::JSValue moduleKey, JSC::JSValue scriptFetcher) +{ + JSDOMWindowBase* thisObject = JSC::jsCast<JSDOMWindowBase*>(globalObject); + if (RefPtr<Document> document = thisObject->wrapped().document()) + return document->moduleLoader()->fetch(globalObject, exec, moduleLoader, moduleKey, scriptFetcher); + JSC::JSInternalPromiseDeferred* deferred = JSC::JSInternalPromiseDeferred::create(exec, globalObject); + return deferred->reject(exec, jsUndefined()); +} + +JSC::JSValue JSDOMWindowBase::moduleLoaderEvaluate(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSModuleLoader* moduleLoader, JSC::JSValue moduleKey, JSC::JSValue moduleRecord, JSC::JSValue scriptFetcher) +{ + JSDOMWindowBase* thisObject = JSC::jsCast<JSDOMWindowBase*>(globalObject); + if (RefPtr<Document> document = thisObject->wrapped().document()) + return document->moduleLoader()->evaluate(globalObject, exec, moduleLoader, moduleKey, moduleRecord, scriptFetcher); + return JSC::jsUndefined(); +} + +JSC::JSInternalPromise* JSDOMWindowBase::moduleLoaderImportModule(JSC::JSGlobalObject* globalObject, JSC::ExecState* exec, JSC::JSModuleLoader* moduleLoader, JSC::JSString* moduleName, const JSC::SourceOrigin& sourceOrigin) +{ + JSDOMWindowBase* thisObject = JSC::jsCast<JSDOMWindowBase*>(globalObject); + if (RefPtr<Document> document = thisObject->wrapped().document()) + return document->moduleLoader()->importModule(globalObject, exec, moduleLoader, moduleName, sourceOrigin); + JSC::JSInternalPromiseDeferred* deferred = JSC::JSInternalPromiseDeferred::create(exec, globalObject); + return deferred->reject(exec, jsUndefined()); +} + } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMWindowBase.h b/Source/WebCore/bindings/js/JSDOMWindowBase.h index fb4c601bc..19c3da4a7 100644 --- a/Source/WebCore/bindings/js/JSDOMWindowBase.h +++ b/Source/WebCore/bindings/js/JSDOMWindowBase.h @@ -17,8 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef JSDOMWindowBase_h -#define JSDOMWindowBase_h +#pragma once #include "JSDOMBinding.h" #include "JSDOMGlobalObject.h" @@ -34,10 +33,10 @@ namespace WebCore { class JSDOMWindowBasePrivate; - class JSDOMWindowBase : public JSDOMGlobalObject { + class WEBCORE_EXPORT JSDOMWindowBase : public JSDOMGlobalObject { typedef JSDOMGlobalObject Base; protected: - JSDOMWindowBase(JSC::VM&, JSC::Structure*, PassRefPtr<DOMWindow>, JSDOMWindowShell*); + JSDOMWindowBase(JSC::VM&, JSC::Structure*, RefPtr<DOMWindow>&&, JSDOMWindowShell*); void finishCreation(JSC::VM&, JSDOMWindowShell*); static void destroy(JSCell*); @@ -45,7 +44,7 @@ namespace WebCore { public: void updateDocument(); - DOMWindow& impl() const { return *m_impl; } + DOMWindow& wrapped() const { return *m_wrapped; } ScriptExecutionContext* scriptExecutionContext() const; // Called just before removing this window from the JSDOMWindowShell. @@ -60,38 +59,46 @@ namespace WebCore { static const JSC::GlobalObjectMethodTable s_globalObjectMethodTable; - static bool supportsProfiling(const JSC::JSGlobalObject*); static bool supportsRichSourceInfo(const JSC::JSGlobalObject*); static bool shouldInterruptScript(const JSC::JSGlobalObject*); static bool shouldInterruptScriptBeforeTimeout(const JSC::JSGlobalObject*); - static bool javaScriptExperimentsEnabled(const JSC::JSGlobalObject*); - static void queueTaskToEventLoop(const JSC::JSGlobalObject*, PassRefPtr<JSC::Microtask>); + static JSC::RuntimeFlags javaScriptRuntimeFlags(const JSC::JSGlobalObject*); + static void queueTaskToEventLoop(const JSC::JSGlobalObject*, Ref<JSC::Microtask>&&); void printErrorMessage(const String&) const; JSDOMWindowShell* shell() const; - static JSC::VM* commonVM(); -#if PLATFORM(IOS) - static bool commonVMExists(); - static JSC::VM*& commonVMInternal(); -#endif + static void fireFrameClearedWatchpointsForWindow(DOMWindow*); + static void visitChildren(JSC::JSCell*, JSC::SlotVisitor&); + + protected: + JSC::WatchpointSet m_windowCloseWatchpoints; private: - RefPtr<DOMWindow> m_impl; + static JSC::JSInternalPromise* moduleLoaderResolve(JSC::JSGlobalObject*, JSC::ExecState*, JSC::JSModuleLoader*, JSC::JSValue, JSC::JSValue, JSC::JSValue); + static JSC::JSInternalPromise* moduleLoaderFetch(JSC::JSGlobalObject*, JSC::ExecState*, JSC::JSModuleLoader*, JSC::JSValue, JSC::JSValue); + static JSC::JSValue moduleLoaderEvaluate(JSC::JSGlobalObject*, JSC::ExecState*, JSC::JSModuleLoader*, JSC::JSValue, JSC::JSValue, JSC::JSValue); + static JSC::JSInternalPromise* moduleLoaderImportModule(JSC::JSGlobalObject*, JSC::ExecState*, JSC::JSModuleLoader*, JSC::JSString*, const JSC::SourceOrigin&); + + RefPtr<DOMWindow> m_wrapped; JSDOMWindowShell* m_shell; }; // Returns a JSDOMWindow or jsNull() // JSDOMGlobalObject* is ignored, accessing a window in any context will // use that DOMWindow's prototype chain. - JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, DOMWindow*); - JSC::JSValue toJS(JSC::ExecState*, DOMWindow*); + WEBCORE_EXPORT JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, DOMWindow&); + inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMWindow* window) { return window ? toJS(exec, globalObject, *window) : JSC::jsNull(); } + JSC::JSValue toJS(JSC::ExecState*, DOMWindow&); + inline JSC::JSValue toJS(JSC::ExecState* exec, DOMWindow* window) { return window ? toJS(exec, *window) : JSC::jsNull(); } // Returns JSDOMWindow or 0 JSDOMWindow* toJSDOMWindow(Frame*, DOMWrapperWorld&); - JSDOMWindow* toJSDOMWindow(JSC::JSValue); + WEBCORE_EXPORT JSDOMWindow* toJSDOMWindow(JSC::VM&, JSC::JSValue); -} // namespace WebCore + DOMWindow& callerDOMWindow(JSC::ExecState*); + DOMWindow& activeDOMWindow(JSC::ExecState*); + DOMWindow& firstDOMWindow(JSC::ExecState*); -#endif // JSDOMWindowBase_h +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp b/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp index 795da5a49..c00484af5 100644 --- a/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp +++ b/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2007-2017 Apple Inc. All rights reserved. * Copyright (C) 2011 Google Inc. All rights reserved. * * This library is free software; you can redistribute it and/or @@ -21,117 +21,74 @@ #include "config.h" #include "JSDOMWindowCustom.h" +#include "DOMWindowIndexedDatabase.h" #include "Frame.h" #include "HTMLCollection.h" #include "HTMLDocument.h" +#include "HTMLFrameOwnerElement.h" +#include "JSDOMBindingSecurity.h" #include "JSEvent.h" #include "JSEventListener.h" #include "JSHTMLAudioElement.h" #include "JSHTMLCollection.h" #include "JSHTMLOptionElement.h" -#include "JSImageConstructor.h" -#include "JSMessagePortCustom.h" +#include "JSIDBFactory.h" #include "JSWorker.h" #include "Location.h" +#include "RuntimeEnabledFeatures.h" #include "ScheduledAction.h" #include "Settings.h" -#include "SharedWorkerRepository.h" +#include <runtime/JSCInlines.h> +#include <runtime/Lookup.h> -#if ENABLE(SHARED_WORKERS) -#include "JSSharedWorker.h" -#endif - -#if ENABLE(IOS_TOUCH_EVENTS) -#include "JSTouchConstructorIOS.h" -#include "JSTouchListConstructorIOS.h" -#endif - -#if ENABLE(WEB_AUDIO) -#include "JSAudioContext.h" -#endif - -#if ENABLE(WEB_SOCKETS) -#include "JSWebSocket.h" +#if ENABLE(USER_MESSAGE_HANDLERS) +#include "JSWebKitNamespace.h" #endif using namespace JSC; namespace WebCore { -void JSDOMWindow::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(thisObject, visitor); - - thisObject->impl().visitJSEventListeners(visitor); - if (Frame* frame = thisObject->impl().frame()) - visitor.addOpaqueRoot(frame); -} - -template<NativeFunction nativeFunction, int length> -EncodedJSValue nonCachingStaticFunctionGetter(ExecState* exec, EncodedJSValue, EncodedJSValue, PropertyName propertyName) -{ - return JSValue::encode(JSFunction::create(exec->vm(), exec->lexicalGlobalObject(), length, propertyName.publicName(), nativeFunction)); -} +EncodedJSValue JSC_HOST_CALL jsDOMWindowInstanceFunctionShowModalDialog(ExecState*); -static EncodedJSValue childFrameGetter(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName propertyName) +void JSDOMWindow::visitAdditionalChildren(SlotVisitor& visitor) { - return JSValue::encode(toJS(exec, jsCast<JSDOMWindow*>(JSValue::decode(slotBase))->impl().frame()->tree().scopedChild(propertyNameToAtomicString(propertyName))->document()->domWindow())); -} - -static EncodedJSValue indexGetter(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, unsigned index) -{ - return JSValue::encode(toJS(exec, jsCast<JSDOMWindow*>(JSValue::decode(slotBase))->impl().frame()->tree().scopedChild(index)->document()->domWindow())); + if (Frame* frame = wrapped().frame()) + visitor.addOpaqueRoot(frame); + + // Normally JSEventTargetCustom.cpp's JSEventTarget::visitAdditionalChildren() would call this. But + // even though DOMWindow is an EventTarget, JSDOMWindow does not subclass JSEventTarget, so we need + // to do this here. + wrapped().visitJSEventListeners(visitor); } -static EncodedJSValue namedItemGetter(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName propertyName) +#if ENABLE(USER_MESSAGE_HANDLERS) +static EncodedJSValue jsDOMWindowWebKit(ExecState* exec, EncodedJSValue thisValue, PropertyName) { - JSDOMWindowBase* thisObj = jsCast<JSDOMWindow*>(JSValue::decode(slotBase)); - Document* document = thisObj->impl().frame()->document(); - - ASSERT(BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObj->impl())); - ASSERT(document); - ASSERT(document->isHTMLDocument()); - - AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName); - if (!atomicPropertyName || !toHTMLDocument(document)->hasWindowNamedItem(*atomicPropertyName)) + VM& vm = exec->vm(); + JSDOMWindow* castedThis = toJSDOMWindow(vm, JSValue::decode(thisValue)); + if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, castedThis->wrapped())) return JSValue::encode(jsUndefined()); - - if (UNLIKELY(toHTMLDocument(document)->windowNamedItemContainsMultipleElements(*atomicPropertyName))) { - RefPtr<HTMLCollection> collection = document->windowNamedItems(atomicPropertyName); - ASSERT(collection->length() > 1); - return JSValue::encode(toJS(exec, thisObj->globalObject(), WTF::getPtr(collection))); - } - - return JSValue::encode(toJS(exec, thisObj->globalObject(), toHTMLDocument(document)->windowNamedItem(*atomicPropertyName))); + return JSValue::encode(toJS(exec, castedThis->globalObject(), castedThis->wrapped().webkitNamespace())); } +#endif -bool JSDOMWindow::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) +static bool jsDOMWindowGetOwnPropertySlotRestrictedAccess(JSDOMWindow* thisObject, Frame* frame, ExecState* exec, PropertyName propertyName, PropertySlot& slot, const String& errorMessage) { - JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object); - // When accessing a Window cross-domain, functions are always the native built-in ones, and they - // are not affected by properties changed on the Window or anything in its prototype chain. - // This is consistent with the behavior of Firefox. - - const HashEntry* entry; - - // We don't want any properties other than "close" and "closed" on a frameless window (i.e. one whose page got closed, - // or whose iframe got removed). - // FIXME: This doesn't fully match Firefox, which allows at least toString in addition to those. - if (!thisObject->impl().frame()) { - // The following code is safe for cross-domain and same domain use. - // It ignores any custom properties that might be set on the DOMWindow (including a custom prototype). - entry = s_info.propHashTable(exec)->entry(exec, propertyName); - if (entry && !(entry->attributes() & JSC::Function) && entry->propertyGetter() == jsDOMWindowClosed) { - slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, entry->propertyGetter()); + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + // We don't want any properties other than "close" and "closed" on a frameless window + // (i.e. one whose page got closed, or whose iframe got removed). + // FIXME: This handling for frameless windows duplicates similar behaviour for cross-origin + // access below; we should try to find a way to merge the two. + if (!frame) { + if (propertyName == exec->propertyNames().closed) { + slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, jsDOMWindowClosed); return true; } - entry = JSDOMWindowPrototype::info()->propHashTable(exec)->entry(exec, propertyName); - if (entry && (entry->attributes() & JSC::Function) && entry->function() == jsDOMWindowPrototypeFunctionClose) { - slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>); + if (propertyName == exec->propertyNames().close) { + slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowInstanceFunctionClose, 0>); return true; } @@ -141,240 +98,186 @@ bool JSDOMWindow::getOwnPropertySlot(JSObject* object, ExecState* exec, Property return true; } - // We need to check for cross-domain access here without printing the generic warning message - // because we always allow access to some function, just different ones depending whether access - // is allowed. - String errorMessage; - bool allowsAccess = shouldAllowAccessToDOMWindow(exec, thisObject->impl(), errorMessage); - - // Look for overrides before looking at any of our own properties, but ignore overrides completely - // if this is cross-domain access. - if (allowsAccess && JSGlobalObject::getOwnPropertySlot(thisObject, exec, propertyName, slot)) + // https://html.spec.whatwg.org/#crossorigingetownpropertyhelper-(-o,-p-) + if (propertyName == exec->propertyNames().toStringTagSymbol || propertyName == exec->propertyNames().hasInstanceSymbol || propertyName == exec->propertyNames().isConcatSpreadableSymbol) { + slot.setValue(thisObject, ReadOnly | DontEnum, jsUndefined()); return true; - - // We need this code here because otherwise JSDOMWindowBase will stop the search before we even get to the - // prototype due to the blanket same origin (shouldAllowAccessToDOMWindow) check at the end of getOwnPropertySlot. - // Also, it's important to get the implementation straight out of the DOMWindow prototype regardless of - // what prototype is actually set on this object. - entry = JSDOMWindowPrototype::info()->propHashTable(exec)->entry(exec, propertyName); - if (entry) { - if (entry->attributes() & JSC::Function) { - if (entry->function() == jsDOMWindowPrototypeFunctionBlur) { - if (!allowsAccess) { - slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionBlur, 0>); - return true; - } - } else if (entry->function() == jsDOMWindowPrototypeFunctionClose) { - if (!allowsAccess) { - slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>); - return true; - } - } else if (entry->function() == jsDOMWindowPrototypeFunctionFocus) { - if (!allowsAccess) { - slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionFocus, 0>); - return true; - } - } else if (entry->function() == jsDOMWindowPrototypeFunctionPostMessage) { - if (!allowsAccess) { - slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionPostMessage, 2>); - return true; - } - } else if (entry->function() == jsDOMWindowPrototypeFunctionShowModalDialog) { - if (!DOMWindow::canShowModalDialog(thisObject->impl().frame())) { - slot.setUndefined(); - return true; - } - } - } - } else { - // Allow access to toString() cross-domain, but always Object.prototype.toString. - if (propertyName == exec->propertyNames().toString) { - if (!allowsAccess) { - slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, objectToStringFunctionGetter); - return true; - } - } } - entry = JSDOMWindow::info()->propHashTable(exec)->entry(exec, propertyName); - if (entry) { - slot.setCustom(thisObject, allowsAccess ? entry->attributes() : ReadOnly | DontDelete | DontEnum, entry->propertyGetter()); + // These are the functions we allow access to cross-origin (DoNotCheckSecurity in IDL). + // Always provide the original function, on a fresh uncached function object. + if (propertyName == exec->propertyNames().blur) { + slot.setCustom(thisObject, ReadOnly | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowInstanceFunctionBlur, 0>); return true; } - - // Check for child frames by name before built-in properties to - // match Mozilla. This does not match IE, but some sites end up - // naming frames things that conflict with window properties that - // are in Moz but not IE. Since we have some of these, we have to do - // it the Moz way. - if (thisObject->impl().frame()->tree().scopedChild(propertyNameToAtomicString(propertyName))) { - slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, childFrameGetter); + if (propertyName == exec->propertyNames().close) { + slot.setCustom(thisObject, ReadOnly | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowInstanceFunctionClose, 0>); return true; } - - // Do prototype lookup early so that functions and attributes in the prototype can have - // precedence over the index and name getters. - JSValue proto = thisObject->prototype(); - if (proto.isObject()) { - if (asObject(proto)->getPropertySlot(exec, propertyName, slot)) { - if (!allowsAccess) { - thisObject->printErrorMessage(errorMessage); - slot.setUndefined(); - } - return true; - } - } - - // FIXME: Search the whole frame hierarchy somewhere around here. - // We need to test the correct priority order. - - // allow window[1] or parent[1] etc. (#56983) - unsigned i = propertyName.asIndex(); - if (i < thisObject->impl().frame()->tree().scopedChildCount()) { - ASSERT(i != PropertyName::NotAnIndex); - slot.setCustomIndex(thisObject, ReadOnly | DontDelete | DontEnum, i, indexGetter); + if (propertyName == exec->propertyNames().focus) { + slot.setCustom(thisObject, ReadOnly | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowInstanceFunctionFocus, 0>); return true; } - - if (!allowsAccess) { - thisObject->printErrorMessage(errorMessage); - slot.setUndefined(); + if (propertyName == exec->propertyNames().postMessage) { + slot.setCustom(thisObject, ReadOnly | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowInstanceFunctionPostMessage, 2>); return true; } - // Allow shortcuts like 'Image1' instead of document.images.Image1 - Document* document = thisObject->impl().frame()->document(); - if (document->isHTMLDocument()) { - AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName); - if (atomicPropertyName && toHTMLDocument(document)->hasWindowNamedItem(*atomicPropertyName)) { - slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, namedItemGetter); + // When accessing cross-origin known Window properties, we always use the original property getter, + // even if the property was removed / redefined. As of early 2016, this matches Firefox and Chrome's + // behavior. + if (auto* entry = JSDOMWindow::info()->staticPropHashTable->entry(propertyName)) { + // Only allow access to these specific properties. + if (propertyName == exec->propertyNames().location + || propertyName == exec->propertyNames().closed + || propertyName == exec->propertyNames().length + || propertyName == exec->propertyNames().self + || propertyName == exec->propertyNames().window + || propertyName == exec->propertyNames().frames + || propertyName == exec->propertyNames().opener + || propertyName == exec->propertyNames().parent + || propertyName == exec->propertyNames().top) { + bool shouldExposeSetter = propertyName == exec->propertyNames().location; + CustomGetterSetter* customGetterSetter = CustomGetterSetter::create(vm, entry->propertyGetter(), shouldExposeSetter ? entry->propertyPutter() : nullptr); + slot.setCustomGetterSetter(thisObject, DontEnum | CustomAccessor, customGetterSetter); return true; } + + // For any other entries in the static property table, deny access. (Early return also prevents + // named getter from returning frames with matching names - this seems a little questionable, see + // FIXME comment on prototype search below.) + throwSecurityError(*exec, scope, errorMessage); + slot.setUndefined(); + return false; } - return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); + // Check for child frames by name before built-in properties to match Mozilla. This does + // not match IE, but some sites end up naming frames things that conflict with window + // properties that are in Moz but not IE. Since we have some of these, we have to do it + // the Moz way. + if (auto* scopedChild = frame->tree().scopedChild(propertyNameToAtomicString(propertyName))) { + slot.setValue(thisObject, ReadOnly | DontDelete | DontEnum, toJS(exec, scopedChild->document()->domWindow())); + return true; + } + + throwSecurityError(*exec, scope, errorMessage); + slot.setUndefined(); + return false; } -bool JSDOMWindow::getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned index, PropertySlot& slot) +// Property access sequence is: +// (1) indexed properties, +// (2) regular own properties, +// (3) named properties (in fact, these shouldn't be on the window, should be on the NPO). +bool JSDOMWindow::getOwnPropertySlot(JSObject* object, ExecState* state, PropertyName propertyName, PropertySlot& slot) { - JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object); - - if (!thisObject->impl().frame()) { - // FIXME: We should have a message here that explains why the property access/function call was - // not allowed. - slot.setUndefined(); - return true; - } + // (1) First, indexed properties. + // Hand off all indexed access to getOwnPropertySlotByIndex, which supports the indexed getter. + if (std::optional<unsigned> index = parseIndex(propertyName)) + return getOwnPropertySlotByIndex(object, state, index.value(), slot); - // We need to check for cross-domain access here without printing the generic warning message - // because we always allow access to some function, just different ones depending whether access - // is allowed. - String errorMessage; - bool allowsAccess = shouldAllowAccessToDOMWindow(exec, thisObject->impl(), errorMessage); + auto* thisObject = jsCast<JSDOMWindow*>(object); + auto* frame = thisObject->wrapped().frame(); - // Look for overrides before looking at any of our own properties, but ignore overrides completely - // if this is cross-domain access. - if (allowsAccess && JSGlobalObject::getOwnPropertySlotByIndex(thisObject, exec, index, slot)) - return true; - - PropertyName propertyName = Identifier::from(exec, index); - - // Check for child frames by name before built-in properties to - // match Mozilla. This does not match IE, but some sites end up - // naming frames things that conflict with window properties that - // are in Moz but not IE. Since we have some of these, we have to do - // it the Moz way. - if (thisObject->impl().frame()->tree().scopedChild(propertyNameToAtomicString(propertyName))) { - slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, childFrameGetter); - return true; - } + // Hand off all cross-domain/frameless access to jsDOMWindowGetOwnPropertySlotRestrictedAccess. + String errorMessage; + if (!frame || !BindingSecurity::shouldAllowAccessToDOMWindow(*state, thisObject->wrapped(), errorMessage)) + return jsDOMWindowGetOwnPropertySlotRestrictedAccess(thisObject, frame, state, propertyName, slot, errorMessage); - // Do prototype lookup early so that functions and attributes in the prototype can have - // precedence over the index and name getters. - JSValue proto = thisObject->prototype(); - if (proto.isObject()) { - if (asObject(proto)->getPropertySlot(exec, index, slot)) { - if (!allowsAccess) { - thisObject->printErrorMessage(errorMessage); - slot.setUndefined(); - } + // FIXME: this need more explanation. + // (Particularly, is it correct that this exists here but not in getOwnPropertySlotByIndex?) + slot.setWatchpointSet(thisObject->m_windowCloseWatchpoints); + + // (2) Regular own properties. + PropertySlot slotCopy = slot; + if (Base::getOwnPropertySlot(thisObject, state, propertyName, slot)) { + // Detect when we're getting the property 'showModalDialog', this is disabled, and has its original value. + bool isShowModalDialogAndShouldHide = propertyName == state->propertyNames().showModalDialog + && !DOMWindow::canShowModalDialog(*frame) + && slot.isValue() && isHostFunction(slot.getValue(state, propertyName), jsDOMWindowInstanceFunctionShowModalDialog); + // Unless we're in the showModalDialog special case, we're done. + if (!isShowModalDialogAndShouldHide) return true; - } + slot = slotCopy; } - // FIXME: Search the whole frame hierarchy somewhere around here. - // We need to test the correct priority order. - - // allow window[1] or parent[1] etc. (#56983) - if (index < thisObject->impl().frame()->tree().scopedChildCount()) { - ASSERT(index != PropertyName::NotAnIndex); - slot.setCustomIndex(thisObject, ReadOnly | DontDelete | DontEnum, index, indexGetter); +#if ENABLE(USER_MESSAGE_HANDLERS) + if (propertyName == state->propertyNames().webkit && thisObject->wrapped().shouldHaveWebKitNamespaceForWorld(thisObject->world())) { + slot.setCacheableCustom(thisObject, DontDelete | ReadOnly, jsDOMWindowWebKit); return true; } +#endif - if (!allowsAccess) { - thisObject->printErrorMessage(errorMessage); - slot.setUndefined(); + return false; +} + +// Property access sequence is: +// (1) indexed properties, +// (2) regular own properties, +// (3) named properties (in fact, these shouldn't be on the window, should be on the NPO). +bool JSDOMWindow::getOwnPropertySlotByIndex(JSObject* object, ExecState* state, unsigned index, PropertySlot& slot) +{ + auto* thisObject = jsCast<JSDOMWindow*>(object); + auto* frame = thisObject->wrapped().frame(); + + // Indexed getters take precendence over regular properties, so caching would be invalid. + slot.disableCaching(); + + // (1) First, indexed properties. + // These are also allowed cross-orgin, so come before the access check. + if (frame && index < frame->tree().scopedChildCount()) { + slot.setValue(thisObject, ReadOnly | DontEnum, toJS(state, frame->tree().scopedChild(index)->document()->domWindow())); return true; } - // Allow shortcuts like 'Image1' instead of document.images.Image1 - Document* document = thisObject->impl().frame()->document(); - if (document->isHTMLDocument()) { - AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName); - if (atomicPropertyName && toHTMLDocument(document)->hasWindowNamedItem(*atomicPropertyName)) { - slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, namedItemGetter); - return true; - } - } + // Hand off all cross-domain/frameless access to jsDOMWindowGetOwnPropertySlotRestrictedAccess. + String errorMessage; + if (!frame || !BindingSecurity::shouldAllowAccessToDOMWindow(*state, thisObject->wrapped(), errorMessage)) + return jsDOMWindowGetOwnPropertySlotRestrictedAccess(thisObject, frame, state, Identifier::from(state, index), slot, errorMessage); - return Base::getOwnPropertySlotByIndex(thisObject, exec, index, slot); + // (2) Regular own properties. + return Base::getOwnPropertySlotByIndex(thisObject, state, index, slot); } -void JSDOMWindow::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) +bool JSDOMWindow::put(JSCell* cell, ExecState* state, PropertyName propertyName, JSValue value, PutPropertySlot& slot) { - JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(cell); - if (!thisObject->impl().frame()) - return; + VM& vm = state->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); - // Optimization: access JavaScript global variables directly before involving the DOM. - if (thisObject->JSGlobalObject::hasOwnPropertyForWrite(exec, propertyName)) { - if (BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl())) - JSGlobalObject::put(thisObject, exec, propertyName, value, slot); - return; - } + auto* thisObject = jsCast<JSDOMWindow*>(cell); + if (!thisObject->wrapped().frame()) + return false; - if (lookupPut(exec, propertyName, thisObject, value, *s_info.propHashTable(exec), slot)) - return; + String errorMessage; + if (!BindingSecurity::shouldAllowAccessToDOMWindow(*state, thisObject->wrapped(), errorMessage)) { + // We only allow setting "location" attribute cross-origin. + if (propertyName == state->propertyNames().location) { + bool putResult = false; + if (lookupPut(state, propertyName, thisObject, value, *s_info.staticPropHashTable, slot, putResult)) + return putResult; + return false; + } + throwSecurityError(*state, scope, errorMessage); + return false; + } - if (BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl())) - Base::put(thisObject, exec, propertyName, value, slot); + return Base::put(thisObject, state, propertyName, value, slot); } -void JSDOMWindow::putByIndex(JSCell* cell, ExecState* exec, unsigned index, JSValue value, bool shouldThrow) +bool JSDOMWindow::putByIndex(JSCell* cell, ExecState* exec, unsigned index, JSValue value, bool shouldThrow) { - JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(cell); - if (!thisObject->impl().frame()) - return; - - PropertyName propertyName = Identifier::from(exec, index); - - // Optimization: access JavaScript global variables directly before involving the DOM. - if (thisObject->JSGlobalObject::hasOwnPropertyForWrite(exec, propertyName)) { - if (BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl())) - JSGlobalObject::putByIndex(thisObject, exec, index, value, shouldThrow); - return; - } + auto* thisObject = jsCast<JSDOMWindow*>(cell); + if (!thisObject->wrapped().frame() || !BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped())) + return false; - if (BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl())) - Base::putByIndex(thisObject, exec, index, value, shouldThrow); + return Base::putByIndex(thisObject, exec, index, value, shouldThrow); } bool JSDOMWindow::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) { JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(cell); // Only allow deleting properties by frames in the same origin. - if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl())) + if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), ThrowSecurityError)) return false; return Base::deleteProperty(thisObject, exec, propertyName); } @@ -383,26 +286,128 @@ bool JSDOMWindow::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned { JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(cell); // Only allow deleting properties by frames in the same origin. - if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl())) + if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), ThrowSecurityError)) return false; return Base::deletePropertyByIndex(thisObject, exec, propertyName); } +uint32_t JSDOMWindow::getEnumerableLength(ExecState* exec, JSObject* object) +{ + JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object); + // Only allow the window to enumerated by frames in the same origin. + if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped())) + return 0; + return Base::getEnumerableLength(exec, thisObject); +} + +void JSDOMWindow::getStructurePropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) +{ + JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object); + // Only allow the window to enumerated by frames in the same origin. + if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped())) + return; + Base::getStructurePropertyNames(thisObject, exec, propertyNames, mode); +} + +void JSDOMWindow::getGenericPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) +{ + JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object); + // Only allow the window to enumerated by frames in the same origin. + if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped())) + return; + Base::getGenericPropertyNames(thisObject, exec, propertyNames, mode); +} + void JSDOMWindow::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object); // Only allow the window to enumerated by frames in the same origin. - if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl())) + if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped())) return; Base::getPropertyNames(thisObject, exec, propertyNames, mode); } +static bool inScope(Frame& frame, TreeScope& scope) +{ + auto* document = frame.document(); + if (!document) + return false; + auto* owner = document->ownerElement(); + return owner && &owner->treeScope() == &scope; +} + +static void addScopedChildrenNames(ExecState& state, DOMWindow& window, PropertyNameArray& propertyNames) +{ + auto* document = window.document(); + if (!document) + return; + + auto* frame = document->frame(); + if (!frame) + return; + + for (auto* child = frame->tree().firstChild(); child; child = child->tree().nextSibling()) { + if (!inScope(*child, *document)) + continue; + if (!child->tree().name().isEmpty()) + propertyNames.add(Identifier::fromString(&state, child->tree().name())); + } +} + +// https://html.spec.whatwg.org/#crossoriginproperties-(-o-) +static void addCrossOriginPropertyNames(ExecState& state, DOMWindow& window, PropertyNameArray& propertyNames) +{ + static const Identifier* const properties[] = { + &state.propertyNames().blur, &state.propertyNames().close, &state.propertyNames().closed, + &state.propertyNames().focus, &state.propertyNames().frames, &state.propertyNames().length, + &state.propertyNames().location, &state.propertyNames().opener, &state.propertyNames().parent, + &state.propertyNames().postMessage, &state.propertyNames().self, &state.propertyNames().top, + &state.propertyNames().window + }; + for (auto* property : properties) + propertyNames.add(*property); + + addScopedChildrenNames(state, window, propertyNames); +} + +static void addScopedChildrenIndexes(ExecState& state, DOMWindow& window, PropertyNameArray& propertyNames) +{ + auto* document = window.document(); + if (!document) + return; + + auto* frame = document->frame(); + if (!frame) + return; + + unsigned scopedChildCount = frame->tree().scopedChildCount(); + for (unsigned i = 0; i < scopedChildCount; ++i) + propertyNames.add(Identifier::from(&state, i)); +} + +// https://html.spec.whatwg.org/#crossoriginownpropertykeys-(-o-) +static void addCrossOriginOwnPropertyNames(ExecState& state, DOMWindow& window, PropertyNameArray& propertyNames) +{ + addCrossOriginPropertyNames(state, window, propertyNames); + + propertyNames.add(state.propertyNames().toStringTagSymbol); + propertyNames.add(state.propertyNames().hasInstanceSymbol); + propertyNames.add(state.propertyNames().isConcatSpreadableSymbol); +} + +// https://html.spec.whatwg.org/#windowproxy-ownpropertykeys void JSDOMWindow::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object); - // Only allow the window to enumerated by frames in the same origin. - if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl())) + + if (mode.includeDontEnumProperties()) + addScopedChildrenIndexes(*exec, thisObject->wrapped(), propertyNames); + + if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), DoNotReportSecurityError)) { + if (mode.includeDontEnumProperties()) + addCrossOriginOwnPropertyNames(*exec, thisObject->wrapped(), propertyNames); return; + } Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode); } @@ -410,88 +415,99 @@ bool JSDOMWindow::defineOwnProperty(JSC::JSObject* object, JSC::ExecState* exec, { JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object); // Only allow defining properties in this way by frames in the same origin, as it allows setters to be introduced. - if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->impl())) + if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), ThrowSecurityError)) return false; // Don't allow shadowing location using accessor properties. - if (descriptor.isAccessorDescriptor() && propertyName == Identifier(exec, "location")) + if (descriptor.isAccessorDescriptor() && propertyName == Identifier::fromString(exec, "location")) return false; return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow); } +JSValue JSDOMWindow::getPrototype(JSObject* object, ExecState* exec) +{ + JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object); + if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), DoNotReportSecurityError)) + return jsNull(); + + return Base::getPrototype(object, exec); +} + +bool JSDOMWindow::preventExtensions(JSObject*, ExecState* exec) +{ + auto scope = DECLARE_THROW_SCOPE(exec->vm()); + + throwTypeError(exec, scope, ASCIILiteral("Cannot prevent extensions on this object")); + return false; +} + +String JSDOMWindow::toStringName(const JSObject* object, ExecState* exec) +{ + auto* thisObject = jsCast<const JSDOMWindow*>(object); + if (!BindingSecurity::shouldAllowAccessToDOMWindow(exec, thisObject->wrapped(), DoNotReportSecurityError)) + return ASCIILiteral("Object"); + return ASCIILiteral("Window"); +} + // Custom Attributes -void JSDOMWindow::setLocation(ExecState* exec, JSValue value) +void JSDOMWindow::setLocation(ExecState& state, JSValue value) { + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + #if ENABLE(DASHBOARD_SUPPORT) // To avoid breaking old widgets, make "var location =" in a top-level frame create // a property named "location" instead of performing a navigation (<rdar://problem/5688039>). - if (Frame* activeFrame = activeDOMWindow(exec).frame()) { + if (Frame* activeFrame = activeDOMWindow(&state).frame()) { if (activeFrame->settings().usesDashboardBackwardCompatibilityMode() && !activeFrame->tree().parent()) { - if (BindingSecurity::shouldAllowAccessToDOMWindow(exec, impl())) - putDirect(exec->vm(), Identifier(exec, "location"), value); + if (BindingSecurity::shouldAllowAccessToDOMWindow(&state, wrapped())) + putDirect(state.vm(), Identifier::fromString(&state, "location"), value); return; } } #endif - String locationString = value.toString(exec)->value(exec); - if (exec->hadException()) - return; + String locationString = value.toWTFString(&state); + RETURN_IF_EXCEPTION(scope, void()); - if (Location* location = impl().location()) - location->setHref(locationString, activeDOMWindow(exec), firstDOMWindow(exec)); + if (Location* location = wrapped().location()) + location->setHref(activeDOMWindow(&state), firstDOMWindow(&state), locationString); } -JSValue JSDOMWindow::event(ExecState* exec) const +JSValue JSDOMWindow::event(ExecState& state) const { Event* event = currentEvent(); if (!event) return jsUndefined(); - return toJS(exec, const_cast<JSDOMWindow*>(this), event); -} - -JSValue JSDOMWindow::image(ExecState* exec) const -{ - return getDOMConstructor<JSImageConstructor>(exec->vm(), this); -} - -#if ENABLE(IOS_TOUCH_EVENTS) -JSValue JSDOMWindow::touch(ExecState* exec) const -{ - return getDOMConstructor<JSTouchConstructor>(exec->vm(), this); + return toJS(&state, const_cast<JSDOMWindow*>(this), event); } -JSValue JSDOMWindow::touchList(ExecState* exec) const -{ - return getDOMConstructor<JSTouchListConstructor>(exec->vm(), this); -} -#endif - // Custom functions -JSValue JSDOMWindow::open(ExecState* exec) +JSValue JSDOMWindow::open(ExecState& state) { - String urlString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0)); - if (exec->hadException()) - return jsUndefined(); - AtomicString frameName = exec->argument(1).isUndefinedOrNull() ? "_blank" : exec->argument(1).toString(exec)->value(exec); - if (exec->hadException()) - return jsUndefined(); - String windowFeaturesString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(2)); - if (exec->hadException()) - return jsUndefined(); - - RefPtr<DOMWindow> openedWindow = impl().open(urlString, frameName, windowFeaturesString, activeDOMWindow(exec), firstDOMWindow(exec)); + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + String urlString = convert<IDLNullable<IDLUSVString>>(state, state.argument(0)); + RETURN_IF_EXCEPTION(scope, JSValue()); + JSValue targetValue = state.argument(1); + AtomicString target = targetValue.isUndefinedOrNull() ? AtomicString("_blank", AtomicString::ConstructFromLiteral) : targetValue.toString(&state)->toAtomicString(&state); + RETURN_IF_EXCEPTION(scope, JSValue()); + String windowFeaturesString = convert<IDLNullable<IDLDOMString>>(state, state.argument(2)); + RETURN_IF_EXCEPTION(scope, JSValue()); + + RefPtr<DOMWindow> openedWindow = wrapped().open(urlString, target, windowFeaturesString, activeDOMWindow(&state), firstDOMWindow(&state)); if (!openedWindow) - return jsUndefined(); - return toJS(exec, openedWindow.get()); + return jsNull(); + return toJS(&state, openedWindow.get()); } class DialogHandler { public: - explicit DialogHandler(ExecState* exec) + explicit DialogHandler(ExecState& exec) : m_exec(exec) { } @@ -500,7 +516,7 @@ public: JSValue returnValue() const; private: - ExecState* m_exec; + ExecState& m_exec; RefPtr<Frame> m_frame; }; @@ -510,162 +526,91 @@ inline void DialogHandler::dialogCreated(DOMWindow& dialog) // FIXME: This looks like a leak between the normal world and an isolated // world if dialogArguments comes from an isolated world. - JSDOMWindow* globalObject = toJSDOMWindow(m_frame.get(), normalWorld(m_exec->vm())); - if (JSValue dialogArguments = m_exec->argument(1)) - globalObject->putDirect(m_exec->vm(), Identifier(m_exec, "dialogArguments"), dialogArguments); + JSDOMWindow* globalObject = toJSDOMWindow(m_frame.get(), normalWorld(m_exec.vm())); + if (JSValue dialogArguments = m_exec.argument(1)) + globalObject->putDirect(m_exec.vm(), Identifier::fromString(&m_exec, "dialogArguments"), dialogArguments); } inline JSValue DialogHandler::returnValue() const { - JSDOMWindow* globalObject = toJSDOMWindow(m_frame.get(), normalWorld(m_exec->vm())); + JSDOMWindow* globalObject = toJSDOMWindow(m_frame.get(), normalWorld(m_exec.vm())); if (!globalObject) return jsUndefined(); - Identifier identifier(m_exec, "returnValue"); - PropertySlot slot(globalObject); - if (!JSGlobalObject::getOwnPropertySlot(globalObject, m_exec, identifier, slot)) + Identifier identifier = Identifier::fromString(&m_exec, "returnValue"); + PropertySlot slot(globalObject, PropertySlot::InternalMethodType::Get); + if (!JSGlobalObject::getOwnPropertySlot(globalObject, &m_exec, identifier, slot)) return jsUndefined(); - return slot.getValue(m_exec, identifier); + return slot.getValue(&m_exec, identifier); } -JSValue JSDOMWindow::showModalDialog(ExecState* exec) +JSValue JSDOMWindow::showModalDialog(ExecState& state) { - String urlString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0)); - if (exec->hadException()) - return jsUndefined(); - String dialogFeaturesString = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(2)); - if (exec->hadException()) - return jsUndefined(); + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(state.argumentCount() < 1)) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + + String urlString = convert<IDLNullable<IDLDOMString>>(state, state.argument(0)); + RETURN_IF_EXCEPTION(scope, JSValue()); + String dialogFeaturesString = convert<IDLNullable<IDLDOMString>>(state, state.argument(2)); + RETURN_IF_EXCEPTION(scope, JSValue()); - DialogHandler handler(exec); + DialogHandler handler(state); - impl().showModalDialog(urlString, dialogFeaturesString, activeDOMWindow(exec), firstDOMWindow(exec), [&handler](DOMWindow& dialog) { + wrapped().showModalDialog(urlString, dialogFeaturesString, activeDOMWindow(&state), firstDOMWindow(&state), [&handler](DOMWindow& dialog) { handler.dialogCreated(dialog); }); return handler.returnValue(); } -static JSValue handlePostMessage(DOMWindow* impl, ExecState* exec) +JSValue JSDOMWindow::setTimeout(ExecState& state) { - MessagePortArray messagePorts; - ArrayBufferArray arrayBuffers; + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); - // This function has variable arguments and can be: - // Per current spec: - // postMessage(message, targetOrigin) - // postMessage(message, targetOrigin, {sequence of transferrables}) - // Legacy non-standard implementations in webkit allowed: - // postMessage(message, {sequence of transferrables}, targetOrigin); - int targetOriginArgIndex = 1; - if (exec->argumentCount() > 2) { - int transferablesArgIndex = 2; - if (exec->argument(2).isString()) { - targetOriginArgIndex = 2; - transferablesArgIndex = 1; - } - fillMessagePortArray(exec, exec->argument(transferablesArgIndex), messagePorts, arrayBuffers); - } - if (exec->hadException()) - return jsUndefined(); - - RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(exec, exec->argument(0), - &messagePorts, - &arrayBuffers); - - if (exec->hadException()) - return jsUndefined(); - - String targetOrigin = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(targetOriginArgIndex)); - if (exec->hadException()) - return jsUndefined(); - - ExceptionCode ec = 0; - impl->postMessage(message.release(), &messagePorts, targetOrigin, activeDOMWindow(exec), ec); - setDOMException(exec, ec); - - return jsUndefined(); -} - -JSValue JSDOMWindow::postMessage(ExecState* exec) -{ - return handlePostMessage(&impl(), exec); -} - -JSValue JSDOMWindow::setTimeout(ExecState* exec) -{ - ContentSecurityPolicy* contentSecurityPolicy = impl().document() ? impl().document()->contentSecurityPolicy() : 0; - OwnPtr<ScheduledAction> action = ScheduledAction::create(exec, currentWorld(exec), contentSecurityPolicy); - if (exec->hadException()) - return jsUndefined(); + if (UNLIKELY(state.argumentCount() < 1)) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + auto* contentSecurityPolicy = wrapped().document() ? wrapped().document()->contentSecurityPolicy() : nullptr; + auto action = ScheduledAction::create(&state, globalObject()->world(), contentSecurityPolicy); + RETURN_IF_EXCEPTION(scope, JSValue()); if (!action) return jsNumber(0); - int delay = exec->argument(1).toInt32(exec); - - ExceptionCode ec = 0; - int result = impl().setTimeout(action.release(), delay, ec); - setDOMException(exec, ec); - - return jsNumber(result); + int delay = state.argument(1).toInt32(&state); + return toJS<IDLLong>(state, scope, wrapped().setTimeout(WTFMove(action), delay)); } -JSValue JSDOMWindow::setInterval(ExecState* exec) +JSValue JSDOMWindow::setInterval(ExecState& state) { - 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); + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + if (UNLIKELY(state.argumentCount() < 1)) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + + auto* contentSecurityPolicy = wrapped().document() ? wrapped().document()->contentSecurityPolicy() : nullptr; + auto action = ScheduledAction::create(&state, globalObject()->world(), contentSecurityPolicy); + RETURN_IF_EXCEPTION(scope, JSValue()); if (!action) return jsNumber(0); - ExceptionCode ec = 0; - int result = impl().setInterval(action.release(), delay, ec); - setDOMException(exec, ec); - - return jsNumber(result); -} - -JSValue JSDOMWindow::addEventListener(ExecState* exec) -{ - Frame* frame = impl().frame(); - if (!frame) - return jsUndefined(); - - JSValue listener = exec->argument(1); - if (!listener.isObject()) - return jsUndefined(); - - impl().addEventListener(exec->argument(0).toString(exec)->value(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)), exec->argument(2).toBoolean(exec)); - return jsUndefined(); + int delay = state.argument(1).toInt32(&state); + return toJS<IDLLong>(state, scope, wrapped().setInterval(WTFMove(action), delay)); } -JSValue JSDOMWindow::removeEventListener(ExecState* exec) -{ - Frame* frame = impl().frame(); - if (!frame) - return jsUndefined(); - - JSValue listener = exec->argument(1); - if (!listener.isObject()) - return jsUndefined(); - - impl().removeEventListener(exec->argument(0).toString(exec)->value(exec), JSEventListener::create(asObject(listener), this, false, currentWorld(exec)).get(), exec->argument(2).toBoolean(exec)); - return jsUndefined(); -} - -DOMWindow* toDOMWindow(JSValue value) +DOMWindow* JSDOMWindow::toWrapped(VM& vm, JSValue value) { if (!value.isObject()) - return 0; + return nullptr; JSObject* object = asObject(value); - if (object->inherits(JSDOMWindow::info())) - return &jsCast<JSDOMWindow*>(object)->impl(); - if (object->inherits(JSDOMWindowShell::info())) - return &jsCast<JSDOMWindowShell*>(object)->impl(); - return 0; + if (object->inherits(vm, JSDOMWindow::info())) + return &jsCast<JSDOMWindow*>(object)->wrapped(); + if (object->inherits(vm, JSDOMWindowShell::info())) + return &jsCast<JSDOMWindowShell*>(object)->wrapped(); + return nullptr; } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMWindowCustom.h b/Source/WebCore/bindings/js/JSDOMWindowCustom.h index b72ff0d05..ab629d6dc 100644 --- a/Source/WebCore/bindings/js/JSDOMWindowCustom.h +++ b/Source/WebCore/bindings/js/JSDOMWindowCustom.h @@ -16,8 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef JSDOMWindowCustom_h -#define JSDOMWindowCustom_h +#pragma once #include "JSDOMWindow.h" #include "JSDOMWindowShell.h" @@ -34,6 +33,4 @@ inline const JSDOMWindow* asJSDOMWindow(const JSC::JSGlobalObject* globalObject) return static_cast<const JSDOMWindow*>(globalObject); } -} - -#endif // JSDOMWindowCustom_h +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMWindowProperties.cpp b/Source/WebCore/bindings/js/JSDOMWindowProperties.cpp new file mode 100644 index 000000000..c364f2fde --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMWindowProperties.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2016 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 "JSDOMWindowProperties.h" + +#include "Frame.h" +#include "HTMLDocument.h" +#include "JSDOMBinding.h" +#include "JSDOMBindingSecurity.h" +#include "JSDOMWindowBase.h" +#include "JSElement.h" +#include "JSHTMLCollection.h" + +namespace WebCore { + +using namespace JSC; + +const ClassInfo JSDOMWindowProperties::s_info = { "WindowProperties", &Base::s_info, 0, CREATE_METHOD_TABLE(JSDOMWindowProperties) }; + +static bool jsDOMWindowPropertiesGetOwnPropertySlotNamedItemGetter(JSDOMWindowProperties* thisObject, Frame& frame, ExecState* exec, PropertyName propertyName, PropertySlot& slot) +{ + // Check for child frames by name before built-in properties to match Mozilla. This does + // not match IE, but some sites end up naming frames things that conflict with window + // properties that are in Moz but not IE. Since we have some of these, we have to do it + // the Moz way. + if (auto* scopedChild = frame.tree().scopedChild(propertyNameToAtomicString(propertyName))) { + slot.setValue(thisObject, ReadOnly | DontDelete | DontEnum, toJS(exec, scopedChild->document()->domWindow())); + return true; + } + + if (!BindingSecurity::shouldAllowAccessToFrame(exec, &frame, ThrowSecurityError)) + return false; + + // FIXME: Search the whole frame hierarchy somewhere around here. + // We need to test the correct priority order. + + // Allow shortcuts like 'Image1' instead of document.images.Image1 + Document* document = frame.document(); + if (is<HTMLDocument>(*document)) { + auto& htmlDocument = downcast<HTMLDocument>(*document); + auto* atomicPropertyName = propertyName.publicName(); + if (atomicPropertyName && htmlDocument.hasWindowNamedItem(*atomicPropertyName)) { + JSValue namedItem; + if (UNLIKELY(htmlDocument.windowNamedItemContainsMultipleElements(*atomicPropertyName))) { + Ref<HTMLCollection> collection = document->windowNamedItems(atomicPropertyName); + ASSERT(collection->length() > 1); + namedItem = toJS(exec, thisObject->globalObject(), collection); + } else + namedItem = toJS(exec, thisObject->globalObject(), htmlDocument.windowNamedItem(*atomicPropertyName)); + slot.setValue(thisObject, ReadOnly | DontDelete | DontEnum, namedItem); + return true; + } + } + + return false; +} + +bool JSDOMWindowProperties::getOwnPropertySlot(JSObject* object, ExecState* state, PropertyName propertyName, PropertySlot& slot) +{ + auto* thisObject = jsCast<JSDOMWindowProperties*>(object); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + if (Base::getOwnPropertySlot(thisObject, state, propertyName, slot)) + return true; + JSValue proto = thisObject->getPrototypeDirect(); + if (proto.isObject() && jsCast<JSObject*>(proto)->hasProperty(state, propertyName)) + return false; + + auto& window = jsCast<JSDOMWindowBase*>(thisObject->globalObject())->wrapped(); + if (auto* frame = window.frame()) + return jsDOMWindowPropertiesGetOwnPropertySlotNamedItemGetter(thisObject, *frame, state, propertyName, slot); + + return false; +} + +bool JSDOMWindowProperties::getOwnPropertySlotByIndex(JSObject* object, ExecState* state, unsigned index, PropertySlot& slot) +{ + return getOwnPropertySlot(object, state, Identifier::from(state, index), slot); +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMWindowProperties.h b/Source/WebCore/bindings/js/JSDOMWindowProperties.h new file mode 100644 index 000000000..a3c47de31 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMWindowProperties.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "DOMWindow.h" +#include "JSDOMWindow.h" +#include "JSDOMWrapper.h" + +namespace WebCore { + +class JSDOMWindowProperties : public JSDOMObject { +public: + static JSDOMWindowProperties* create(JSC::Structure* structure, JSC::JSGlobalObject& globalObject) + { + JSDOMWindowProperties* ptr = new (NotNull, JSC::allocateCell<JSDOMWindowProperties>(globalObject.vm().heap)) JSDOMWindowProperties(structure, globalObject); + ptr->finishCreation(globalObject.vm()); + return ptr; + } + + DECLARE_INFO; + + static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) + { + return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); + } + + static bool getOwnPropertySlot(JSC::JSObject*, JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&); + static bool getOwnPropertySlotByIndex(JSC::JSObject*, JSC::ExecState*, unsigned propertyName, JSC::PropertySlot&); + + static const unsigned StructureFlags = JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::IsImmutablePrototypeExoticObject | Base::StructureFlags; + +protected: + JSDOMWindowProperties(JSC::Structure* structure, JSC::JSGlobalObject& globalObject) + : JSDOMObject(structure, globalObject) + { } +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMWindowShell.cpp b/Source/WebCore/bindings/js/JSDOMWindowShell.cpp index b5fc83e99..a42a030e9 100644 --- a/Source/WebCore/bindings/js/JSDOMWindowShell.cpp +++ b/Source/WebCore/bindings/js/JSDOMWindowShell.cpp @@ -10,7 +10,7 @@ * 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -29,10 +29,12 @@ #include "config.h" #include "JSDOMWindowShell.h" +#include "CommonVM.h" #include "Frame.h" #include "GCController.h" #include "JSDOMWindow.h" -#include "DOMWindow.h" +#include "JSDOMWindowProperties.h" +#include "JSEventTarget.h" #include "ScriptController.h" #include <heap/StrongInlines.h> #include <runtime/JSObject.h> @@ -41,7 +43,7 @@ using namespace JSC; namespace WebCore { -const ClassInfo JSDOMWindowShell::s_info = { "JSDOMWindowShell", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSDOMWindowShell) }; +const ClassInfo JSDOMWindowShell::s_info = { "JSDOMWindowShell", &Base::s_info, 0, CREATE_METHOD_TABLE(JSDOMWindowShell) }; JSDOMWindowShell::JSDOMWindowShell(VM& vm, Structure* structure, DOMWrapperWorld& world) : Base(vm, structure) @@ -49,11 +51,11 @@ JSDOMWindowShell::JSDOMWindowShell(VM& vm, Structure* structure, DOMWrapperWorld { } -void JSDOMWindowShell::finishCreation(VM& vm, PassRefPtr<DOMWindow> window) +void JSDOMWindowShell::finishCreation(VM& vm, RefPtr<DOMWindow>&& window) { Base::finishCreation(vm); - ASSERT(inherits(info())); - setWindow(window); + ASSERT(inherits(vm, info())); + setWindow(WTFMove(window)); } void JSDOMWindowShell::destroy(JSCell* cell) @@ -66,25 +68,30 @@ void JSDOMWindowShell::setWindow(VM& vm, JSDOMWindow* window) ASSERT_ARG(window, window); setTarget(vm, window); structure()->setGlobalObject(vm, window); - gcController().garbageCollectSoon(); + GCController::singleton().garbageCollectSoon(); } -void JSDOMWindowShell::setWindow(PassRefPtr<DOMWindow> domWindow) +void JSDOMWindowShell::setWindow(RefPtr<DOMWindow>&& domWindow) { // Replacing JSDOMWindow via telling JSDOMWindowShell to use the same DOMWindow it already uses makes no sense, // so we'd better never try to. - ASSERT(!window() || domWindow.get() != &window()->impl()); + ASSERT(!window() || domWindow.get() != &window()->wrapped()); // 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.) - VM& vm = *JSDOMWindow::commonVM(); + VM& vm = commonVM(); Structure* prototypeStructure = JSDOMWindowPrototype::createStructure(vm, 0, jsNull()); Strong<JSDOMWindowPrototype> prototype(vm, JSDOMWindowPrototype::create(vm, 0, prototypeStructure)); Structure* structure = JSDOMWindow::createStructure(vm, 0, prototype.get()); - JSDOMWindow* jsDOMWindow = JSDOMWindow::create(vm, structure, domWindow, this); + JSDOMWindow* jsDOMWindow = JSDOMWindow::create(vm, structure, *domWindow, this); prototype->structure()->setGlobalObject(vm, jsDOMWindow); + + Structure* windowPropertiesStructure = JSDOMWindowProperties::createStructure(vm, jsDOMWindow, JSEventTarget::prototype(vm, jsDOMWindow)); + JSDOMWindowProperties* windowProperties = JSDOMWindowProperties::create(windowPropertiesStructure, *jsDOMWindow); + + prototype->structure()->setPrototypeWithoutTransition(vm, windowProperties); setWindow(vm, jsDOMWindow); ASSERT(jsDOMWindow->globalObject() == jsDOMWindow); ASSERT(prototype->globalObject() == jsDOMWindow); @@ -94,9 +101,17 @@ void JSDOMWindowShell::setWindow(PassRefPtr<DOMWindow> domWindow) // JSDOMWindow methods // ---- -DOMWindow& JSDOMWindowShell::impl() const +DOMWindow& JSDOMWindowShell::wrapped() const +{ + return window()->wrapped(); +} + +DOMWindow* JSDOMWindowShell::toWrapped(VM& vm, JSObject* value) { - return window()->impl(); + auto* wrapper = jsDynamicDowncast<JSDOMWindowShell*>(vm, value); + if (!wrapper) + return nullptr; + return &wrapper->window()->wrapped(); } // ---- diff --git a/Source/WebCore/bindings/js/JSDOMWindowShell.h b/Source/WebCore/bindings/js/JSDOMWindowShell.h index 85a6fd873..17129237b 100644 --- a/Source/WebCore/bindings/js/JSDOMWindowShell.h +++ b/Source/WebCore/bindings/js/JSDOMWindowShell.h @@ -10,7 +10,7 @@ * 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -26,15 +26,14 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSDOMWindowShell_h -#define JSDOMWindowShell_h +#pragma once +#include "DOMWindow.h" #include "JSDOMWindow.h" #include <runtime/JSProxy.h> namespace WebCore { - class DOMWindow; class Frame; class JSDOMWindowShell : public JSC::JSProxy { @@ -44,29 +43,30 @@ namespace WebCore { JSDOMWindow* window() const { return JSC::jsCast<JSDOMWindow*>(target()); } void setWindow(JSC::VM&, JSDOMWindow*); - void setWindow(PassRefPtr<DOMWindow>); + void setWindow(RefPtr<DOMWindow>&&); DECLARE_INFO; - DOMWindow& impl() const; + DOMWindow& wrapped() const; + static WEBCORE_EXPORT DOMWindow* toWrapped(JSC::VM&, JSC::JSObject*); - static JSDOMWindowShell* create(JSC::VM& vm, PassRefPtr<DOMWindow> window, JSC::Structure* structure, DOMWrapperWorld& world) + static JSDOMWindowShell* create(JSC::VM& vm, RefPtr<DOMWindow>&& window, JSC::Structure* structure, DOMWrapperWorld& world) { JSDOMWindowShell* shell = new (NotNull, JSC::allocateCell<JSDOMWindowShell>(vm.heap)) JSDOMWindowShell(vm, structure, world); - shell->finishCreation(vm, window); + shell->finishCreation(vm, WTFMove(window)); return shell; } static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSValue prototype) { - return JSC::Structure::create(vm, 0, prototype, JSC::TypeInfo(JSC::ProxyType, StructureFlags), info()); + return JSC::Structure::create(vm, 0, prototype, JSC::TypeInfo(JSC::PureForwardingProxyType, StructureFlags), info()); } - DOMWrapperWorld& world() { return m_world.get(); } + DOMWrapperWorld& world() { return m_world; } protected: JSDOMWindowShell(JSC::VM&, JSC::Structure*, DOMWrapperWorld&); - void finishCreation(JSC::VM&, PassRefPtr<DOMWindow>); + void finishCreation(JSC::VM&, RefPtr<DOMWindow>&&); Ref<DOMWrapperWorld> m_world; }; @@ -75,5 +75,3 @@ namespace WebCore { JSDOMWindowShell* toJSDOMWindowShell(Frame*, DOMWrapperWorld&); } // namespace WebCore - -#endif // JSDOMWindowShell_h diff --git a/Source/WebCore/bindings/js/JSDOMWrapper.cpp b/Source/WebCore/bindings/js/JSDOMWrapper.cpp index 1629ae57e..21da86365 100644 --- a/Source/WebCore/bindings/js/JSDOMWrapper.cpp +++ b/Source/WebCore/bindings/js/JSDOMWrapper.cpp @@ -26,12 +26,32 @@ #include "config.h" #include "JSDOMWrapper.h" +#include "DOMWrapperWorld.h" +#include "JSDOMWindow.h" +#include "WebCoreJSClientData.h" #include <runtime/Error.h> using namespace JSC; namespace WebCore { -STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSDOMWrapper); +STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSDOMObject); + +JSDOMWindow& JSDOMObject::domWindow() const +{ + auto* domWindow = JSC::jsCast<JSDOMWindow*>(JSC::JSNonFinalObject::globalObject()); + ASSERT(domWindow); + return *domWindow; +} + +Subspace* outputConstraintSubspaceFor(VM& vm) +{ + return &static_cast<JSVMClientData*>(vm.clientData)->outputConstraintSpace(); +} + +Subspace* globalObjectOutputConstraintSubspaceFor(VM& vm) +{ + return &static_cast<JSVMClientData*>(vm.clientData)->globalObjectOutputConstraintSpace(); +} } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMWrapper.h b/Source/WebCore/bindings/js/JSDOMWrapper.h index 026dcd931..11d439ce2 100644 --- a/Source/WebCore/bindings/js/JSDOMWrapper.h +++ b/Source/WebCore/bindings/js/JSDOMWrapper.h @@ -19,31 +19,101 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef JSDOMWrapper_h -#define JSDOMWrapper_h +#pragma once #include "JSDOMGlobalObject.h" +#include "NodeConstants.h" #include <runtime/JSDestructibleObject.h> namespace WebCore { +class JSDOMWindow; class ScriptExecutionContext; -class JSDOMWrapper : public JSC::JSDestructibleObject { +// JSC allows us to extend JSType. If the highest bit is set, we can add any Object types and they are +// recognized as OtherObj in JSC. And we encode Node type into JSType if the given JSType is subclass of Node. +// offset | 7 | 6 | 5 4 | 3 2 1 0 | +// value | 1 | 0 | Non-node DOM types | +// If the given JSType is a subclass of Node, the format is the following. +// offset | 7 | 6 | 5 4 | 3 2 1 0 | +// value | 1 | 1 | Kind | NodeType | +static const uint8_t JSNodeTypeMask = 0b00001111; + +static const uint8_t JSDOMWrapperType = 0b10000000; +static const uint8_t JSEventType = 0b10000001; +static const uint8_t JSNodeType = 0b11000000; +static const uint8_t JSTextNodeType = JSNodeType | NodeConstants::TEXT_NODE; +static const uint8_t JSProcessingInstructionNodeType = JSNodeType | NodeConstants::PROCESSING_INSTRUCTION_NODE; +static const uint8_t JSDocumentTypeNodeType = JSNodeType | NodeConstants::DOCUMENT_TYPE_NODE; +static const uint8_t JSDocumentFragmentNodeType = JSNodeType | NodeConstants::DOCUMENT_FRAGMENT_NODE; +static const uint8_t JSDocumentWrapperType = JSNodeType | NodeConstants::DOCUMENT_NODE; +static const uint8_t JSCommentNodeType = JSNodeType | NodeConstants::COMMENT_NODE; +static const uint8_t JSCDATASectionNodeType = JSNodeType | NodeConstants::CDATA_SECTION_NODE; +static const uint8_t JSAttrNodeType = JSNodeType | NodeConstants::ATTRIBUTE_NODE; +static const uint8_t JSElementType = 0b11010000 | NodeConstants::ELEMENT_NODE; + +static_assert(JSDOMWrapperType > JSC::LastJSCObjectType, "JSC::JSType offers the highest bit."); +static_assert(NodeConstants::LastNodeType <= JSNodeTypeMask, "NodeType should be represented in 4bit."); + +class JSDOMObject : public JSC::JSDestructibleObject { public: typedef JSC::JSDestructibleObject Base; + static constexpr bool isDOMWrapper = false; JSDOMGlobalObject* globalObject() const { return JSC::jsCast<JSDOMGlobalObject*>(JSC::JSNonFinalObject::globalObject()); } ScriptExecutionContext* scriptExecutionContext() const { return globalObject()->scriptExecutionContext(); } + JSDOMWindow& domWindow() const; + protected: - JSDOMWrapper(JSC::Structure* structure, JSC::JSGlobalObject* globalObject) - : JSDestructibleObject(globalObject->vm(), structure) + JSDOMObject(JSC::Structure* structure, JSC::JSGlobalObject& globalObject) + : Base(globalObject.vm(), structure) { ASSERT(scriptExecutionContext()); } }; -} // namespace WebCore +WEBCORE_EXPORT JSC::Subspace* outputConstraintSubspaceFor(JSC::VM&); +WEBCORE_EXPORT JSC::Subspace* globalObjectOutputConstraintSubspaceFor(JSC::VM&); + +template<typename ImplementationClass> class JSDOMWrapper : public JSDOMObject { +public: + typedef JSDOMObject Base; + typedef ImplementationClass DOMWrapped; + static constexpr bool isDOMWrapper = true; + + ImplementationClass& wrapped() const { return m_wrapped; } + static ptrdiff_t offsetOfWrapped() { return OBJECT_OFFSETOF(JSDOMWrapper<ImplementationClass>, m_wrapped); } + +protected: + JSDOMWrapper(JSC::Structure* structure, JSC::JSGlobalObject& globalObject, Ref<ImplementationClass>&& impl) + : Base(structure, globalObject) + , m_wrapped(WTFMove(impl)) { } + +private: + Ref<ImplementationClass> m_wrapped; +}; + +template<typename ImplementationClass> struct JSDOMWrapperConverterTraits; + +template<typename JSClass, typename Enable = void> +struct JSDOMObjectInspector { +public: + static constexpr bool isSimpleWrapper = false; + static constexpr bool isComplexWrapper = false; + static constexpr bool isBuiltin = true; +}; -#endif // JSDOMWrapper_h +template<typename JSClass> +struct JSDOMObjectInspector<JSClass, typename std::enable_if<JSClass::isDOMWrapper>::type> { +private: + template<typename T> static constexpr auto test(int) -> decltype(T::create(), bool()) { return true; } + template<typename T> static constexpr bool test(...) { return false; } + +public: + static constexpr bool isSimpleWrapper = test<typename JSClass::DOMWrapped>(0); + static constexpr bool isComplexWrapper = !isSimpleWrapper; + static constexpr bool isBuiltin = false; +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMWrapperCache.cpp b/Source/WebCore/bindings/js/JSDOMWrapperCache.cpp new file mode 100644 index 000000000..6d875d58a --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMWrapperCache.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2004-2011, 2013, 2016 Apple Inc. All rights reserved. + * Copyright (C) 2007 Samuel Weinig <sam@webkit.org> + * Copyright (C) 2013 Michael Pruett <michael@68k.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "JSDOMWrapperCache.h" + +#include <runtime/JSCInlines.h> + +using namespace JSC; + +namespace WebCore { + +Structure* getCachedDOMStructure(JSDOMGlobalObject& globalObject, const ClassInfo* classInfo) +{ + JSDOMStructureMap& structures = globalObject.structures(NoLockingNecessary); + return structures.get(classInfo).get(); +} + +Structure* cacheDOMStructure(JSDOMGlobalObject& globalObject, Structure* structure, const ClassInfo* classInfo) +{ + auto locker = lockDuringMarking(globalObject.vm().heap, globalObject.gcLock()); + JSDOMStructureMap& structures = globalObject.structures(locker); + ASSERT(!structures.contains(classInfo)); + return structures.set(classInfo, WriteBarrier<Structure>(globalObject.vm(), &globalObject, structure)).iterator->value.get(); +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDOMWrapperCache.h b/Source/WebCore/bindings/js/JSDOMWrapperCache.h new file mode 100644 index 000000000..dd8c4b206 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDOMWrapperCache.h @@ -0,0 +1,206 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2003-2006, 2008-2009, 2013, 2016 Apple Inc. All rights reserved. + * Copyright (C) 2007 Samuel Weinig <sam@webkit.org> + * Copyright (C) 2009 Google, Inc. All rights reserved. + * Copyright (C) 2012 Ericsson AB. All rights reserved. + * Copyright (C) 2013 Michael Pruett <michael@68k.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "DOMWrapperWorld.h" +#include "JSDOMGlobalObject.h" +#include "JSDOMWrapper.h" +#include "JSDynamicDowncast.h" +#include "ScriptWrappable.h" +#include "ScriptWrappableInlines.h" +#include "WebCoreTypedArrayController.h" +#include <heap/Weak.h> +#include <heap/WeakInlines.h> +#include <runtime/JSArrayBuffer.h> +#include <runtime/TypedArrayInlines.h> +#include <runtime/TypedArrays.h> + +namespace WebCore { + +WEBCORE_EXPORT JSC::Structure* getCachedDOMStructure(JSDOMGlobalObject&, const JSC::ClassInfo*); +WEBCORE_EXPORT JSC::Structure* cacheDOMStructure(JSDOMGlobalObject&, JSC::Structure*, const JSC::ClassInfo*); + +template<typename WrapperClass> JSC::Structure* getDOMStructure(JSC::VM&, JSDOMGlobalObject&); +template<typename WrapperClass> JSC::Structure* deprecatedGetDOMStructure(JSC::ExecState*); +template<typename WrapperClass> JSC::JSObject* getDOMPrototype(JSC::VM&, JSC::JSGlobalObject*); + +JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld&, JSC::ArrayBuffer*); +void* wrapperKey(JSC::ArrayBuffer*); + +JSDOMObject* getInlineCachedWrapper(DOMWrapperWorld&, void*); +JSDOMObject* getInlineCachedWrapper(DOMWrapperWorld&, ScriptWrappable*); +JSC::JSArrayBuffer* getInlineCachedWrapper(DOMWrapperWorld&, JSC::ArrayBuffer*); + +bool setInlineCachedWrapper(DOMWrapperWorld&, void*, JSDOMObject*, JSC::WeakHandleOwner*); +bool setInlineCachedWrapper(DOMWrapperWorld&, ScriptWrappable*, JSDOMObject* wrapper, JSC::WeakHandleOwner* wrapperOwner); +bool setInlineCachedWrapper(DOMWrapperWorld&, JSC::ArrayBuffer*, JSC::JSArrayBuffer* wrapper, JSC::WeakHandleOwner* wrapperOwner); + +bool clearInlineCachedWrapper(DOMWrapperWorld&, void*, JSDOMObject*); +bool clearInlineCachedWrapper(DOMWrapperWorld&, ScriptWrappable*, JSDOMObject* wrapper); +bool clearInlineCachedWrapper(DOMWrapperWorld&, JSC::ArrayBuffer*, JSC::JSArrayBuffer* wrapper); + +template<typename DOMClass> JSC::JSObject* getCachedWrapper(DOMWrapperWorld&, DOMClass&); +template<typename DOMClass> inline JSC::JSObject* getCachedWrapper(DOMWrapperWorld& world, Ref<DOMClass>& object) { return getCachedWrapper(world, object.get()); } +template<typename DOMClass, typename WrapperClass> void cacheWrapper(DOMWrapperWorld&, DOMClass*, WrapperClass*); +template<typename DOMClass, typename WrapperClass> void uncacheWrapper(DOMWrapperWorld&, DOMClass*, WrapperClass*); +template<typename DOMClass, typename T> auto createWrapper(JSDOMGlobalObject*, Ref<T>&&) -> typename std::enable_if<std::is_same<DOMClass, T>::value, typename JSDOMWrapperConverterTraits<DOMClass>::WrapperClass*>::type; +template<typename DOMClass, typename T> auto createWrapper(JSDOMGlobalObject*, Ref<T>&&) -> typename std::enable_if<!std::is_same<DOMClass, T>::value, typename JSDOMWrapperConverterTraits<DOMClass>::WrapperClass*>::type; + +template<typename DOMClass> JSC::JSValue wrap(JSC::ExecState*, JSDOMGlobalObject*, DOMClass&); + + +// Inline functions and template definitions. + +inline JSDOMGlobalObject* deprecatedGlobalObjectForPrototype(JSC::ExecState* exec) +{ + // FIXME: Callers to this function should be using the global object + // from which the object is being created, instead of assuming the lexical one. + // e.g. subframe.document.body should use the subframe's global object, not the lexical one. + return JSC::jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()); +} + +template<typename WrapperClass> inline JSC::Structure* getDOMStructure(JSC::VM& vm, JSDOMGlobalObject& globalObject) +{ + if (JSC::Structure* structure = getCachedDOMStructure(globalObject, WrapperClass::info())) + return structure; + return cacheDOMStructure(globalObject, WrapperClass::createStructure(vm, &globalObject, WrapperClass::createPrototype(vm, &globalObject)), WrapperClass::info()); +} + +template<typename 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->vm(), *deprecatedGlobalObjectForPrototype(exec)); +} + +template<typename WrapperClass> inline JSC::JSObject* getDOMPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject) +{ + return JSC::jsCast<JSC::JSObject*>(asObject(getDOMStructure<WrapperClass>(vm, *JSC::jsCast<JSDOMGlobalObject*>(globalObject))->storedPrototype())); +} + +inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld& world, JSC::ArrayBuffer*) +{ + return static_cast<WebCoreTypedArrayController*>(world.vm().m_typedArrayController.get())->wrapperOwner(); +} + +inline void* wrapperKey(JSC::ArrayBuffer* domObject) +{ + return domObject; +} + +inline JSDOMObject* getInlineCachedWrapper(DOMWrapperWorld&, void*) { return nullptr; } +inline bool setInlineCachedWrapper(DOMWrapperWorld&, void*, JSDOMObject*, JSC::WeakHandleOwner*) { return false; } +inline bool clearInlineCachedWrapper(DOMWrapperWorld&, void*, JSDOMObject*) { return false; } + +inline JSDOMObject* getInlineCachedWrapper(DOMWrapperWorld& world, ScriptWrappable* domObject) +{ + if (!world.isNormal()) + return nullptr; + return domObject->wrapper(); +} + +inline JSC::JSArrayBuffer* getInlineCachedWrapper(DOMWrapperWorld& world, JSC::ArrayBuffer* buffer) +{ + if (!world.isNormal()) + return nullptr; + return buffer->m_wrapper.get(); +} + +inline bool setInlineCachedWrapper(DOMWrapperWorld& world, ScriptWrappable* domObject, JSDOMObject* wrapper, JSC::WeakHandleOwner* wrapperOwner) +{ + if (!world.isNormal()) + return false; + domObject->setWrapper(wrapper, wrapperOwner, &world); + return true; +} + +inline bool setInlineCachedWrapper(DOMWrapperWorld& world, JSC::ArrayBuffer* domObject, JSC::JSArrayBuffer* wrapper, JSC::WeakHandleOwner* wrapperOwner) +{ + if (!world.isNormal()) + return false; + domObject->m_wrapper = JSC::Weak<JSC::JSArrayBuffer>(wrapper, wrapperOwner, &world); + return true; +} + +inline bool clearInlineCachedWrapper(DOMWrapperWorld& world, ScriptWrappable* domObject, JSDOMObject* wrapper) +{ + if (!world.isNormal()) + return false; + domObject->clearWrapper(wrapper); + return true; +} + +inline bool clearInlineCachedWrapper(DOMWrapperWorld& world, JSC::ArrayBuffer* domObject, JSC::JSArrayBuffer* wrapper) +{ + if (!world.isNormal()) + return false; + weakClear(domObject->m_wrapper, wrapper); + return true; +} + +template<typename DOMClass> inline JSC::JSObject* getCachedWrapper(DOMWrapperWorld& world, DOMClass& domObject) +{ + if (auto* wrapper = getInlineCachedWrapper(world, &domObject)) + return wrapper; + return world.m_wrappers.get(wrapperKey(&domObject)); +} + +template<typename DOMClass, typename WrapperClass> inline void cacheWrapper(DOMWrapperWorld& world, DOMClass* domObject, WrapperClass* wrapper) +{ + JSC::WeakHandleOwner* owner = wrapperOwner(world, domObject); + if (setInlineCachedWrapper(world, domObject, wrapper, owner)) + return; + weakAdd(world.m_wrappers, wrapperKey(domObject), JSC::Weak<JSC::JSObject>(wrapper, owner, &world)); +} + +template<typename DOMClass, typename WrapperClass> inline void uncacheWrapper(DOMWrapperWorld& world, DOMClass* domObject, WrapperClass* wrapper) +{ + if (clearInlineCachedWrapper(world, domObject, wrapper)) + return; + weakRemove(world.m_wrappers, wrapperKey(domObject), wrapper); +} + +template<typename DOMClass, typename T> inline auto createWrapper(JSDOMGlobalObject* globalObject, Ref<T>&& domObject) -> typename std::enable_if<std::is_same<DOMClass, T>::value, typename JSDOMWrapperConverterTraits<DOMClass>::WrapperClass*>::type +{ + using WrapperClass = typename JSDOMWrapperConverterTraits<DOMClass>::WrapperClass; + + ASSERT(!getCachedWrapper(globalObject->world(), domObject)); + auto* domObjectPtr = domObject.ptr(); + auto* wrapper = WrapperClass::create(getDOMStructure<WrapperClass>(globalObject->vm(), *globalObject), globalObject, WTFMove(domObject)); + cacheWrapper(globalObject->world(), domObjectPtr, wrapper); + return wrapper; +} + +template<typename DOMClass, typename T> inline auto createWrapper(JSDOMGlobalObject* globalObject, Ref<T>&& domObject) -> typename std::enable_if<!std::is_same<DOMClass, T>::value, typename JSDOMWrapperConverterTraits<DOMClass>::WrapperClass*>::type +{ + return createWrapper<DOMClass>(globalObject, static_reference_cast<DOMClass>(WTFMove(domObject))); +} + +template<typename DOMClass> inline JSC::JSValue wrap(JSC::ExecState* state, JSDOMGlobalObject* globalObject, DOMClass& domObject) +{ + if (auto* wrapper = getCachedWrapper(globalObject->world(), domObject)) + return wrapper; + return toJSNewlyCreated(state, globalObject, Ref<DOMClass>(domObject)); +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDedicatedWorkerGlobalScopeCustom.cpp b/Source/WebCore/bindings/js/JSDedicatedWorkerGlobalScopeCustom.cpp deleted file mode 100644 index ea62e28ed..000000000 --- a/Source/WebCore/bindings/js/JSDedicatedWorkerGlobalScopeCustom.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2009 Apple, 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 - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "JSDedicatedWorkerGlobalScope.h" - -#include "JSDOMBinding.h" -#include "JSMessagePortCustom.h" - -using namespace JSC; - -namespace WebCore { - -JSC::JSValue JSDedicatedWorkerGlobalScope::postMessage(JSC::ExecState* exec) -{ - return handlePostMessage(exec, &impl()); -} - -} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDeviceMotionEventCustom.cpp b/Source/WebCore/bindings/js/JSDeviceMotionEventCustom.cpp deleted file mode 100644 index b4d5c4f8d..000000000 --- a/Source/WebCore/bindings/js/JSDeviceMotionEventCustom.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2010 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#if ENABLE(DEVICE_ORIENTATION) - -#include "JSDeviceMotionEvent.h" - -#include "DeviceMotionData.h" -#include "DeviceMotionEvent.h" -#include <runtime/ObjectConstructor.h> - -using namespace JSC; - -namespace WebCore { - -static PassRefPtr<DeviceMotionData::Acceleration> readAccelerationArgument(JSValue value, ExecState* exec) -{ - if (value.isUndefinedOrNull()) - return 0; - - // Given the above test, this will always yield an object. - JSObject* object = value.toObject(exec); - - JSValue xValue = object->get(exec, Identifier(exec, "x")); - if (exec->hadException()) - return 0; - bool canProvideX = !xValue.isUndefinedOrNull(); - double x = xValue.toNumber(exec); - if (exec->hadException()) - return 0; - - JSValue yValue = object->get(exec, Identifier(exec, "y")); - if (exec->hadException()) - return 0; - bool canProvideY = !yValue.isUndefinedOrNull(); - double y = yValue.toNumber(exec); - if (exec->hadException()) - return 0; - - JSValue zValue = object->get(exec, Identifier(exec, "z")); - if (exec->hadException()) - return 0; - bool canProvideZ = !zValue.isUndefinedOrNull(); - double z = zValue.toNumber(exec); - if (exec->hadException()) - return 0; - - if (!canProvideX && !canProvideY && !canProvideZ) - return 0; - - return DeviceMotionData::Acceleration::create(canProvideX, x, canProvideY, y, canProvideZ, z); -} - -static PassRefPtr<DeviceMotionData::RotationRate> readRotationRateArgument(JSValue value, ExecState* exec) -{ - if (value.isUndefinedOrNull()) - return 0; - - // Given the above test, this will always yield an object. - JSObject* object = value.toObject(exec); - - JSValue alphaValue = object->get(exec, Identifier(exec, "alpha")); - if (exec->hadException()) - return 0; - bool canProvideAlpha = !alphaValue.isUndefinedOrNull(); - double alpha = alphaValue.toNumber(exec); - if (exec->hadException()) - return 0; - - JSValue betaValue = object->get(exec, Identifier(exec, "beta")); - if (exec->hadException()) - return 0; - bool canProvideBeta = !betaValue.isUndefinedOrNull(); - double beta = betaValue.toNumber(exec); - if (exec->hadException()) - return 0; - - JSValue gammaValue = object->get(exec, Identifier(exec, "gamma")); - if (exec->hadException()) - return 0; - bool canProvideGamma = !gammaValue.isUndefinedOrNull(); - double gamma = gammaValue.toNumber(exec); - if (exec->hadException()) - return 0; - - if (!canProvideAlpha && !canProvideBeta && !canProvideGamma) - return 0; - - return DeviceMotionData::RotationRate::create(canProvideAlpha, alpha, canProvideBeta, beta, canProvideGamma, gamma); -} - -static JSObject* createAccelerationObject(const DeviceMotionData::Acceleration* acceleration, ExecState* exec) -{ - JSObject* object = constructEmptyObject(exec); - object->putDirect(exec->vm(), Identifier(exec, "x"), acceleration->canProvideX() ? jsNumber(acceleration->x()) : jsNull()); - object->putDirect(exec->vm(), Identifier(exec, "y"), acceleration->canProvideY() ? jsNumber(acceleration->y()) : jsNull()); - object->putDirect(exec->vm(), Identifier(exec, "z"), acceleration->canProvideZ() ? jsNumber(acceleration->z()) : jsNull()); - return object; -} - -static JSObject* createRotationRateObject(const DeviceMotionData::RotationRate* rotationRate, ExecState* exec) -{ - JSObject* object = constructEmptyObject(exec); - object->putDirect(exec->vm(), Identifier(exec, "alpha"), rotationRate->canProvideAlpha() ? jsNumber(rotationRate->alpha()) : jsNull()); - object->putDirect(exec->vm(), Identifier(exec, "beta"), rotationRate->canProvideBeta() ? jsNumber(rotationRate->beta()) : jsNull()); - object->putDirect(exec->vm(), Identifier(exec, "gamma"), rotationRate->canProvideGamma() ? jsNumber(rotationRate->gamma()) : jsNull()); - return object; -} - -JSValue JSDeviceMotionEvent::acceleration(ExecState* exec) const -{ - DeviceMotionEvent& imp = impl(); - if (!imp.deviceMotionData()->acceleration()) - return jsNull(); - return createAccelerationObject(imp.deviceMotionData()->acceleration(), exec); -} - -JSValue JSDeviceMotionEvent::accelerationIncludingGravity(ExecState* exec) const -{ - DeviceMotionEvent& imp = impl(); - if (!imp.deviceMotionData()->accelerationIncludingGravity()) - return jsNull(); - return createAccelerationObject(imp.deviceMotionData()->accelerationIncludingGravity(), exec); -} - -JSValue JSDeviceMotionEvent::rotationRate(ExecState* exec) const -{ - DeviceMotionEvent& imp = impl(); - if (!imp.deviceMotionData()->rotationRate()) - return jsNull(); - return createRotationRateObject(imp.deviceMotionData()->rotationRate(), exec); -} - -JSValue JSDeviceMotionEvent::interval(ExecState*) const -{ - DeviceMotionEvent& imp = impl(); - if (!imp.deviceMotionData()->canProvideInterval()) - return jsNull(); - return jsNumber(imp.deviceMotionData()->interval()); -} - -JSValue JSDeviceMotionEvent::initDeviceMotionEvent(ExecState* exec) -{ - const String type = exec->argument(0).toString(exec)->value(exec); - bool bubbles = exec->argument(1).toBoolean(exec); - bool cancelable = exec->argument(2).toBoolean(exec); - - // If any of the parameters are null or undefined, mark them as not provided. - // Otherwise, use the standard JavaScript conversion. - RefPtr<DeviceMotionData::Acceleration> acceleration = readAccelerationArgument(exec->argument(3), exec); - if (exec->hadException()) - return jsUndefined(); - - RefPtr<DeviceMotionData::Acceleration> accelerationIncludingGravity = readAccelerationArgument(exec->argument(4), exec); - if (exec->hadException()) - return jsUndefined(); - - RefPtr<DeviceMotionData::RotationRate> rotationRate = readRotationRateArgument(exec->argument(5), exec); - if (exec->hadException()) - return jsUndefined(); - - bool intervalProvided = !exec->argument(6).isUndefinedOrNull(); - double interval = exec->argument(6).toNumber(exec); - RefPtr<DeviceMotionData> deviceMotionData = DeviceMotionData::create(acceleration, accelerationIncludingGravity, rotationRate, intervalProvided, interval); - impl().initDeviceMotionEvent(type, bubbles, cancelable, deviceMotionData.get()); - return jsUndefined(); -} - -} // namespace WebCore - -#endif // ENABLE(DEVICE_ORIENTATION) diff --git a/Source/WebCore/bindings/js/JSDeviceOrientationEventCustom.cpp b/Source/WebCore/bindings/js/JSDeviceOrientationEventCustom.cpp deleted file mode 100644 index 86ddc96aa..000000000 --- a/Source/WebCore/bindings/js/JSDeviceOrientationEventCustom.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#if ENABLE(DEVICE_ORIENTATION) - -#include "JSDeviceOrientationEvent.h" - -#include "DeviceOrientationData.h" -#include "DeviceOrientationEvent.h" - -using namespace JSC; - -namespace WebCore { - -JSValue JSDeviceOrientationEvent::alpha(ExecState*) const -{ - DeviceOrientationEvent& imp = impl(); - if (!imp.orientation()->canProvideAlpha()) - return jsNull(); - return jsNumber(imp.orientation()->alpha()); -} - -JSValue JSDeviceOrientationEvent::beta(ExecState*) const -{ - DeviceOrientationEvent& imp = impl(); - if (!imp.orientation()->canProvideBeta()) - return jsNull(); - return jsNumber(imp.orientation()->beta()); -} - -JSValue JSDeviceOrientationEvent::gamma(ExecState*) const -{ - DeviceOrientationEvent& imp = impl(); - if (!imp.orientation()->canProvideGamma()) - return jsNull(); - return jsNumber(imp.orientation()->gamma()); -} - -#if PLATFORM(IOS) -JSValue JSDeviceOrientationEvent::webkitCompassHeading(ExecState*) const -{ - DeviceOrientationEvent& imp = impl(); - if (!imp.orientation()->canProvideCompassHeading()) - return jsNull(); - return jsNumber(imp.orientation()->compassHeading()); -} - -JSValue JSDeviceOrientationEvent::webkitCompassAccuracy(ExecState*) const -{ - DeviceOrientationEvent& imp = impl(); - if (!imp.orientation()->canProvideCompassAccuracy()) - return jsNull(); - return jsNumber(imp.orientation()->compassAccuracy()); -} -#endif - -#if !PLATFORM(IOS) -JSValue JSDeviceOrientationEvent::absolute(ExecState*) const -{ - DeviceOrientationEvent& imp = impl(); - if (!imp.orientation()->canProvideAbsolute()) - return jsNull(); - return jsBoolean(imp.orientation()->absolute()); -} -#endif - -JSValue JSDeviceOrientationEvent::initDeviceOrientationEvent(ExecState* exec) -{ - const String type = exec->argument(0).toString(exec)->value(exec); - bool bubbles = exec->argument(1).toBoolean(exec); - bool cancelable = exec->argument(2).toBoolean(exec); - // If alpha, beta or gamma are null or undefined, mark them as not provided. - // Otherwise, use the standard JavaScript conversion. - bool alphaProvided = !exec->argument(3).isUndefinedOrNull(); - double alpha = exec->argument(3).toNumber(exec); - bool betaProvided = !exec->argument(4).isUndefinedOrNull(); - double beta = exec->argument(4).toNumber(exec); - bool gammaProvided = !exec->argument(5).isUndefinedOrNull(); - double gamma = exec->argument(5).toNumber(exec); -#if PLATFORM(IOS) - bool compassHeadingProvided = !exec->argument(6).isUndefinedOrNull(); - double compassHeading = exec->argument(6).toNumber(exec); - bool compassAccuracyProvided = !exec->argument(7).isUndefinedOrNull(); - double compassAccuracy = exec->argument(7).toNumber(exec); - RefPtr<DeviceOrientationData> orientation = DeviceOrientationData::create(alphaProvided, alpha, betaProvided, beta, gammaProvided, gamma, compassHeadingProvided, compassHeading, compassAccuracyProvided, compassAccuracy); -#else - bool absoluteProvided = !exec->argument(6).isUndefinedOrNull(); - bool absolute = exec->argument(6).toBoolean(exec); - RefPtr<DeviceOrientationData> orientation = DeviceOrientationData::create(alphaProvided, alpha, betaProvided, beta, gammaProvided, gamma, absoluteProvided, absolute); -#endif - impl().initDeviceOrientationEvent(type, bubbles, cancelable, orientation.get()); - return jsUndefined(); -} - -} // namespace WebCore - -#endif // ENABLE(DEVICE_ORIENTATION) diff --git a/Source/WebCore/bindings/js/JSDictionary.cpp b/Source/WebCore/bindings/js/JSDictionary.cpp deleted file mode 100644 index 4c2882611..000000000 --- a/Source/WebCore/bindings/js/JSDictionary.cpp +++ /dev/null @@ -1,279 +0,0 @@ -/* - * 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 "JSDictionary.h" - -#include "ArrayValue.h" -#include "Dictionary.h" -#include "JSCSSFontFaceRule.h" -#include "JSDOMError.h" -#include "JSDOMWindow.h" -#include "JSEventTarget.h" -#include "JSMessagePortCustom.h" -#include "JSNode.h" -#include "JSStorage.h" -#include "JSTrackCustom.h" -#include "JSVoidCallback.h" -#include "SerializedScriptValue.h" -#include <runtime/JSTypedArrays.h> -#include <wtf/HashMap.h> -#include <wtf/MathExtras.h> -#include <wtf/text/AtomicString.h> - -#if ENABLE(ENCRYPTED_MEDIA) -#include "JSMediaKeyError.h" -#endif - -#if ENABLE(MEDIA_STREAM) -#include "JSMediaStream.h" -#include "JSMediaStreamTrack.h" -#endif - -#if ENABLE(SCRIPTED_SPEECH) -#include "JSSpeechRecognitionResultList.h" -#endif - -using namespace JSC; - -namespace WebCore { - -JSDictionary::GetPropertyResult JSDictionary::tryGetProperty(const char* propertyName, JSValue& finalResult) const -{ - ASSERT(isValid()); - Identifier identifier(m_exec, propertyName); - PropertySlot slot(m_initializerObject.get()); - - if (!m_initializerObject.get()->getPropertySlot(m_exec, identifier, slot)) - return NoPropertyFound; - - if (m_exec->hadException()) - return ExceptionThrown; - - finalResult = slot.getValue(m_exec, identifier); - if (m_exec->hadException()) - return ExceptionThrown; - - return PropertyFound; -} - -void JSDictionary::convertValue(ExecState* exec, JSValue value, bool& result) -{ - result = value.toBoolean(exec); -} - -void JSDictionary::convertValue(ExecState* exec, JSValue value, int& result) -{ - result = value.toInt32(exec); -} - -void JSDictionary::convertValue(ExecState* exec, JSValue value, unsigned& result) -{ - result = value.toUInt32(exec); -} - -void JSDictionary::convertValue(ExecState* exec, JSValue value, unsigned short& result) -{ - result = static_cast<unsigned short>(value.toUInt32(exec)); -} - -void JSDictionary::convertValue(ExecState* exec, JSValue value, unsigned long& result) -{ - result = static_cast<unsigned long>(value.toUInt32(exec)); -} - -void JSDictionary::convertValue(ExecState* exec, JSValue value, unsigned long long& result) -{ - double d = value.toNumber(exec); - doubleToInteger(d, result); -} - -void JSDictionary::convertValue(ExecState* exec, JSValue value, double& result) -{ - result = value.toNumber(exec); -} - -void JSDictionary::convertValue(JSC::ExecState* exec, JSC::JSValue value, Dictionary& result) -{ - result = Dictionary(exec, value); -} - -void JSDictionary::convertValue(ExecState* exec, JSValue value, String& result) -{ - result = value.toString(exec)->value(exec); -} - -void JSDictionary::convertValue(ExecState* exec, JSValue value, Vector<String>& result) -{ - if (value.isUndefinedOrNull()) - return; - - unsigned length = 0; - JSObject* object = toJSSequence(exec, value, length); - if (exec->hadException()) - return; - - for (unsigned i = 0 ; i < length; ++i) { - JSValue itemValue = object->get(exec, i); - if (exec->hadException()) - return; - result.append(itemValue.toString(exec)->value(exec)); - } -} - -void JSDictionary::convertValue(ExecState* exec, JSValue value, Deprecated::ScriptValue& result) -{ - result = Deprecated::ScriptValue(exec->vm(), value); -} - -void JSDictionary::convertValue(ExecState* exec, JSValue value, RefPtr<SerializedScriptValue>& result) -{ - result = SerializedScriptValue::create(exec, value, 0, 0); -} - -void JSDictionary::convertValue(ExecState*, JSValue value, RefPtr<DOMWindow>& result) -{ - result = toDOMWindow(value); -} - -void JSDictionary::convertValue(ExecState*, JSValue value, RefPtr<EventTarget>& result) -{ - result = toEventTarget(value); -} - -void JSDictionary::convertValue(ExecState*, JSValue value, RefPtr<Node>& result) -{ - result = toNode(value); -} - -void JSDictionary::convertValue(ExecState*, JSValue value, RefPtr<Storage>& result) -{ - result = toStorage(value); -} - -void JSDictionary::convertValue(ExecState* exec, JSValue value, MessagePortArray& result) -{ - ArrayBufferArray arrayBuffers; - fillMessagePortArray(exec, value, result, arrayBuffers); -} - -#if ENABLE(VIDEO_TRACK) -void JSDictionary::convertValue(ExecState*, JSValue value, RefPtr<TrackBase>& result) -{ - result = toTrack(value); -} -#endif - -void JSDictionary::convertValue(ExecState* exec, JSValue value, HashSet<AtomicString>& result) -{ - result.clear(); - - if (value.isUndefinedOrNull()) - return; - - unsigned length = 0; - JSObject* object = toJSSequence(exec, value, length); - if (exec->hadException()) - return; - - for (unsigned i = 0 ; i < length; ++i) { - JSValue itemValue = object->get(exec, i); - if (exec->hadException()) - return; - result.add(itemValue.toString(exec)->value(exec)); - } -} - -void JSDictionary::convertValue(ExecState* exec, JSValue value, ArrayValue& result) -{ - if (value.isUndefinedOrNull()) - return; - - result = ArrayValue(exec, value); -} - -void JSDictionary::convertValue(JSC::ExecState*, JSC::JSValue value, RefPtr<Uint8Array>& result) -{ - result = toUint8Array(value); -} - -#if ENABLE(ENCRYPTED_MEDIA) -void JSDictionary::convertValue(JSC::ExecState*, JSC::JSValue value, RefPtr<MediaKeyError>& result) -{ - result = toMediaKeyError(value); -} -#endif - -#if ENABLE(MEDIA_STREAM) -void JSDictionary::convertValue(JSC::ExecState*, JSC::JSValue value, RefPtr<MediaStream>& result) -{ - result = toMediaStream(value); -} - -void JSDictionary::convertValue(JSC::ExecState*, JSC::JSValue value, RefPtr<MediaStreamTrack>& result) -{ - result = toMediaStreamTrack(value); -} -#endif - -#if ENABLE(FONT_LOAD_EVENTS) -void JSDictionary::convertValue(JSC::ExecState*, JSC::JSValue value, RefPtr<CSSFontFaceRule>& result) -{ - result = toCSSFontFaceRule(value); -} - -void JSDictionary::convertValue(JSC::ExecState*, JSC::JSValue value, RefPtr<DOMError>& result) -{ - result = toDOMError(value); -} - -void JSDictionary::convertValue(JSC::ExecState* exec, JSC::JSValue value, RefPtr<VoidCallback>& result) -{ - if (!value.isFunction()) - return; - - result = JSVoidCallback::create(asObject(value), jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())); -} -#endif - -#if ENABLE(SCRIPTED_SPEECH) -void JSDictionary::convertValue(JSC::ExecState*, JSC::JSValue value, RefPtr<SpeechRecognitionResultList>& result) -{ - result = toSpeechRecognitionResultList(value); -} -#endif - -bool JSDictionary::getWithUndefinedOrNullCheck(const String& propertyName, String& result) const -{ - ASSERT(isValid()); - JSValue value; - if (tryGetProperty(propertyName.utf8().data(), value) != PropertyFound || value.isUndefinedOrNull()) - return false; - - result = value.toWTFString(m_exec); - return true; -} - -} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDictionary.h b/Source/WebCore/bindings/js/JSDictionary.h deleted file mode 100644 index 3a8e2cc6f..000000000 --- a/Source/WebCore/bindings/js/JSDictionary.h +++ /dev/null @@ -1,193 +0,0 @@ -/* - * 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 JSDictionary_h -#define JSDictionary_h - -#include "MessagePort.h" -#include <heap/Strong.h> -#include <heap/StrongInlines.h> -#include <interpreter/CallFrame.h> -#include <runtime/Operations.h> -#include <runtime/Uint8Array.h> -#include <wtf/Forward.h> - -namespace Deprecated { -class ScriptValue; -} - -namespace WebCore { - -class ArrayValue; -class CSSFontFaceRule; -class Dictionary; -class DOMError; -class DOMWindow; -class EventTarget; -class MediaKeyError; -class MediaStream; -class MediaStreamTrack; -class Node; -class SerializedScriptValue; -class Storage; -class TrackBase; -class VoidCallback; - -#if ENABLE(SCRIPTED_SPEECH) -class SpeechRecognitionResultList; -#endif - -class JSDictionary { -public: - JSDictionary(JSC::ExecState* exec, JSC::JSObject* initializerObject) - : m_exec(exec) - { - if (exec && initializerObject) - m_initializerObject = JSC::Strong<JSC::JSObject>(exec->vm(), initializerObject); - } - - // Returns false if any exceptions were thrown, regardless of whether the property was found. - template <typename Result> - bool tryGetProperty(const char* propertyName, Result&) const; - template <typename T, typename Result> - bool tryGetProperty(const char* propertyName, T* context, void (*setter)(T* context, const Result&)) const; - - // Returns true if the property was found in the dictionary, and the value could be converted to the desired type. - template <typename Result> - bool get(const char* propertyName, Result&) const; - bool getWithUndefinedOrNullCheck(const String& propertyName, String& value) const; - - JSC::ExecState* execState() const { return m_exec; } - JSC::JSObject* initializerObject() const { return m_initializerObject.get(); } - bool isValid() const { return m_exec && m_initializerObject; } - -private: - template <typename Result> - struct IdentitySetter { - static void identitySetter(Result* context, const Result& result) - { - *context = result; - } - }; - - enum GetPropertyResult { - ExceptionThrown, - NoPropertyFound, - PropertyFound - }; - - template <typename T, typename Result> - GetPropertyResult tryGetPropertyAndResult(const char* propertyName, T* context, void (*setter)(T* context, const Result&)) const; - GetPropertyResult tryGetProperty(const char* propertyName, JSC::JSValue&) const; - - static void convertValue(JSC::ExecState*, JSC::JSValue, bool& result); - static void convertValue(JSC::ExecState*, JSC::JSValue, int& result); - static void convertValue(JSC::ExecState*, JSC::JSValue, unsigned& result); - static void convertValue(JSC::ExecState*, JSC::JSValue, unsigned short& result); - static void convertValue(JSC::ExecState*, JSC::JSValue, unsigned long& result); - static void convertValue(JSC::ExecState*, JSC::JSValue, unsigned long long& result); - static void convertValue(JSC::ExecState*, JSC::JSValue, double& result); - static void convertValue(JSC::ExecState*, JSC::JSValue, Dictionary& result); - static void convertValue(JSC::ExecState*, JSC::JSValue, String& result); - static void convertValue(JSC::ExecState*, JSC::JSValue, Deprecated::ScriptValue& result); - static void convertValue(JSC::ExecState*, JSC::JSValue, Vector<String>& result); - static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<SerializedScriptValue>& result); - static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<DOMWindow>& result); - static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<EventTarget>& result); - static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<Node>& result); - static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<Storage>& result); - static void convertValue(JSC::ExecState*, JSC::JSValue, MessagePortArray& result); -#if ENABLE(VIDEO_TRACK) - static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<TrackBase>& result); -#endif - static void convertValue(JSC::ExecState*, JSC::JSValue, HashSet<AtomicString>& result); - static void convertValue(JSC::ExecState*, JSC::JSValue, ArrayValue& result); - static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<JSC::Uint8Array>& result); -#if ENABLE(ENCRYPTED_MEDIA) - static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<MediaKeyError>& result); -#endif -#if ENABLE(MEDIA_STREAM) - static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<MediaStream>& result); - static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<MediaStreamTrack>& result); -#endif -#if ENABLE(FONT_LOAD_EVENTS) - static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<CSSFontFaceRule>& result); - static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<DOMError>& result); - static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<VoidCallback>& result); -#endif -#if ENABLE(SCRIPTED_SPEECH) - static void convertValue(JSC::ExecState*, JSC::JSValue, RefPtr<SpeechRecognitionResultList>&); -#endif - - JSC::ExecState* m_exec; - JSC::Strong<JSC::JSObject> m_initializerObject; -}; - -template <typename T, typename Result> -bool JSDictionary::tryGetProperty(const char* propertyName, T* context, void (*setter)(T* context, const Result&)) const -{ - return tryGetPropertyAndResult(propertyName, context, setter) != ExceptionThrown; -} - -template <typename Result> -bool JSDictionary::tryGetProperty(const char* propertyName, Result& finalResult) const -{ - return tryGetPropertyAndResult(propertyName, &finalResult, IdentitySetter<Result>::identitySetter) != ExceptionThrown; -} - -template <typename Result> -bool JSDictionary::get(const char* propertyName, Result& finalResult) const -{ - return tryGetPropertyAndResult(propertyName, &finalResult, IdentitySetter<Result>::identitySetter) == PropertyFound; -} - -template <typename T, typename Result> -JSDictionary::GetPropertyResult JSDictionary::tryGetPropertyAndResult(const char* propertyName, T* context, void (*setter)(T* context, const Result&)) const -{ - JSC::JSValue value; - GetPropertyResult getPropertyResult = tryGetProperty(propertyName, value); - switch (getPropertyResult) { - case ExceptionThrown: - return getPropertyResult; - case PropertyFound: { - Result result; - convertValue(m_exec, value, result); - - if (m_exec->hadException()) - return ExceptionThrown; - - setter(context, result); - break; - } - case NoPropertyFound: - break; - } - - return getPropertyResult; -} - -} // namespace WebCore - -#endif // JSDictionary_h diff --git a/Source/WebCore/bindings/js/JSDocumentCustom.cpp b/Source/WebCore/bindings/js/JSDocumentCustom.cpp index 34088ca48..a78b01844 100644 --- a/Source/WebCore/bindings/js/JSDocumentCustom.cpp +++ b/Source/WebCore/bindings/js/JSDocumentCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2009, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2007-2009, 2011, 2016 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -25,108 +25,138 @@ #include "FrameLoader.h" #include "HTMLDocument.h" #include "JSCanvasRenderingContext2D.h" -#if ENABLE(WEBGL) -#include "JSWebGLRenderingContext.h" -#endif +#include "JSDOMConvert.h" #include "JSDOMWindowCustom.h" #include "JSHTMLDocument.h" #include "JSLocation.h" -#include "JSTouch.h" -#include "JSTouchList.h" +#include "JSXMLDocument.h" #include "Location.h" #include "NodeTraversal.h" +#include "SVGDocument.h" #include "ScriptController.h" #include "TouchList.h" +#include "XMLDocument.h" +#include <wtf/GetPtr.h> -#if ENABLE(SVG) -#include "JSSVGDocument.h" -#include "SVGDocument.h" +#if ENABLE(WEBGL) +#include "JSWebGLRenderingContextBase.h" #endif -#include <wtf/GetPtr.h> +#if ENABLE(TOUCH_EVENTS) +#include "JSTouch.h" +#include "JSTouchList.h" +#endif using namespace JSC; namespace WebCore { -JSValue JSDocument::location(ExecState* exec) const +static inline JSValue createNewDocumentWrapper(ExecState& state, JSDOMGlobalObject& globalObject, Ref<Document>&& passedDocument) { - RefPtr<Frame> frame = impl().frame(); - if (!frame) - return jsNull(); + auto& document = passedDocument.get(); + JSObject* wrapper; + if (document.isHTMLDocument()) + wrapper = createWrapper<HTMLDocument>(&globalObject, WTFMove(passedDocument)); + else if (document.isXMLDocument()) + wrapper = createWrapper<XMLDocument>(&globalObject, WTFMove(passedDocument)); + else + wrapper = createWrapper<Document>(&globalObject, WTFMove(passedDocument)); + + reportMemoryForDocumentIfFrameless(state, document); - RefPtr<Location> location = frame->document()->domWindow()->location(); - if (JSObject* wrapper = getCachedWrapper(currentWorld(exec), location.get())) + return wrapper; +} + +JSObject* cachedDocumentWrapper(ExecState& state, JSDOMGlobalObject& globalObject, Document& document) +{ + if (auto* wrapper = getCachedWrapper(globalObject.world(), document)) return wrapper; - JSLocation* jsLocation = JSLocation::create(getDOMStructure<JSLocation>(exec->vm(), globalObject()), globalObject(), location.get()); - cacheWrapper(currentWorld(exec), location.get(), jsLocation); - return jsLocation; + auto* window = document.domWindow(); + if (!window) + return nullptr; + + // Creating a wrapper for domWindow might have created a wrapper for document as well. + return getCachedWrapper(toJSDOMWindow(state.vm(), toJS(&state, *window))->world(), document); } -void JSDocument::setLocation(ExecState* exec, JSValue value) +void reportMemoryForDocumentIfFrameless(ExecState& state, Document& document) { - String locationString = value.toString(exec)->value(exec); - if (exec->hadException()) + // Make sure the document is kept around by the window object, and works right with the back/forward cache. + if (document.frame()) return; - RefPtr<Frame> frame = impl().frame(); - if (!frame) - return; + size_t memoryCost = 0; + for (Node* node = &document; node; node = NodeTraversal::next(*node)) + memoryCost += node->approximateMemoryCost(); - if (RefPtr<Location> location = frame->document()->domWindow()->location()) - location->setHref(locationString, activeDOMWindow(exec), firstDOMWindow(exec)); + // FIXME: Adopt reportExtraMemoryVisited, and switch to reportExtraMemoryAllocated. + // https://bugs.webkit.org/show_bug.cgi?id=142595 + state.heap()->deprecatedReportExtraMemory(memoryCost); } -JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, Document* document) +JSValue toJSNewlyCreated(ExecState* state, JSDOMGlobalObject* globalObject, Ref<Document>&& document) { - if (!document) - return jsNull(); + return createNewDocumentWrapper(*state, *globalObject, WTFMove(document)); +} - JSObject* wrapper = getCachedWrapper(currentWorld(exec), document); - if (wrapper) +JSValue toJS(ExecState* state, JSDOMGlobalObject* globalObject, Document& document) +{ + if (auto* wrapper = cachedDocumentWrapper(*state, *globalObject, document)) return wrapper; + return toJSNewlyCreated(state, globalObject, Ref<Document>(document)); +} - if (DOMWindow* domWindow = document->domWindow()) { - globalObject = toJSDOMWindow(toJS(exec, domWindow)); - // Creating a wrapper for domWindow might have created a wrapper for document as well. - wrapper = getCachedWrapper(currentWorld(exec), document); - if (wrapper) - return wrapper; - } +#if ENABLE(TOUCH_EVENTS) +JSValue JSDocument::createTouchList(ExecState& state) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); - if (document->isHTMLDocument()) - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, HTMLDocument, document); -#if ENABLE(SVG) - else if (document->isSVGDocument()) - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, SVGDocument, document); -#endif - else - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, Document, document); - - // Make sure the document is kept around by the window object, and works right with the - // back/forward cache. - if (!document->frame()) { - size_t nodeCount = 0; - for (Node* n = document; n; n = NodeTraversal::next(n)) - nodeCount++; - - exec->heap()->reportExtraMemoryCost(nodeCount * sizeof(Node)); - } + auto touchList = TouchList::create(); - return wrapper; + for (size_t i = 0; i < state.argumentCount(); ++i) { + auto* item = JSTouch::toWrapped(vm, state.uncheckedArgument(i)); + if (!item) + return JSValue::decode(throwArgumentTypeError(state, scope, i, "touches", "Document", "createTouchList", "Touch")); + + touchList->append(*item); + } + return toJSNewlyCreated(&state, globalObject(), WTFMove(touchList)); } +#endif -#if ENABLE(TOUCH_EVENTS) -JSValue JSDocument::createTouchList(ExecState* exec) +JSValue JSDocument::getCSSCanvasContext(JSC::ExecState& state) { - RefPtr<TouchList> touchList = TouchList::create(); + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(state.argumentCount() < 4)) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + auto contextId = state.uncheckedArgument(0).toWTFString(&state); + RETURN_IF_EXCEPTION(scope, JSValue()); + auto name = state.uncheckedArgument(1).toWTFString(&state); + RETURN_IF_EXCEPTION(scope, JSValue()); + auto width = convert<IDLLong>(state, state.uncheckedArgument(2), IntegerConversionConfiguration::Normal); + RETURN_IF_EXCEPTION(scope, JSValue()); + auto height = convert<IDLLong>(state, state.uncheckedArgument(3), IntegerConversionConfiguration::Normal); + RETURN_IF_EXCEPTION(scope, JSValue()); + + auto* context = wrapped().getCSSCanvasContext(WTFMove(contextId), WTFMove(name), WTFMove(width), WTFMove(height)); + if (!context) + return jsNull(); - for (size_t i = 0; i < exec->argumentCount(); i++) - touchList->append(toTouch(exec->argument(i))); +#if ENABLE(WEBGL) + if (is<WebGLRenderingContextBase>(*context)) + return toJS(&state, globalObject(), downcast<WebGLRenderingContextBase>(*context)); +#endif - return toJS(exec, globalObject(), touchList.release()); + return toJS(&state, globalObject(), downcast<CanvasRenderingContext2D>(*context)); +} + +void JSDocument::visitAdditionalChildren(SlotVisitor& visitor) +{ + visitor.addOpaqueRoot(static_cast<ScriptExecutionContext*>(&wrapped())); } -#endif } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSHTMLMediaElementCustom.cpp b/Source/WebCore/bindings/js/JSDocumentCustom.h index 1d40c60d8..5b60f5442 100644 --- a/Source/WebCore/bindings/js/JSHTMLMediaElementCustom.cpp +++ b/Source/WebCore/bindings/js/JSDocumentCustom.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Apple Inc. All Rights Reserved. + * Copyright (C) 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,25 +23,20 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "config.h" -#if ENABLE(VIDEO) +#pragma once -#include "JSHTMLMediaElement.h" - -#include "JSMediaController.h" +#include "JSDOMBinding.h" +#include "JSDocument.h" namespace WebCore { -using namespace JSC; - -void JSHTMLMediaElement::setController(ExecState*, JSValue value) +template<typename From> +ALWAYS_INLINE JSDynamicCastResult<JSDocument, From> jsDocumentCast(From* value) { - // 4.8.10.11.2 Media controllers: controller attribute. - // On setting, it must first remove the element's mediagroup attribute, if any, - impl().setMediaGroup(String()); - // and then set the current media controller to the given value. - impl().setController(toMediaController(value)); + return value->type() == JSDocumentWrapperType ? JSC::jsCast<JSDynamicCastResult<JSDocument, From>>(value) : nullptr; } -} -#endif +JSC::JSObject* cachedDocumentWrapper(JSC::ExecState&, JSDOMGlobalObject&, Document&); +void reportMemoryForDocumentIfFrameless(JSC::ExecState&, Document&); + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDocumentFragmentCustom.cpp b/Source/WebCore/bindings/js/JSDocumentFragmentCustom.cpp new file mode 100644 index 000000000..11557165e --- /dev/null +++ b/Source/WebCore/bindings/js/JSDocumentFragmentCustom.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2015 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 "JSDocumentFragment.h" + +#include "ExceptionCode.h" +#include "JSShadowRoot.h" + +using namespace JSC; + +namespace WebCore { + +JSValue toJSNewlyCreated(ExecState*, JSDOMGlobalObject* globalObject, Ref<DocumentFragment>&& impl) +{ + if (impl->isShadowRoot()) + return createWrapper<ShadowRoot>(globalObject, WTFMove(impl)); + return createWrapper<DocumentFragment>(globalObject, WTFMove(impl)); +} + +JSValue toJS(ExecState* state, JSDOMGlobalObject* globalObject, DocumentFragment& impl) +{ + return wrap(state, globalObject, impl); +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSDynamicDowncast.h b/Source/WebCore/bindings/js/JSDynamicDowncast.h new file mode 100644 index 000000000..0160126e1 --- /dev/null +++ b/Source/WebCore/bindings/js/JSDynamicDowncast.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2016 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 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 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. + */ + +#pragma once + +#include <runtime/JSCJSValueInlines.h> +#include <runtime/JSCellInlines.h> +#include <type_traits> + +namespace WebCore { + +template<typename To, typename From> +using JSDynamicCastResult = typename std::conditional<std::is_const<From>::value, const To, To>::type*; + +class JSNode; +template<typename From> +JSDynamicCastResult<JSNode, From> jsNodeCast(From* value); +class JSElement; +template<typename From> +JSDynamicCastResult<JSElement, From> jsElementCast(From* value); +class JSDocument; +template<typename From> +JSDynamicCastResult<JSDocument, From> jsDocumentCast(From* value); +class JSEvent; +template<typename From> +JSDynamicCastResult<JSEvent, From> jsEventCast(From* value); + +template<typename Select> +struct JSDynamicCastTrait { + template<typename To, typename From> + ALWAYS_INLINE static To cast(JSC::VM& vm, From* from) + { + return JSC::jsDynamicCast<To>(vm, from); + } +}; + +template<> +struct JSDynamicCastTrait<JSNode> { + template<typename To, typename From> + ALWAYS_INLINE static To cast(JSC::VM&, From* from) + { + return jsNodeCast(from); + } +}; + +template<> +struct JSDynamicCastTrait<JSElement> { + template<typename To, typename From> + ALWAYS_INLINE static To cast(JSC::VM&, From* from) + { + return jsElementCast(from); + } +}; + +template<> +struct JSDynamicCastTrait<JSDocument> { + template<typename To, typename From> + ALWAYS_INLINE static To cast(JSC::VM&, From* from) + { + return jsDocumentCast(from); + } +}; + +template<> +struct JSDynamicCastTrait<JSEvent> { + template<typename To, typename From> + ALWAYS_INLINE static To cast(JSC::VM&, From* from) + { + return jsEventCast(from); + } +}; + +template<typename To, typename From> +ALWAYS_INLINE To jsDynamicDowncast(JSC::VM& vm, From* from) +{ + typedef JSDynamicCastTrait<typename std::remove_cv<typename std::remove_pointer<To>::type>::type> Dispatcher; + return Dispatcher::template cast<To>(vm, from); +} + +template<typename To> +ALWAYS_INLINE To jsDynamicDowncast(JSC::VM& vm, JSC::JSValue from) +{ + if (UNLIKELY(!from.isCell())) + return nullptr; + return jsDynamicDowncast<To>(vm, from.asCell()); +} + +} diff --git a/Source/WebCore/bindings/js/JSElementCustom.cpp b/Source/WebCore/bindings/js/JSElementCustom.cpp index 021f0a683..91bb3e0d9 100644 --- a/Source/WebCore/bindings/js/JSElementCustom.cpp +++ b/Source/WebCore/bindings/js/JSElementCustom.cpp @@ -10,7 +10,7 @@ * 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -38,12 +38,9 @@ #include "JSDOMBinding.h" #include "JSHTMLElementWrapperFactory.h" #include "JSNodeList.h" -#include "NodeList.h" - -#if ENABLE(SVG) #include "JSSVGElementWrapperFactory.h" +#include "NodeList.h" #include "SVGElement.h" -#endif using namespace JSC; @@ -51,24 +48,28 @@ namespace WebCore { using namespace HTMLNames; -JSValue toJSNewlyCreated(ExecState* exec, JSDOMGlobalObject* globalObject, Element* element) +static JSValue createNewElementWrapper(JSDOMGlobalObject* globalObject, Ref<Element>&& element) { - if (!element) - return jsNull(); - - ASSERT(!getCachedWrapper(currentWorld(exec), element)); + if (is<HTMLElement>(element.get())) + return createJSHTMLWrapper(globalObject, static_reference_cast<HTMLElement>(WTFMove(element))); + if (is<SVGElement>(element.get())) + return createJSSVGWrapper(globalObject, static_reference_cast<SVGElement>(WTFMove(element))); + return createWrapper<Element>(globalObject, WTFMove(element)); +} - JSDOMWrapper* wrapper; - if (element->isHTMLElement()) - wrapper = createJSHTMLWrapper(exec, globalObject, toHTMLElement(element)); -#if ENABLE(SVG) - else if (element->isSVGElement()) - wrapper = createJSSVGWrapper(exec, globalObject, toSVGElement(element)); -#endif - else - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, Element, element); +JSValue toJS(ExecState*, JSDOMGlobalObject* globalObject, Element& element) +{ + if (auto* wrapper = getCachedWrapper(globalObject->world(), element)) + return wrapper; + return createNewElementWrapper(globalObject, element); +} - return wrapper; +JSValue toJSNewlyCreated(ExecState*, JSDOMGlobalObject* globalObject, Ref<Element>&& element) +{ + if (element->isDefinedCustomElement()) + return getCachedWrapper(globalObject->world(), element); + ASSERT(!getCachedWrapper(globalObject->world(), element)); + return createNewElementWrapper(globalObject, WTFMove(element)); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSElementCustom.h b/Source/WebCore/bindings/js/JSElementCustom.h new file mode 100644 index 000000000..b2b65f53a --- /dev/null +++ b/Source/WebCore/bindings/js/JSElementCustom.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2014 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. ``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 + * 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. + */ + +#pragma once + +#include "JSDOMBinding.h" +#include "JSElement.h" + +namespace WebCore { + +template<typename From> +ALWAYS_INLINE JSDynamicCastResult<JSElement, From> jsElementCast(From* value) +{ + return value->type() >= JSElementType ? JSC::jsCast<JSDynamicCastResult<JSElement, From>>(value) : nullptr; +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSErrorHandler.cpp b/Source/WebCore/bindings/js/JSErrorHandler.cpp index f72c334bd..a99c808fa 100644 --- a/Source/WebCore/bindings/js/JSErrorHandler.cpp +++ b/Source/WebCore/bindings/js/JSErrorHandler.cpp @@ -30,15 +30,15 @@ */ #include "config.h" - #include "JSErrorHandler.h" #include "Document.h" #include "ErrorEvent.h" #include "Event.h" -#include "EventNames.h" +#include "JSDOMConvert.h" #include "JSEvent.h" #include "JSMainThreadExecState.h" +#include "JSMainThreadExecStateInstrumentation.h" #include <runtime/JSLock.h> #include <runtime/VMEntryScope.h> #include <wtf/Ref.h> @@ -58,15 +58,14 @@ JSErrorHandler::~JSErrorHandler() void JSErrorHandler::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event) { - - if (event->eventInterface() != ErrorEventInterfaceType) + if (!is<ErrorEvent>(*event)) return JSEventListener::handleEvent(scriptExecutionContext, event); ASSERT(scriptExecutionContext); if (!scriptExecutionContext) return; - ErrorEvent* errorEvent = static_cast<ErrorEvent*>(event); + ErrorEvent& errorEvent = downcast<ErrorEvent>(*event); JSLockHolder lock(scriptExecutionContext->vm()); @@ -83,29 +82,35 @@ void JSErrorHandler::handleEvent(ScriptExecutionContext* scriptExecutionContext, CallData callData; CallType callType = jsFunction->methodTable()->getCallData(jsFunction, callData); - if (callType != CallTypeNone) { - Ref<JSErrorHandler> protectedctor(*this); + if (callType != CallType::None) { + Ref<JSErrorHandler> protectedThis(*this); Event* savedEvent = globalObject->currentEvent(); globalObject->setCurrentEvent(event); MarkedArgumentBuffer args; - args.append(jsStringWithCache(exec, errorEvent->message())); - args.append(jsStringWithCache(exec, errorEvent->filename())); - args.append(jsNumber(errorEvent->lineno())); - args.append(jsNumber(errorEvent->colno())); + args.append(toJS<IDLDOMString>(*exec, errorEvent.message())); + args.append(toJS<IDLUSVString>(*exec, errorEvent.filename())); + args.append(toJS<IDLUnsignedLong>(errorEvent.lineno())); + args.append(toJS<IDLUnsignedLong>(errorEvent.colno())); + args.append(errorEvent.error(*exec, *globalObject)); VM& vm = globalObject->vm(); VMEntryScope entryScope(vm, vm.entryScope ? vm.entryScope->globalObject() : globalObject); + InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(scriptExecutionContext, callType, callData); + + NakedPtr<JSC::Exception> exception; JSValue returnValue = scriptExecutionContext->isDocument() - ? JSMainThreadExecState::call(exec, jsFunction, callType, callData, globalObject, args) - : JSC::call(exec, jsFunction, callType, callData, globalObject, args); + ? JSMainThreadExecState::profiledCall(exec, JSC::ProfilingReason::Other, jsFunction, callType, callData, globalObject, args, exception) + : JSC::profiledCall(exec, JSC::ProfilingReason::Other, jsFunction, callType, callData, globalObject, args, exception); + + InspectorInstrumentation::didCallFunction(cookie, scriptExecutionContext); globalObject->setCurrentEvent(savedEvent); - if (exec->hadException()) - reportCurrentException(exec); + if (exception) + reportException(exec, exception); else { if (returnValue.isTrue()) event->preventDefault(); diff --git a/Source/WebCore/bindings/js/JSErrorHandler.h b/Source/WebCore/bindings/js/JSErrorHandler.h index 55d2d53e0..ba01c0e0b 100644 --- a/Source/WebCore/bindings/js/JSErrorHandler.h +++ b/Source/WebCore/bindings/js/JSErrorHandler.h @@ -28,37 +28,34 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSErrorHandler_h -#define JSErrorHandler_h +#pragma once #include "JSEventListener.h" namespace WebCore { -class JSErrorHandler : public JSEventListener { +class JSErrorHandler final : public JSEventListener { public: - static PassRefPtr<JSErrorHandler> create(JSC::JSObject* listener, JSC::JSObject* wrapper, bool isAttribute, DOMWrapperWorld& world) + static Ref<JSErrorHandler> create(JSC::JSObject* listener, JSC::JSObject* wrapper, bool isAttribute, DOMWrapperWorld& world) { - return adoptRef(new JSErrorHandler(listener, wrapper, isAttribute, world)); + return adoptRef(*new JSErrorHandler(listener, wrapper, isAttribute, world)); } virtual ~JSErrorHandler(); private: JSErrorHandler(JSC::JSObject* function, JSC::JSObject* wrapper, bool isAttribute, DOMWrapperWorld&); - virtual void handleEvent(ScriptExecutionContext*, Event*); + void handleEvent(ScriptExecutionContext*, Event*) final; }; // Creates a JS EventListener for "onerror" event handler in worker context. It has custom implementation because // unlike other event listeners it accepts three parameters. -inline PassRefPtr<JSErrorHandler> createJSErrorHandler(JSC::ExecState* exec, JSC::JSValue listener, JSC::JSObject* wrapper) +inline RefPtr<JSErrorHandler> createJSErrorHandler(JSC::ExecState* exec, JSC::JSValue listener, JSC::JSObject* wrapper) { if (!listener.isObject()) - return 0; + return nullptr; return JSErrorHandler::create(asObject(listener), wrapper, true, currentWorld(exec)); } } // namespace WebCore - -#endif // JSErrorHandler_h diff --git a/Source/WebCore/bindings/js/JSEventCustom.cpp b/Source/WebCore/bindings/js/JSEventCustom.cpp index e1698db17..72917973f 100644 --- a/Source/WebCore/bindings/js/JSEventCustom.cpp +++ b/Source/WebCore/bindings/js/JSEventCustom.cpp @@ -10,7 +10,7 @@ * 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -29,45 +29,35 @@ #include "config.h" #include "JSEvent.h" -#include "Clipboard.h" +#include "DataTransfer.h" #include "Event.h" #include "EventHeaders.h" #include "EventInterfaces.h" -#include "EventNames.h" -#include "JSClipboard.h" +#include "JSDOMBinding.h" +#include "JSDataTransfer.h" #include <runtime/JSLock.h> -#include <wtf/HashMap.h> #include <wtf/text/AtomicString.h> using namespace JSC; namespace WebCore { -JSValue JSEvent::clipboardData(ExecState* exec) const -{ - return impl().isClipboardEvent() ? toJS(exec, globalObject(), impl().clipboardData()) : jsUndefined(); -} - #define TRY_TO_WRAP_WITH_INTERFACE(interfaceName) \ case interfaceName##InterfaceType: \ - return CREATE_DOM_WRAPPER(exec, globalObject, interfaceName, event); + return createWrapper<interfaceName>(globalObject, WTFMove(event)); -JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, Event* event) +JSValue toJSNewlyCreated(ExecState*, JSDOMGlobalObject* globalObject, Ref<Event>&& event) { - JSLockHolder lock(exec); - - if (!event) - return jsNull(); - - JSObject* wrapper = getCachedWrapper(currentWorld(exec), event); - if (wrapper) - return wrapper; - switch (event->eventInterface()) { DOM_EVENT_INTERFACES_FOR_EACH(TRY_TO_WRAP_WITH_INTERFACE) } - return CREATE_DOM_WRAPPER(exec, globalObject, Event, event); + return createWrapper<Event>(globalObject, WTFMove(event)); +} + +JSValue toJS(ExecState* state, JSDOMGlobalObject* globalObject, Event& event) +{ + return wrap(state, globalObject, event); } #undef TRY_TO_WRAP_WITH_INTERFACE diff --git a/Source/WebCore/bindings/js/ScriptProfileNode.h b/Source/WebCore/bindings/js/JSEventCustom.h index 2b9ec5beb..2b85293c4 100644 --- a/Source/WebCore/bindings/js/ScriptProfileNode.h +++ b/Source/WebCore/bindings/js/JSEventCustom.h @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 Apple Inc. All rights reserved. - * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -11,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -24,15 +23,16 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ScriptProfileNode_h -#define ScriptProfileNode_h +#pragma once -#include <profiler/ProfileNode.h> +#include "JSDOMBinding.h" namespace WebCore { -typedef JSC::ProfileNode ScriptProfileNode; +template<typename From> +ALWAYS_INLINE JSDynamicCastResult<JSEvent, From> jsEventCast(From* value) +{ + return value->type() == JSEventType ? JSC::jsCast<JSDynamicCastResult<JSEvent, From>>(value) : nullptr; +} } // namespace WebCore - -#endif // ScriptProfileNode_h diff --git a/Source/WebCore/bindings/js/JSEventListener.cpp b/Source/WebCore/bindings/js/JSEventListener.cpp index 00d16c849..621a210bb 100644 --- a/Source/WebCore/bindings/js/JSEventListener.cpp +++ b/Source/WebCore/bindings/js/JSEventListener.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2013 Apple Inc. All Rights Reserved. + * Copyright (C) 2003-2017 Apple Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,9 +21,12 @@ #include "JSEventListener.h" #include "BeforeUnloadEvent.h" +#include "ContentSecurityPolicy.h" #include "Event.h" #include "Frame.h" -#include "InspectorCounters.h" +#include "HTMLElement.h" +#include "JSDOMConvert.h" +#include "JSDocument.h" #include "JSEvent.h" #include "JSEventTarget.h" #include "JSMainThreadExecState.h" @@ -33,8 +36,8 @@ #include <runtime/ExceptionHelpers.h> #include <runtime/JSLock.h> #include <runtime/VMEntryScope.h> +#include <runtime/Watchdog.h> #include <wtf/Ref.h> -#include <wtf/RefCountedLeakCounter.h> using namespace JSC; @@ -44,28 +47,22 @@ JSEventListener::JSEventListener(JSObject* function, JSObject* wrapper, bool isA : EventListener(JSEventListenerType) , m_wrapper(wrapper) , m_isAttribute(isAttribute) - , m_isolatedWorld(&isolatedWorld) + , m_isolatedWorld(isolatedWorld) { if (wrapper) { - JSC::Heap::writeBarrier(wrapper, function); + JSC::Heap::heap(wrapper)->writeBarrier(wrapper, function); m_jsFunction = JSC::Weak<JSC::JSObject>(function); } else ASSERT(!function); -#if ENABLE(INSPECTOR) - ThreadLocalInspectorCounters::current().incrementCounter(ThreadLocalInspectorCounters::JSEventListenerCounter); -#endif } JSEventListener::~JSEventListener() { -#if ENABLE(INSPECTOR) - ThreadLocalInspectorCounters::current().decrementCounter(ThreadLocalInspectorCounters::JSEventListenerCounter); -#endif } JSObject* JSEventListener::initializeJSFunction(ScriptExecutionContext*) const { - return 0; + return nullptr; } void JSEventListener::visitJSFunction(SlotVisitor& visitor) @@ -74,7 +71,17 @@ void JSEventListener::visitJSFunction(SlotVisitor& visitor) if (!m_wrapper) return; - visitor.appendUnbarrieredWeak(&m_jsFunction); + visitor.append(m_jsFunction); +} + +static void handleBeforeUnloadEventReturnValue(BeforeUnloadEvent& event, const String& returnValue) +{ + if (returnValue.isNull()) + return; + + event.preventDefault(); + if (event.returnValue().isEmpty()) + event.setReturnValue(returnValue); } void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext, Event* event) @@ -83,22 +90,29 @@ void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext if (!scriptExecutionContext || scriptExecutionContext->isJSExecutionForbidden()) return; - JSLockHolder lock(scriptExecutionContext->vm()); + VM& vm = scriptExecutionContext->vm(); + JSLockHolder lock(vm); + auto scope = DECLARE_CATCH_SCOPE(vm); + // See https://dom.spec.whatwg.org/#dispatching-events spec on calling handleEvent. + // "If this throws an exception, report the exception." It should not propagate the + // exception. JSObject* jsFunction = this->jsFunction(scriptExecutionContext); if (!jsFunction) return; - JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, *m_isolatedWorld); + JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(scriptExecutionContext, m_isolatedWorld); if (!globalObject) return; if (scriptExecutionContext->isDocument()) { JSDOMWindow* window = jsCast<JSDOMWindow*>(globalObject); - if (!window->impl().isCurrentlyDisplayedInFrame()) + if (!window->wrapped().isCurrentlyDisplayedInFrame()) + return; + if (wasCreatedFromMarkup() && !scriptExecutionContext->contentSecurityPolicy()->allowInlineEventHandlers(sourceURL(), sourcePosition().m_line)) return; // FIXME: Is this check needed for other contexts? - ScriptController& script = window->impl().frame()->script(); + ScriptController& script = window->wrapped().frame()->script(); if (!script.canExecuteScripts(AboutToExecuteScript) || script.isPaused()) return; } @@ -109,13 +123,21 @@ void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext CallData callData; CallType callType = getCallData(handleEventFunction, callData); // If jsFunction is not actually a function, see if it implements the EventListener interface and use that - if (callType == CallTypeNone) { - handleEventFunction = jsFunction->get(exec, Identifier(exec, "handleEvent")); + if (callType == CallType::None) { + handleEventFunction = jsFunction->get(exec, Identifier::fromString(exec, "handleEvent")); + if (UNLIKELY(scope.exception())) { + auto* exception = scope.exception(); + scope.clearException(); + + event->target()->uncaughtExceptionInEventHandler(); + reportException(exec, exception); + return; + } callType = getCallData(handleEventFunction, callData); } - if (callType != CallTypeNone) { - Ref<JSEventListener> protect(*this); + if (callType != CallType::None) { + Ref<JSEventListener> protectedThis(*this); MarkedArgumentBuffer args; args.append(toJS(exec, globalObject, event)); @@ -123,32 +145,34 @@ void JSEventListener::handleEvent(ScriptExecutionContext* scriptExecutionContext Event* savedEvent = globalObject->currentEvent(); globalObject->setCurrentEvent(event); - VM& vm = globalObject->vm(); VMEntryScope entryScope(vm, vm.entryScope ? vm.entryScope->globalObject() : globalObject); InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(scriptExecutionContext, callType, callData); JSValue thisValue = handleEventFunction == jsFunction ? toJS(exec, globalObject, event->currentTarget()) : jsFunction; + NakedPtr<JSC::Exception> exception; JSValue retval = scriptExecutionContext->isDocument() - ? JSMainThreadExecState::call(exec, handleEventFunction, callType, callData, thisValue, args) - : JSC::call(exec, handleEventFunction, callType, callData, thisValue, args); + ? JSMainThreadExecState::profiledCall(exec, JSC::ProfilingReason::Other, handleEventFunction, callType, callData, thisValue, args, exception) + : JSC::profiledCall(exec, JSC::ProfilingReason::Other, handleEventFunction, callType, callData, thisValue, args, exception); - InspectorInstrumentation::didCallFunction(cookie); + InspectorInstrumentation::didCallFunction(cookie, scriptExecutionContext); globalObject->setCurrentEvent(savedEvent); - if (scriptExecutionContext->isWorkerGlobalScope()) { - bool terminatorCausedException = (exec->hadException() && isTerminatedExecutionException(exec->exception())); - if (terminatorCausedException || vm.watchdog.didFire()) - static_cast<WorkerGlobalScope*>(scriptExecutionContext)->script()->forbidExecution(); + if (is<WorkerGlobalScope>(*scriptExecutionContext)) { + auto scriptController = downcast<WorkerGlobalScope>(*scriptExecutionContext).script(); + bool terminatorCausedException = (scope.exception() && isTerminatedExecutionException(vm, scope.exception())); + if (terminatorCausedException || scriptController->isTerminatingExecution()) + scriptController->forbidExecution(); } - if (exec->hadException()) { + if (exception) { event->target()->uncaughtExceptionInEventHandler(); - reportCurrentException(exec); + reportException(exec, exception); } else { - if (!retval.isUndefinedOrNull() && event->isBeforeUnloadEvent()) - toBeforeUnloadEvent(event)->setReturnValue(retval.toString(exec)->value(exec)); + if (is<BeforeUnloadEvent>(*event)) + handleBeforeUnloadEventReturnValue(downcast<BeforeUnloadEvent>(*event), convert<IDLNullable<IDLDOMString>>(*exec, retval, StringConversionConfiguration::Normal)); + if (m_isAttribute) { if (retval.isFalse()) event->preventDefault(); @@ -162,11 +186,91 @@ bool JSEventListener::virtualisAttribute() const return m_isAttribute; } -bool JSEventListener::operator==(const EventListener& listener) +bool JSEventListener::operator==(const EventListener& listener) const { if (const JSEventListener* jsEventListener = JSEventListener::cast(&listener)) return m_jsFunction == jsEventListener->m_jsFunction && m_isAttribute == jsEventListener->m_isAttribute; return false; } +static inline JSC::JSValue eventHandlerAttribute(EventListener* abstractListener, ScriptExecutionContext& context) +{ + if (!abstractListener) + return jsNull(); + + auto* listener = JSEventListener::cast(abstractListener); + if (!listener) + return jsNull(); + + auto* function = listener->jsFunction(&context); + if (!function) + return jsNull(); + + return function; +} + +static inline RefPtr<JSEventListener> createEventListenerForEventHandlerAttribute(JSC::ExecState& state, JSC::JSValue listener, JSC::JSObject& wrapper) +{ + if (!listener.isObject()) + return nullptr; + return JSEventListener::create(asObject(listener), &wrapper, true, currentWorld(&state)); +} + +JSC::JSValue eventHandlerAttribute(EventTarget& target, const AtomicString& eventType, DOMWrapperWorld& isolatedWorld) +{ + return eventHandlerAttribute(target.attributeEventListener(eventType, isolatedWorld), *target.scriptExecutionContext()); +} + +void setEventHandlerAttribute(JSC::ExecState& state, JSC::JSObject& wrapper, EventTarget& target, const AtomicString& eventType, JSC::JSValue value) +{ + target.setAttributeEventListener(eventType, createEventListenerForEventHandlerAttribute(state, value, wrapper), currentWorld(&state)); +} + +JSC::JSValue windowEventHandlerAttribute(HTMLElement& element, const AtomicString& eventType, DOMWrapperWorld& isolatedWorld) +{ + auto& document = element.document(); + return eventHandlerAttribute(document.getWindowAttributeEventListener(eventType, isolatedWorld), document); +} + +void setWindowEventHandlerAttribute(JSC::ExecState& state, JSC::JSObject& wrapper, HTMLElement& element, const AtomicString& eventType, JSC::JSValue value) +{ + ASSERT(wrapper.globalObject()); + element.document().setWindowAttributeEventListener(eventType, createEventListenerForEventHandlerAttribute(state, value, *wrapper.globalObject()), currentWorld(&state)); +} + +JSC::JSValue windowEventHandlerAttribute(DOMWindow& window, const AtomicString& eventType, DOMWrapperWorld& isolatedWorld) +{ + return eventHandlerAttribute(window, eventType, isolatedWorld); +} + +void setWindowEventHandlerAttribute(JSC::ExecState& state, JSC::JSObject& wrapper, DOMWindow& window, const AtomicString& eventType, JSC::JSValue value) +{ + setEventHandlerAttribute(state, wrapper, window, eventType, value); +} + +JSC::JSValue documentEventHandlerAttribute(HTMLElement& element, const AtomicString& eventType, DOMWrapperWorld& isolatedWorld) +{ + auto& document = element.document(); + return eventHandlerAttribute(document.attributeEventListener(eventType, isolatedWorld), document); +} + +void setDocumentEventHandlerAttribute(JSC::ExecState& state, JSC::JSObject& wrapper, HTMLElement& element, const AtomicString& eventType, JSC::JSValue value) +{ + ASSERT(wrapper.globalObject()); + auto& document = element.document(); + auto* documentWrapper = JSC::jsCast<JSDocument*>(toJS(&state, JSC::jsCast<JSDOMGlobalObject*>(wrapper.globalObject()), document)); + ASSERT(documentWrapper); + document.setAttributeEventListener(eventType, createEventListenerForEventHandlerAttribute(state, value, *documentWrapper), currentWorld(&state)); +} + +JSC::JSValue documentEventHandlerAttribute(Document& document, const AtomicString& eventType, DOMWrapperWorld& isolatedWorld) +{ + return eventHandlerAttribute(document, eventType, isolatedWorld); +} + +void setDocumentEventHandlerAttribute(JSC::ExecState& state, JSC::JSObject& wrapper, Document& document, const AtomicString& eventType, JSC::JSValue value) +{ + setEventHandlerAttribute(state, wrapper, document, eventType, value); +} + } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSEventListener.h b/Source/WebCore/bindings/js/JSEventListener.h index 303ff691c..693853adb 100644 --- a/Source/WebCore/bindings/js/JSEventListener.h +++ b/Source/WebCore/bindings/js/JSEventListener.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2003-2017 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,103 +17,129 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef JSEventListener_h -#define JSEventListener_h +#pragma once +#include "DOMWrapperWorld.h" #include "EventListener.h" -#include "JSDOMWindow.h" #include <heap/StrongInlines.h> #include <heap/Weak.h> #include <heap/WeakInlines.h> #include <wtf/Ref.h> +#include <wtf/TypeCasts.h> +#include <wtf/text/TextPosition.h> +#include <wtf/text/WTFString.h> namespace WebCore { - class JSDOMGlobalObject; +class DOMWindow; +class EventTarget; +class HTMLElement; +class JSDOMGlobalObject; - class JSEventListener : public EventListener { - public: - static PassRefPtr<JSEventListener> create(JSC::JSObject* listener, JSC::JSObject* wrapper, bool isAttribute, DOMWrapperWorld& world) - { - return adoptRef(new JSEventListener(listener, wrapper, isAttribute, world)); - } +class JSEventListener : public EventListener { +public: + static Ref<JSEventListener> create(JSC::JSObject* listener, JSC::JSObject* wrapper, bool isAttribute, DOMWrapperWorld& world) + { + return adoptRef(*new JSEventListener(listener, wrapper, isAttribute, world)); + } - static const JSEventListener* cast(const EventListener* listener) - { - return listener->type() == JSEventListenerType - ? static_cast<const JSEventListener*>(listener) - : 0; - } + static RefPtr<JSEventListener> create(JSC::JSValue listener, JSC::JSObject& wrapper, bool isAttribute, DOMWrapperWorld& world) + { + if (UNLIKELY(!listener.isObject())) + return nullptr; - virtual ~JSEventListener(); + return adoptRef(new JSEventListener(JSC::asObject(listener), &wrapper, isAttribute, world)); + } - virtual bool operator==(const EventListener& other) override; + static const JSEventListener* cast(const EventListener* listener) + { + return listener->type() == JSEventListenerType + ? static_cast<const JSEventListener*>(listener) + : nullptr; + } - // Returns true if this event listener was created for an event handler attribute, like "onload" or "onclick". - bool isAttribute() const { return m_isAttribute; } + virtual ~JSEventListener(); - JSC::JSObject* jsFunction(ScriptExecutionContext*) const; - DOMWrapperWorld& isolatedWorld() const { return *m_isolatedWorld; } + bool operator==(const EventListener& other) const override; - JSC::JSObject* wrapper() const { return m_wrapper.get(); } - void setWrapper(JSC::VM&, JSC::JSObject* wrapper) const { m_wrapper = JSC::Weak<JSC::JSObject>(wrapper); } + // Returns true if this event listener was created for an event handler attribute, like "onload" or "onclick". + bool isAttribute() const { return m_isAttribute; } - private: - virtual JSC::JSObject* initializeJSFunction(ScriptExecutionContext*) const; - virtual void visitJSFunction(JSC::SlotVisitor&) override; - virtual bool virtualisAttribute() const override; + JSC::JSObject* jsFunction(ScriptExecutionContext*) const; + DOMWrapperWorld& isolatedWorld() const { return m_isolatedWorld; } - protected: - JSEventListener(JSC::JSObject* function, JSC::JSObject* wrapper, bool isAttribute, DOMWrapperWorld&); - virtual void handleEvent(ScriptExecutionContext*, Event*) override; + JSC::JSObject* wrapper() const { return m_wrapper.get(); } + void setWrapper(JSC::VM&, JSC::JSObject* wrapper) const { m_wrapper = JSC::Weak<JSC::JSObject>(wrapper); } - private: - mutable JSC::Weak<JSC::JSObject> m_jsFunction; - mutable JSC::Weak<JSC::JSObject> m_wrapper; + virtual String sourceURL() const { return String(); } + virtual TextPosition sourcePosition() const { return TextPosition(); } - bool m_isAttribute; - RefPtr<DOMWrapperWorld> m_isolatedWorld; - }; +private: + virtual JSC::JSObject* initializeJSFunction(ScriptExecutionContext*) const; + void visitJSFunction(JSC::SlotVisitor&) override; + bool virtualisAttribute() const override; - inline JSC::JSObject* JSEventListener::jsFunction(ScriptExecutionContext* scriptExecutionContext) const - { - // initializeJSFunction can trigger code that deletes this event listener - // before we're done. It should always return 0 in this case. - Ref<JSEventListener> protect(const_cast<JSEventListener&>(*this)); - JSC::Strong<JSC::JSObject> wrapper(*m_isolatedWorld->vm(), m_wrapper.get()); - - if (!m_jsFunction) { - JSC::JSObject* function = initializeJSFunction(scriptExecutionContext); - JSC::Heap::writeBarrier(m_wrapper.get(), function); - m_jsFunction = JSC::Weak<JSC::JSObject>(function); - } - - // Verify that we have a valid wrapper protecting our function from - // garbage collection. That is except for when we're not in the normal - // world and can have zombie m_jsFunctions. - ASSERT(!m_isolatedWorld->isNormal() || m_wrapper || !m_jsFunction); - - // If m_wrapper is 0, then m_jsFunction is zombied, and should never be accessed. - if (!m_wrapper) - return 0; - - // Try to verify that m_jsFunction wasn't recycled. (Not exact, since an - // event listener can be almost anything, but this makes test-writing easier). - ASSERT(!m_jsFunction || static_cast<JSC::JSCell*>(m_jsFunction.get())->isObject()); - - return m_jsFunction.get(); - } +protected: + JSEventListener(JSC::JSObject* function, JSC::JSObject* wrapper, bool isAttribute, DOMWrapperWorld&); + void handleEvent(ScriptExecutionContext*, Event*) override; - // Creates a JS EventListener for an "onXXX" event attribute. - inline PassRefPtr<JSEventListener> createJSAttributeEventListener(JSC::ExecState* exec, JSC::JSValue listener, JSC::JSObject* wrapper) - { - if (!listener.isObject()) - return 0; +private: + mutable JSC::Weak<JSC::JSObject> m_jsFunction; + mutable JSC::Weak<JSC::JSObject> m_wrapper; - return JSEventListener::create(asObject(listener), wrapper, true, currentWorld(exec)); + bool m_isAttribute; + Ref<DOMWrapperWorld> m_isolatedWorld; +}; + +// For "onxxx" attributes that automatically set up JavaScript event listeners. +JSC::JSValue eventHandlerAttribute(EventTarget&, const AtomicString& eventType, DOMWrapperWorld&); +void setEventHandlerAttribute(JSC::ExecState&, JSC::JSObject&, EventTarget&, const AtomicString& eventType, JSC::JSValue); + +// Like the functions above, but for attributes that forward event handlers to the window object rather than setting them on the target. +JSC::JSValue windowEventHandlerAttribute(HTMLElement&, const AtomicString& eventType, DOMWrapperWorld&); +void setWindowEventHandlerAttribute(JSC::ExecState&, JSC::JSObject&, HTMLElement&, const AtomicString& eventType, JSC::JSValue); +JSC::JSValue windowEventHandlerAttribute(DOMWindow&, const AtomicString& eventType, DOMWrapperWorld&); +void setWindowEventHandlerAttribute(JSC::ExecState&, JSC::JSObject&, DOMWindow&, const AtomicString& eventType, JSC::JSValue); + +// Like the functions above, but for attributes that forward event handlers to the document rather than setting them on the target. +JSC::JSValue documentEventHandlerAttribute(HTMLElement&, const AtomicString& eventType, DOMWrapperWorld&); +void setDocumentEventHandlerAttribute(JSC::ExecState&, JSC::JSObject&, HTMLElement&, const AtomicString& eventType, JSC::JSValue); +JSC::JSValue documentEventHandlerAttribute(Document&, const AtomicString& eventType, DOMWrapperWorld&); +void setDocumentEventHandlerAttribute(JSC::ExecState&, JSC::JSObject&, Document&, const AtomicString& eventType, JSC::JSValue); + +inline JSC::JSObject* JSEventListener::jsFunction(ScriptExecutionContext* scriptExecutionContext) const +{ + // initializeJSFunction can trigger code that deletes this event listener + // before we're done. It should always return 0 in this case. + auto protect = makeRef(const_cast<JSEventListener&>(*this)); + JSC::Strong<JSC::JSObject> wrapper(m_isolatedWorld->vm(), m_wrapper.get()); + + if (!m_jsFunction) { + JSC::JSObject* function = initializeJSFunction(scriptExecutionContext); + JSC::JSObject* wrapper = m_wrapper.get(); + if (wrapper) + JSC::Heap::heap(wrapper)->writeBarrier(wrapper, function); + m_jsFunction = JSC::Weak<JSC::JSObject>(function); } + // Verify that we have a valid wrapper protecting our function from + // garbage collection. That is except for when we're not in the normal + // world and can have zombie m_jsFunctions. + ASSERT(!m_isolatedWorld->isNormal() || m_wrapper || !m_jsFunction); + + // If m_wrapper is 0, then m_jsFunction is zombied, and should never be accessed. + if (!m_wrapper) + return nullptr; + + // Try to verify that m_jsFunction wasn't recycled. (Not exact, since an + // event listener can be almost anything, but this makes test-writing easier). + ASSERT(!m_jsFunction || static_cast<JSC::JSCell*>(m_jsFunction.get())->isObject()); + + return m_jsFunction.get(); +} } // namespace WebCore -#endif // JSEventListener_h +SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::JSEventListener) +static bool isType(const WebCore::EventListener& input) { return input.type() == WebCore::JSEventListener::JSEventListenerType; } +SPECIALIZE_TYPE_TRAITS_END() diff --git a/Source/WebCore/bindings/js/JSEventTargetCustom.cpp b/Source/WebCore/bindings/js/JSEventTargetCustom.cpp index 5210f12bb..07b46899e 100644 --- a/Source/WebCore/bindings/js/JSEventTargetCustom.cpp +++ b/Source/WebCore/bindings/js/JSEventTargetCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008-2017 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,10 +26,15 @@ #include "config.h" #include "JSEventTarget.h" +#include "DOMWindow.h" +#include "EventTarget.h" #include "EventTargetHeaders.h" #include "EventTargetInterfaces.h" +#include "JSDOMWindow.h" #include "JSDOMWindowShell.h" #include "JSEventListener.h" +#include "JSWorkerGlobalScope.h" +#include "WorkerGlobalScope.h" using namespace JSC; @@ -37,14 +42,11 @@ namespace WebCore { #define TRY_TO_WRAP_WITH_INTERFACE(interfaceName) \ case interfaceName##EventTargetInterfaceType: \ - return toJS(exec, globalObject, static_cast<interfaceName*>(target)); + return toJS(exec, globalObject, static_cast<interfaceName&>(target)); -JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, EventTarget* target) +JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, EventTarget& target) { - if (!target) - return jsNull(); - - switch (target->eventTargetInterface()) { + switch (target.eventTargetInterface()) { DOM_EVENT_TARGET_INTERFACES_FOR_EACH(TRY_TO_WRAP_WITH_INTERFACE) } @@ -55,18 +57,34 @@ JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, EventTarget* targ #undef TRY_TO_WRAP_WITH_INTERFACE #define TRY_TO_UNWRAP_WITH_INTERFACE(interfaceName) \ - if (value.inherits(JS##interfaceName::info())) \ - return &jsCast<JS##interfaceName*>(asObject(value))->impl(); + if (value.inherits(vm, JS##interfaceName::info())) \ + return &jsCast<JS##interfaceName*>(asObject(value))->wrapped(); -EventTarget* toEventTarget(JSC::JSValue value) +EventTarget* JSEventTarget::toWrapped(VM& vm, JSValue value) { TRY_TO_UNWRAP_WITH_INTERFACE(DOMWindowShell) + TRY_TO_UNWRAP_WITH_INTERFACE(DOMWindow) + TRY_TO_UNWRAP_WITH_INTERFACE(WorkerGlobalScope) TRY_TO_UNWRAP_WITH_INTERFACE(EventTarget) - // FIXME: Remove this once all event targets extend EventTarget - DOM_EVENT_TARGET_INTERFACES_FOR_EACH(TRY_TO_UNWRAP_WITH_INTERFACE) - return 0; + return nullptr; } #undef TRY_TO_UNWRAP_WITH_INTERFACE +std::unique_ptr<JSEventTargetWrapper> jsEventTargetCast(VM& vm, JSValue thisValue) +{ + if (auto* target = jsDynamicDowncast<JSEventTarget*>(vm, thisValue)) + return std::make_unique<JSEventTargetWrapper>(target->wrapped(), *target); + if (auto* window = toJSDOMWindow(vm, thisValue)) + return std::make_unique<JSEventTargetWrapper>(window->wrapped(), *window); + if (auto* scope = toJSWorkerGlobalScope(vm, thisValue)) + return std::make_unique<JSEventTargetWrapper>(scope->wrapped(), *scope); + return nullptr; +} + +void JSEventTarget::visitAdditionalChildren(SlotVisitor& visitor) +{ + wrapped().visitJSEventListeners(visitor); +} + } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSEventTargetCustom.h b/Source/WebCore/bindings/js/JSEventTargetCustom.h new file mode 100644 index 000000000..7f55358d5 --- /dev/null +++ b/Source/WebCore/bindings/js/JSEventTargetCustom.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2016 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. + */ + +#pragma once + +#include "DOMWindow.h" +#include "JSDOMBinding.h" +#include "JSDOMBindingCaller.h" +#include "JSDOMBindingSecurity.h" + +namespace WebCore { + +// Wrapper type for JSEventTarget's castedThis because JSDOMWindow and JSWorkerGlobalScope do not inherit JSEventTarget. +class JSEventTargetWrapper { + WTF_MAKE_FAST_ALLOCATED; +public: + JSEventTargetWrapper(EventTarget& wrapped, JSC::JSObject& wrapper) + : m_wrapped(wrapped) + , m_wrapper(wrapper) + { } + + EventTarget& wrapped() { return m_wrapped; } + + operator JSC::JSObject&() { return m_wrapper; } + +private: + EventTarget& m_wrapped; + JSC::JSObject& m_wrapper; +}; + +std::unique_ptr<JSEventTargetWrapper> jsEventTargetCast(JSC::VM&, JSC::JSValue thisValue); + +template<> struct BindingCaller<JSEventTarget> { + using OperationCallerFunction = JSC::EncodedJSValue(JSC::ExecState*, JSEventTargetWrapper*, JSC::ThrowScope&); + + template<OperationCallerFunction operationCaller> + static JSC::EncodedJSValue callOperation(JSC::ExecState* state, const char* operationName) + { + ASSERT(state); + JSC::VM& vm = state->vm(); + auto throwScope = DECLARE_THROW_SCOPE(vm); + + auto thisObject = jsEventTargetCast(vm, state->thisValue().toThis(state, JSC::NotStrictMode)); + if (UNLIKELY(!thisObject)) + return throwThisTypeError(*state, throwScope, "EventTarget", operationName); + + if (auto* window = thisObject->wrapped().toDOMWindow()) { + if (!window->frame() || !BindingSecurity::shouldAllowAccessToDOMWindow(state, *window, ThrowSecurityError)) + return JSC::JSValue::encode(JSC::jsUndefined()); + } + + return operationCaller(state, thisObject.get(), throwScope); + } +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSExceptionBase.cpp b/Source/WebCore/bindings/js/JSExceptionBase.cpp index 8a51e0c97..f9238f333 100644 --- a/Source/WebCore/bindings/js/JSExceptionBase.cpp +++ b/Source/WebCore/bindings/js/JSExceptionBase.cpp @@ -27,40 +27,23 @@ #include "JSExceptionBase.h" #include "JSDOMCoreException.h" -#include "JSEventException.h" -#include "JSRangeException.h" -#include "JSXMLHttpRequestException.h" -#if ENABLE(SQL_DATABASE) -#include "SQLException.h" #include "JSSQLException.h" -#endif -#if ENABLE(SVG) #include "JSSVGException.h" -#endif #include "JSXPathException.h" +#include "SQLException.h" namespace WebCore { -ExceptionBase* toExceptionBase(JSC::JSValue value) +ExceptionBase* toExceptionBase(JSC::VM& vm, JSC::JSValue value) { - if (DOMCoreException* domException = toDOMCoreException(value)) + if (DOMCoreException* domException = JSDOMCoreException::toWrapped(vm, value)) return reinterpret_cast<ExceptionBase*>(domException); - if (RangeException* rangeException = toRangeException(value)) - return reinterpret_cast<ExceptionBase*>(rangeException); - if (EventException* eventException = toEventException(value)) - return reinterpret_cast<ExceptionBase*>(eventException); - if (XMLHttpRequestException* xmlHttpException = toXMLHttpRequestException(value)) - return reinterpret_cast<ExceptionBase*>(xmlHttpException); -#if ENABLE(SVG) - if (SVGException* svgException = toSVGException(value)) + if (SVGException* svgException = JSSVGException::toWrapped(vm, value)) return reinterpret_cast<ExceptionBase*>(svgException); -#endif - if (XPathException* pathException = toXPathException(value)) + if (XPathException* pathException = JSXPathException::toWrapped(vm, value)) return reinterpret_cast<ExceptionBase*>(pathException); -#if ENABLE(SQL_DATABASE) - if (SQLException* pathException = toSQLException(value)) + if (SQLException* pathException = JSSQLException::toWrapped(vm, value)) return reinterpret_cast<ExceptionBase*>(pathException); -#endif return 0; } diff --git a/Source/WebCore/bindings/js/JSExceptionBase.h b/Source/WebCore/bindings/js/JSExceptionBase.h index 771300293..d88141e02 100644 --- a/Source/WebCore/bindings/js/JSExceptionBase.h +++ b/Source/WebCore/bindings/js/JSExceptionBase.h @@ -23,21 +23,17 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSExceptionBase_h -#define JSExceptionBase_h +#pragma once namespace JSC { - class JSValue; - -} // namespace JSC +class VM; +} namespace WebCore { class ExceptionBase; -ExceptionBase* toExceptionBase(JSC::JSValue); +ExceptionBase* toExceptionBase(JSC::VM&, JSC::JSValue); } // namespace WebCore - -#endif // JSExceptionBase_h diff --git a/Source/WebCore/bindings/js/JSFileReaderCustom.cpp b/Source/WebCore/bindings/js/JSFileReaderCustom.cpp deleted file mode 100644 index f2970b27b..000000000 --- a/Source/WebCore/bindings/js/JSFileReaderCustom.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#if ENABLE(BLOB) - -#include "JSFileReader.h" - -#include "FileReader.h" -#include <runtime/ArrayBuffer.h> -#include <runtime/JSArrayBuffer.h> - -using namespace JSC; - -namespace WebCore { - -JSValue JSFileReader::result(ExecState* exec) const -{ - FileReader& imp = impl(); - if (imp.readType() == FileReaderLoader::ReadAsArrayBuffer) - return toJS(exec, globalObject(), WTF::getPtr(imp.arrayBufferResult())); - return jsOwnedStringOrNull(exec, imp.stringResult()); -} - -} // namespace WebCore - -#endif // ENABLE(BLOB) diff --git a/Source/WebCore/bindings/js/JSFontFaceCustom.cpp b/Source/WebCore/bindings/js/JSFontFaceCustom.cpp new file mode 100644 index 000000000..af460e4ec --- /dev/null +++ b/Source/WebCore/bindings/js/JSFontFaceCustom.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 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 "JSFontFace.h" + +#include "CSSFontSelector.h" +#include "CSSValue.h" +#include "CSSValueList.h" +#include "ExceptionCode.h" +#include "JSDOMConstructor.h" + +namespace WebCore { + +JSC::JSValue JSFontFace::loaded(JSC::ExecState& state) const +{ + if (!m_loaded) { + if (!wrapped().promise()) { + auto promise = createDeferredPromise(state, domWindow()); + m_loaded.set(state.vm(), this, promise->promise()); + wrapped().registerLoaded(WTFMove(promise)); + } else + m_loaded.set(state.vm(), this, wrapped().promise().value().promise()); + } + return m_loaded.get(); +} + +JSC::JSValue JSFontFace::load(JSC::ExecState& state) +{ + wrapped().load(); + return loaded(state); +} + +} diff --git a/Source/WebCore/bindings/js/JSFontFaceSetCustom.cpp b/Source/WebCore/bindings/js/JSFontFaceSetCustom.cpp new file mode 100644 index 000000000..22560d44f --- /dev/null +++ b/Source/WebCore/bindings/js/JSFontFaceSetCustom.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2016 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 "JSFontFaceSet.h" + +#include "FontFace.h" +#include "JSFontFace.h" + +namespace WebCore { + +JSC::JSValue JSFontFaceSet::ready(JSC::ExecState& state) const +{ + if (!m_ready) { + auto promise = createDeferredPromise(state, domWindow()); + m_ready.set(state.vm(), this, promise->promise()); + wrapped().registerReady(WTFMove(promise)); + } + return m_ready.get(); +} + +} diff --git a/Source/WebCore/bindings/js/JSGeolocationCustom.cpp b/Source/WebCore/bindings/js/JSGeolocationCustom.cpp deleted file mode 100644 index d1a2daa1a..000000000 --- a/Source/WebCore/bindings/js/JSGeolocationCustom.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2008 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. ``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 - * 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 "JSGeolocation.h" - -#if ENABLE(GEOLOCATION) - -#include "CallbackFunction.h" -#include "DOMWindow.h" -#include "Geolocation.h" -#include "JSDOMWindow.h" -#include "JSDictionary.h" -#include "JSPositionCallback.h" -#include "JSPositionErrorCallback.h" -#include "PositionOptions.h" - -using namespace JSC; - -namespace WebCore { - -// JSDictionary helper functions - -static void setEnableHighAccuracy(PositionOptions* options, const bool& enableHighAccuracy) -{ - options->setEnableHighAccuracy(enableHighAccuracy); -} - -static void setTimeout(PositionOptions* options, const double& timeout) -{ - // If the value is positive infinity, there's nothing to do. - if (!(std::isinf(timeout) && (timeout > 0))) { - // Wrap to int32 and force non-negative to match behavior of window.setTimeout. - options->setTimeout(std::max<int>(0, timeout)); - } -} - -static void setMaximumAge(PositionOptions* options, const double& maximumAge) -{ - if (std::isinf(maximumAge) && (maximumAge > 0)) { - // If the value is positive infinity, clear maximumAge. - options->clearMaximumAge(); - } else { - // Wrap to int32 and force non-negative to match behavior of window.setTimeout. - options->setMaximumAge(std::max<int>(0, maximumAge)); - } -} - - -static PassRefPtr<PositionOptions> createPositionOptions(ExecState* exec, JSValue value) -{ - // Create default options. - RefPtr<PositionOptions> options = PositionOptions::create(); - - // Argument is optional (hence undefined is allowed), and null is allowed. - if (value.isUndefinedOrNull()) { - // Use default options. - return options.release(); - } - - // Given the above test, this will always yield an object. - JSObject* object = value.toObject(exec); - - // Create the dictionary wrapper from the initializer object. - JSDictionary dictionary(exec, object); - - if (!dictionary.tryGetProperty("enableHighAccuracy", options.get(), setEnableHighAccuracy)) - return 0; - if (!dictionary.tryGetProperty("timeout", options.get(), setTimeout)) - return 0; - if (!dictionary.tryGetProperty("maximumAge", options.get(), setMaximumAge)) - return 0; - - return options.release(); -} - -JSValue JSGeolocation::getCurrentPosition(ExecState* exec) -{ - // Arguments: PositionCallback, (optional)PositionErrorCallback, (optional)PositionOptions - - RefPtr<PositionCallback> positionCallback = createFunctionOnlyCallback<JSPositionCallback>(exec, globalObject(), exec->argument(0)); - if (exec->hadException()) - return jsUndefined(); - ASSERT(positionCallback); - - RefPtr<PositionErrorCallback> positionErrorCallback = createFunctionOnlyCallback<JSPositionErrorCallback>(exec, globalObject(), exec->argument(1), CallbackAllowUndefined | CallbackAllowNull); - if (exec->hadException()) - return jsUndefined(); - - RefPtr<PositionOptions> positionOptions = createPositionOptions(exec, exec->argument(2)); - if (exec->hadException()) - return jsUndefined(); - ASSERT(positionOptions); - - m_impl->getCurrentPosition(positionCallback.release(), positionErrorCallback.release(), positionOptions.release()); - return jsUndefined(); -} - -JSValue JSGeolocation::watchPosition(ExecState* exec) -{ - // Arguments: PositionCallback, (optional)PositionErrorCallback, (optional)PositionOptions - - RefPtr<PositionCallback> positionCallback = createFunctionOnlyCallback<JSPositionCallback>(exec, globalObject(), exec->argument(0)); - if (exec->hadException()) - return jsUndefined(); - ASSERT(positionCallback); - - RefPtr<PositionErrorCallback> positionErrorCallback = createFunctionOnlyCallback<JSPositionErrorCallback>(exec, globalObject(), exec->argument(1), CallbackAllowUndefined | CallbackAllowNull); - if (exec->hadException()) - return jsUndefined(); - - RefPtr<PositionOptions> positionOptions = createPositionOptions(exec, exec->argument(2)); - if (exec->hadException()) - return jsUndefined(); - ASSERT(positionOptions); - - int watchID = m_impl->watchPosition(positionCallback.release(), positionErrorCallback.release(), positionOptions.release()); - return jsNumber(watchID); -} - -} // namespace WebCore - -#endif // ENABLE(GEOLOCATION) diff --git a/Source/WebCore/bindings/js/JSHTMLAllCollectionCustom.cpp b/Source/WebCore/bindings/js/JSHTMLAllCollectionCustom.cpp index 227c34dfb..d8286a52a 100644 --- a/Source/WebCore/bindings/js/JSHTMLAllCollectionCustom.cpp +++ b/Source/WebCore/bindings/js/JSHTMLAllCollectionCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,63 +27,61 @@ #include "JSHTMLAllCollection.h" #include "HTMLAllCollection.h" -#include "JSDOMBinding.h" #include "JSNode.h" #include "JSNodeList.h" -#include "Node.h" #include "StaticNodeList.h" -#include <runtime/JSCJSValue.h> -#include <wtf/Vector.h> -#include <wtf/text/AtomicString.h> +#include <runtime/IdentifierInlines.h> using namespace JSC; namespace WebCore { -static JSValue getNamedItems(ExecState* exec, JSHTMLAllCollection* collection, PropertyName propertyName) +static JSValue namedItems(ExecState& state, JSHTMLAllCollection* collection, PropertyName propertyName) { - Vector<Ref<Element>> namedItems; - collection->impl().namedItems(propertyNameToAtomicString(propertyName), namedItems); + Vector<Ref<Element>> namedItems = collection->wrapped().namedItems(propertyNameToAtomicString(propertyName)); if (namedItems.isEmpty()) return jsUndefined(); if (namedItems.size() == 1) - return toJS(exec, collection->globalObject(), &namedItems[0].get()); + return toJS(&state, collection->globalObject(), namedItems[0]); // FIXME: HTML5 specification says this should be a HTMLCollection. // http://www.whatwg.org/specs/web-apps/current-work/multipage/common-dom-interfaces.html#htmlallcollection - return toJS(exec, collection->globalObject(), StaticElementList::adopt(namedItems).get()); + return toJS(&state, collection->globalObject(), StaticElementList::create(WTFMove(namedItems))); } // HTMLAllCollections are strange objects, they support both get and call. static EncodedJSValue JSC_HOST_CALL callHTMLAllCollection(ExecState* exec) { + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + if (exec->argumentCount() < 1) return JSValue::encode(jsUndefined()); // Do not use thisObj here. It can be the JSHTMLDocument, in the document.forms(i) case. - JSHTMLAllCollection* jsCollection = jsCast<JSHTMLAllCollection*>(exec->callee()); - HTMLAllCollection& collection = jsCollection->impl(); + JSHTMLAllCollection* jsCollection = jsCast<JSHTMLAllCollection*>(exec->jsCallee()); + HTMLAllCollection& collection = jsCollection->wrapped(); // Also, do we need the TypeError test here ? if (exec->argumentCount() == 1) { // Support for document.all(<index>) etc. - String string = exec->argument(0).toString(exec)->value(exec); - unsigned index = toUInt32FromStringImpl(string.impl()); - if (index != PropertyName::NotAnIndex) - return JSValue::encode(toJS(exec, jsCollection->globalObject(), collection.item(index))); + String string = exec->argument(0).toWTFString(exec); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (std::optional<uint32_t> index = parseIndex(*string.impl())) + return JSValue::encode(toJS(exec, jsCollection->globalObject(), collection.item(index.value()))); // Support for document.images('<name>') etc. - return JSValue::encode(getNamedItems(exec, jsCollection, Identifier(exec, string))); + return JSValue::encode(namedItems(*exec, jsCollection, Identifier::fromString(exec, string))); } // The second arg, if set, is the index of the item we want - String string = exec->argument(0).toString(exec)->value(exec); - unsigned index = toUInt32FromStringImpl(exec->argument(1).toWTFString(exec).impl()); - if (index != PropertyName::NotAnIndex) { - if (Node* node = collection.namedItemWithIndex(string, index)) - return JSValue::encode(toJS(exec, jsCollection->globalObject(), node)); + String string = exec->argument(0).toWTFString(exec); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + if (std::optional<uint32_t> index = parseIndex(*exec->argument(1).toWTFString(exec).impl())) { + if (auto* item = collection.namedItemWithIndex(string, index.value())) + return JSValue::encode(toJS(exec, jsCollection->globalObject(), *item)); } return JSValue::encode(jsUndefined()); @@ -92,31 +90,36 @@ static EncodedJSValue JSC_HOST_CALL callHTMLAllCollection(ExecState* exec) CallType JSHTMLAllCollection::getCallData(JSCell*, CallData& callData) { callData.native.function = callHTMLAllCollection; - return CallTypeHost; + return CallType::Host; } -bool JSHTMLAllCollection::canGetItemsForName(ExecState*, HTMLAllCollection* collection, PropertyName propertyName) +bool JSHTMLAllCollection::nameGetter(ExecState* state, PropertyName propertyName, JSValue& value) { - return collection->hasNamedItem(propertyNameToAtomicString(propertyName)); -} + JSValue items = namedItems(*state, this, propertyName); + if (items.isUndefined()) + return false; -EncodedJSValue JSHTMLAllCollection::nameGetter(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName propertyName) -{ - JSHTMLAllCollection* thisObj = jsCast<JSHTMLAllCollection*>(JSValue::decode(slotBase)); - return JSValue::encode(getNamedItems(exec, thisObj, propertyName)); + value = items; + return true; } -JSValue JSHTMLAllCollection::item(ExecState* exec) +JSValue JSHTMLAllCollection::item(ExecState& state) { - uint32_t index = toUInt32FromStringImpl(exec->argument(0).toString(exec)->value(exec).impl()); - if (index != PropertyName::NotAnIndex) - return toJS(exec, globalObject(), impl().item(index)); - return getNamedItems(exec, this, Identifier(exec, exec->argument(0).toString(exec)->value(exec))); + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(state.argumentCount() < 1)) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + + String argument = state.uncheckedArgument(0).toWTFString(&state); + if (std::optional<uint32_t> index = parseIndex(*argument.impl())) + return toJS(&state, globalObject(), wrapped().item(index.value())); + return namedItems(state, this, Identifier::fromString(&state, argument)); } -JSValue JSHTMLAllCollection::namedItem(ExecState* exec) +JSValue JSHTMLAllCollection::namedItem(ExecState& state) { - JSValue value = getNamedItems(exec, this, Identifier(exec, exec->argument(0).toString(exec)->value(exec))); + JSValue value = namedItems(state, this, Identifier::fromString(&state, state.argument(0).toWTFString(&state))); return value.isUndefined() ? jsNull() : value; } diff --git a/Source/WebCore/bindings/js/JSHTMLAppletElementCustom.cpp b/Source/WebCore/bindings/js/JSHTMLAppletElementCustom.cpp index 9994d4205..229e68399 100644 --- a/Source/WebCore/bindings/js/JSHTMLAppletElementCustom.cpp +++ b/Source/WebCore/bindings/js/JSHTMLAppletElementCustom.cpp @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -38,9 +38,9 @@ bool JSHTMLAppletElement::getOwnPropertySlotDelegate(ExecState* exec, PropertyNa return pluginElementCustomGetOwnPropertySlot<JSHTMLAppletElement, Base>(exec, propertyName, slot, this); } -bool JSHTMLAppletElement::putDelegate(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) +bool JSHTMLAppletElement::putDelegate(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot, bool& putResult) { - return pluginElementCustomPut(exec, propertyName, value, this, slot); + return pluginElementCustomPut(exec, propertyName, value, this, slot, putResult); } CallType JSHTMLAppletElement::getCallData(JSCell* cell, CallData& callData) diff --git a/Source/WebCore/bindings/js/JSHTMLCanvasElementCustom.cpp b/Source/WebCore/bindings/js/JSHTMLCanvasElementCustom.cpp index 7ad36f8b2..172c0d997 100644 --- a/Source/WebCore/bindings/js/JSHTMLCanvasElementCustom.cpp +++ b/Source/WebCore/bindings/js/JSHTMLCanvasElementCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2016 Apple Inc. All rights reserved. * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -11,10 +11,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -27,119 +27,67 @@ #include "config.h" #include "JSHTMLCanvasElement.h" -#include "CanvasContextAttributes.h" #include "HTMLCanvasElement.h" -#include "InspectorCanvasInstrumentation.h" #include "JSCanvasRenderingContext2D.h" #include <bindings/ScriptObject.h> #include <wtf/GetPtr.h> #if ENABLE(WEBGL) -#include "JSDictionary.h" -#include "JSWebGLRenderingContext.h" -#include "WebGLContextAttributes.h" +#include "JSWebGLContextAttributes.h" +#include "JSWebGLRenderingContextBase.h" #endif using namespace JSC; namespace WebCore { -#if ENABLE(WEBGL) -static void get3DContextAttributes(ExecState* exec, RefPtr<CanvasContextAttributes>& attrs) +JSValue JSHTMLCanvasElement::getContext(ExecState& state) { - JSValue initializerValue = exec->argument(1); - if (initializerValue.isUndefinedOrNull()) - return; - - JSObject* initializerObject = initializerValue.toObject(exec); - JSDictionary dictionary(exec, initializerObject); - - GraphicsContext3D::Attributes graphicsAttrs; - - dictionary.tryGetProperty("alpha", graphicsAttrs.alpha); - dictionary.tryGetProperty("depth", graphicsAttrs.depth); - dictionary.tryGetProperty("stencil", graphicsAttrs.stencil); - dictionary.tryGetProperty("antialias", graphicsAttrs.antialias); - dictionary.tryGetProperty("premultipliedAlpha", graphicsAttrs.premultipliedAlpha); - dictionary.tryGetProperty("preserveDrawingBuffer", graphicsAttrs.preserveDrawingBuffer); - - attrs = WebGLContextAttributes::create(graphicsAttrs); -} -#endif + auto& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); -JSValue JSHTMLCanvasElement::getContext(ExecState* exec) -{ - HTMLCanvasElement& canvas = impl(); - const String& contextId = exec->argument(0).toString(exec)->value(exec); - - RefPtr<CanvasContextAttributes> attrs; -#if ENABLE(WEBGL) - if (HTMLCanvasElement::is3dType(contextId)) { - get3DContextAttributes(exec, attrs); - if (exec->hadException()) - return jsUndefined(); - } -#endif - - CanvasRenderingContext* context = canvas.getContext(contextId, attrs.get()); - if (!context) - return jsNull(); - JSValue jsValue = toJS(exec, globalObject(), WTF::getPtr(context)); - if (InspectorInstrumentation::canvasAgentEnabled(&canvas.document())) { - Deprecated::ScriptObject contextObject(exec, jsValue.getObject()); - Deprecated::ScriptObject wrapped; - if (context->is2d()) - wrapped = InspectorInstrumentation::wrapCanvas2DRenderingContextForInstrumentation(&canvas.document(), contextObject); -#if ENABLE(WEBGL) - else if (context->is3d()) - wrapped = InspectorInstrumentation::wrapWebGLRenderingContextForInstrumentation(&canvas.document(), contextObject); -#endif - if (!wrapped.hasNoValue()) - return wrapped.jsValue(); - } - return jsValue; -} + if (UNLIKELY(state.argumentCount() < 1)) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + + auto contextId = convert<IDLDOMString>(state, state.uncheckedArgument(0), StringConversionConfiguration::Normal); + RETURN_IF_EXCEPTION(scope, JSValue()); + + if (HTMLCanvasElement::is2dType(contextId)) + return toJS<IDLNullable<IDLInterface<CanvasRenderingContext2D>>>(state, *globalObject(), static_cast<CanvasRenderingContext2D*>(wrapped().getContext2d(contextId))); -JSValue JSHTMLCanvasElement::probablySupportsContext(ExecState* exec) -{ - HTMLCanvasElement& canvas = impl(); - if (!exec->argumentCount()) - return jsBoolean(false); - const String& contextId = exec->uncheckedArgument(0).toString(exec)->value(exec); - if (exec->hadException()) - return jsUndefined(); - - RefPtr<CanvasContextAttributes> attrs; #if ENABLE(WEBGL) if (HTMLCanvasElement::is3dType(contextId)) { - get3DContextAttributes(exec, attrs); - if (exec->hadException()) - return jsUndefined(); + auto attributes = convert<IDLDictionary<WebGLContextAttributes>>(state, state.argument(1)); + RETURN_IF_EXCEPTION(scope, JSValue()); + + return toJS<IDLNullable<IDLInterface<WebGLRenderingContextBase>>>(state, *globalObject(), static_cast<WebGLRenderingContextBase*>(wrapped().getContextWebGL(contextId, WTFMove(attributes)))); } #endif - - return jsBoolean(canvas.probablySupportsContext(contextId, attrs.get())); + + return jsNull(); } -JSValue JSHTMLCanvasElement::toDataURL(ExecState* exec) +JSValue JSHTMLCanvasElement::toDataURL(ExecState& state) { - HTMLCanvasElement& canvas = impl(); - ExceptionCode ec = 0; - - const String& type = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(0)); - double quality; - double* qualityPtr = 0; - if (exec->argumentCount() > 1) { - JSValue v = exec->uncheckedArgument(1); - if (v.isNumber()) { - quality = v.toNumber(exec); - qualityPtr = &quality; - } - } + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto type = convert<IDLNullable<IDLDOMString>>(state, state.argument(0)); + RETURN_IF_EXCEPTION(scope, JSC::JSValue()); - JSValue result = JSC::jsString(exec, canvas.toDataURL(type, qualityPtr, ec)); - setDOMException(exec, ec); - return result; + std::optional<double> quality; + auto qualityValue = state.argument(1); + if (qualityValue.isNumber()) + quality = qualityValue.toNumber(&state); + + // We would use toJS<IDLString> here, but it uses jsStringWithCache and we historically + // did not cache here, presumably because results are likely to be differing long strings. + auto result = wrapped().toDataURL(type, quality); + if (result.hasException()) { + propagateException(state, scope, result.releaseException()); + return { }; + } + return jsString(&state, result.releaseReturnValue()); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSHTMLCollectionCustom.cpp b/Source/WebCore/bindings/js/JSHTMLCollectionCustom.cpp index eecc08b0a..6c8c74d62 100644 --- a/Source/WebCore/bindings/js/JSHTMLCollectionCustom.cpp +++ b/Source/WebCore/bindings/js/JSHTMLCollectionCustom.cpp @@ -20,60 +20,34 @@ #include "config.h" #include "JSHTMLCollection.h" -#include "HTMLAllCollection.h" -#include "HTMLCollection.h" -#include "HTMLFormControlsCollection.h" -#include "HTMLOptionsCollection.h" #include "JSDOMBinding.h" #include "JSHTMLAllCollection.h" #include "JSHTMLFormControlsCollection.h" #include "JSHTMLOptionsCollection.h" -#include "JSNode.h" -#include "JSNodeList.h" -#include "JSRadioNodeList.h" -#include "Node.h" -#include "RadioNodeList.h" -#include <wtf/Vector.h> -#include <wtf/text/AtomicString.h> using namespace JSC; namespace WebCore { -bool JSHTMLCollection::canGetItemsForName(ExecState*, HTMLCollection* collection, PropertyName propertyName) +JSValue toJSNewlyCreated(ExecState*, JSDOMGlobalObject* globalObject, Ref<HTMLCollection>&& collection) { - return collection->hasNamedItem(propertyNameToAtomicString(propertyName)); -} - -EncodedJSValue JSHTMLCollection::nameGetter(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName propertyName) -{ - JSHTMLCollection* collection = jsCast<JSHTMLCollection*>(JSValue::decode(slotBase)); - const AtomicString& name = propertyNameToAtomicString(propertyName); - return JSValue::encode(toJS(exec, collection->globalObject(), collection->impl().namedItem(name))); -} - -JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, HTMLCollection* collection) -{ - if (!collection) - return jsNull(); - - JSObject* wrapper = getCachedWrapper(currentWorld(exec), collection); - - if (wrapper) - return wrapper; - switch (collection->type()) { case FormControls: - return CREATE_DOM_WRAPPER(exec, globalObject, HTMLFormControlsCollection, collection); + return createWrapper<HTMLFormControlsCollection>(globalObject, WTFMove(collection)); case SelectOptions: - return CREATE_DOM_WRAPPER(exec, globalObject, HTMLOptionsCollection, collection); + return createWrapper<HTMLOptionsCollection>(globalObject, WTFMove(collection)); case DocAll: - return CREATE_DOM_WRAPPER(exec, globalObject, HTMLAllCollection, collection); + return createWrapper<HTMLAllCollection>(globalObject, WTFMove(collection)); default: break; } - return CREATE_DOM_WRAPPER(exec, globalObject, HTMLCollection, collection); + return createWrapper<HTMLCollection>(globalObject, WTFMove(collection)); +} + +JSValue toJS(ExecState* state, JSDOMGlobalObject* globalObject, HTMLCollection& collection) +{ + return wrap(state, globalObject, collection); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSHTMLDocumentCustom.cpp b/Source/WebCore/bindings/js/JSHTMLDocumentCustom.cpp index 7e7bb5a44..2003cacac 100644 --- a/Source/WebCore/bindings/js/JSHTMLDocumentCustom.cpp +++ b/Source/WebCore/bindings/js/JSHTMLDocumentCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2007-2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,24 +26,11 @@ #include "config.h" #include "JSHTMLDocument.h" -#include "Frame.h" -#include "HTMLAllCollection.h" -#include "HTMLBodyElement.h" -#include "HTMLCollection.h" -#include "HTMLDocument.h" -#include "HTMLElement.h" #include "HTMLIFrameElement.h" -#include "HTMLNames.h" -#include "JSDOMWindow.h" #include "JSDOMWindowCustom.h" -#include "JSDOMWindowShell.h" #include "JSHTMLCollection.h" -#include "JSMainThreadExecState.h" #include "SegmentedString.h" -#include "DocumentParser.h" -#include <runtime/Error.h> -#include <runtime/JSCell.h> -#include <wtf/unicode/CharacterNames.h> +#include <runtime/Lookup.h> using namespace JSC; @@ -51,120 +38,153 @@ namespace WebCore { using namespace HTMLNames; -bool JSHTMLDocument::canGetItemsForName(ExecState*, HTMLDocument* document, PropertyName propertyName) +JSValue toJSNewlyCreated(ExecState* state, JSDOMGlobalObject* globalObject, Ref<HTMLDocument>&& passedDocument) { - AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName); - return atomicPropertyName && document->hasDocumentNamedItem(*atomicPropertyName); + auto& document = passedDocument.get(); + auto* wrapper = createWrapper<HTMLDocument>(globalObject, WTFMove(passedDocument)); + reportMemoryForDocumentIfFrameless(*state, document); + return wrapper; } -EncodedJSValue JSHTMLDocument::nameGetter(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName propertyName) +JSValue toJS(ExecState* state, JSDOMGlobalObject* globalObject, HTMLDocument& document) { - JSHTMLDocument* thisObj = jsCast<JSHTMLDocument*>(JSValue::decode(slotBase)); - HTMLDocument& document = thisObj->impl(); + if (auto* wrapper = cachedDocumentWrapper(*state, *globalObject, document)) + return wrapper; + return toJSNewlyCreated(state, globalObject, Ref<HTMLDocument>(document)); +} + +bool JSHTMLDocument::getOwnPropertySlot(JSObject* object, ExecState* state, PropertyName propertyName, PropertySlot& slot) +{ + auto& thisObject = *jsCast<JSHTMLDocument*>(object); + ASSERT_GC_OBJECT_INHERITS(object, info()); + + if (propertyName == "open") { + if (Base::getOwnPropertySlot(&thisObject, state, propertyName, slot)) + return true; + slot.setCustom(&thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsHTMLDocumentPrototypeFunctionOpen, 2>); + return true; + } + + JSValue value; + if (thisObject.nameGetter(state, propertyName, value)) { + slot.setValue(&thisObject, ReadOnly | DontDelete | DontEnum, value); + return true; + } - AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName); + return Base::getOwnPropertySlot(&thisObject, state, propertyName, slot); +} + +bool JSHTMLDocument::nameGetter(ExecState* state, PropertyName propertyName, JSValue& value) +{ + auto& document = wrapped(); + + auto* atomicPropertyName = propertyName.publicName(); if (!atomicPropertyName || !document.hasDocumentNamedItem(*atomicPropertyName)) - return JSValue::encode(jsUndefined()); + return false; if (UNLIKELY(document.documentNamedItemContainsMultipleElements(*atomicPropertyName))) { - RefPtr<HTMLCollection> collection = document.documentNamedItems(atomicPropertyName); + auto collection = document.documentNamedItems(atomicPropertyName); ASSERT(collection->length() > 1); - return JSValue::encode(toJS(exec, thisObj->globalObject(), WTF::getPtr(collection))); + value = toJS(state, globalObject(), collection); + return true; } - Element* element = document.documentNamedItem(*atomicPropertyName); - if (UNLIKELY(element->hasTagName(iframeTag))) { - if (Frame* frame = toHTMLIFrameElement(element)->contentFrame()) - return JSValue::encode(toJS(exec, frame)); + auto& element = *document.documentNamedItem(*atomicPropertyName); + if (UNLIKELY(is<HTMLIFrameElement>(element))) { + if (auto* frame = downcast<HTMLIFrameElement>(element).contentFrame()) { + value = toJS(state, frame); + return true; + } } - return JSValue::encode(toJS(exec, thisObj->globalObject(), element)); + value = toJS(state, globalObject(), element); + return true; } // Custom attributes -JSValue JSHTMLDocument::all(ExecState* exec) const +JSValue JSHTMLDocument::all(ExecState& state) const { // If "all" has been overwritten, return the overwritten value - JSValue v = getDirect(exec->vm(), Identifier(exec, "all")); - if (v) - return v; + if (auto overwrittenValue = getDirect(state.vm(), Identifier::fromString(&state, "all"))) + return overwrittenValue; - return toJS(exec, globalObject(), impl().all()); + return toJS(&state, globalObject(), wrapped().all()); } -void JSHTMLDocument::setAll(ExecState* exec, JSValue value) +void JSHTMLDocument::setAll(ExecState& state, JSValue value) { // Add "all" to the property map. - putDirect(exec->vm(), Identifier(exec, "all"), value); + putDirect(state.vm(), Identifier::fromString(&state, "all"), value); +} + +static inline Document* findCallingDocument(ExecState& state) +{ + CallerFunctor functor; + state.iterate(functor); + auto* callerFrame = functor.callerFrame(); + if (!callerFrame) + return nullptr; + return asJSDOMWindow(callerFrame->lexicalGlobalObject())->wrapped().document(); } // Custom functions -JSValue JSHTMLDocument::open(ExecState* exec) +JSValue JSHTMLDocument::open(ExecState& state) { + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + // For compatibility with other browsers, pass open calls with more than 2 parameters to the window. - if (exec->argumentCount() > 2) { - if (Frame* frame = impl().frame()) { - JSDOMWindowShell* wrapper = toJSDOMWindowShell(frame, currentWorld(exec)); - if (wrapper) { - JSValue function = wrapper->get(exec, Identifier(exec, "open")); + if (state.argumentCount() > 2) { + if (auto* frame = wrapped().frame()) { + if (auto* wrapper = toJSDOMWindowShell(frame, currentWorld(&state))) { + auto function = wrapper->get(&state, Identifier::fromString(&state, "open")); CallData callData; - CallType callType = ::getCallData(function, callData); - if (callType == CallTypeNone) - return throwTypeError(exec); - return JSMainThreadExecState::call(exec, function, callType, callData, wrapper, ArgList(exec)); + auto callType = ::getCallData(function, callData); + if (callType == CallType::None) + return throwTypeError(&state, scope); + return JSC::call(&state, function, callType, callData, wrapper, ArgList(&state)); } } return jsUndefined(); } - // document.open clobbers the security context of the document and - // aliases it with the active security context. - Document* activeDocument = asJSDOMWindow(exec->lexicalGlobalObject())->impl().document(); - - // In the case of two parameters or fewer, do a normal document open. - impl().open(activeDocument); + // Calling document.open clobbers the security context of the document and aliases it with the active security context. + // FIXME: Is it correct that this does not use findCallingDocument as the write function below does? + wrapped().open(asJSDOMWindow(state.lexicalGlobalObject())->wrapped().document()); + // FIXME: Why do we return the document instead of returning undefined? return this; } enum NewlineRequirement { DoNotAddNewline, DoAddNewline }; -static inline void documentWrite(ExecState* exec, HTMLDocument* document, NewlineRequirement addNewline) +static inline JSValue documentWrite(ExecState& state, JSHTMLDocument& document, NewlineRequirement addNewline) { - // DOM only specifies single string argument, but browsers allow multiple or no arguments. - - size_t size = exec->argumentCount(); - - String firstString = exec->argument(0).toString(exec)->value(exec); - SegmentedString segmentedString = firstString; - if (size != 1) { - if (!size) - segmentedString.clear(); - else { - for (size_t i = 1; i < size; ++i) { - String subsequentString = exec->uncheckedArgument(i).toString(exec)->value(exec); - segmentedString.append(SegmentedString(subsequentString)); - } - } + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + SegmentedString segmentedString; + size_t argumentCount = state.argumentCount(); + for (size_t i = 0; i < argumentCount; ++i) { + segmentedString.append(state.uncheckedArgument(i).toWTFString(&state)); + RETURN_IF_EXCEPTION(scope, { }); } if (addNewline) - segmentedString.append(SegmentedString(String(&newlineCharacter, 1))); + segmentedString.append(String { "\n" }); - Document* activeDocument = asJSDOMWindow(exec->lexicalGlobalObject())->impl().document(); - document->write(segmentedString, activeDocument); + document.wrapped().write(WTFMove(segmentedString), findCallingDocument(state)); + return jsUndefined(); } -JSValue JSHTMLDocument::write(ExecState* exec) +JSValue JSHTMLDocument::write(ExecState& state) { - documentWrite(exec, &impl(), DoNotAddNewline); - return jsUndefined(); + return documentWrite(state, *this, DoNotAddNewline); } -JSValue JSHTMLDocument::writeln(ExecState* exec) +JSValue JSHTMLDocument::writeln(ExecState& state) { - documentWrite(exec, &impl(), DoAddNewline); - return jsUndefined(); + return documentWrite(state, *this, DoAddNewline); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSHTMLElementCustom.cpp b/Source/WebCore/bindings/js/JSHTMLElementCustom.cpp index 4ee3fd9ef..43792a9d8 100644 --- a/Source/WebCore/bindings/js/JSHTMLElementCustom.cpp +++ b/Source/WebCore/bindings/js/JSHTMLElementCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,27 +26,108 @@ #include "config.h" #include "JSHTMLElement.h" +#include "CustomElementRegistry.h" +#include "DOMWindow.h" #include "Document.h" #include "HTMLFormElement.h" +#include "JSCustomElementInterface.h" +#include "JSDOMConstructorBase.h" +#include "JSNodeCustom.h" +#include "ScriptExecutionContext.h" +#include <runtime/InternalFunction.h> #include <runtime/JSWithScope.h> namespace WebCore { using namespace JSC; +EncodedJSValue JSC_HOST_CALL constructJSHTMLElement(ExecState& exec) +{ + VM& vm = exec.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto* jsConstructor = jsCast<JSDOMConstructorBase*>(exec.jsCallee()); + ASSERT(jsConstructor); + + auto* context = jsConstructor->scriptExecutionContext(); + if (!context) + return throwConstructorScriptExecutionContextUnavailableError(exec, scope, "HTMLElement"); + ASSERT(context->isDocument()); + + JSValue newTargetValue = exec.thisValue(); + auto* globalObject = jsConstructor->globalObject(); + JSValue htmlElementConstructorValue = JSHTMLElement::getConstructor(vm, globalObject); + if (newTargetValue == htmlElementConstructorValue) + return throwVMTypeError(&exec, scope, ASCIILiteral("new.target is not a valid custom element constructor")); + + auto& document = downcast<Document>(*context); + + auto* window = document.domWindow(); + if (!window) + return throwVMTypeError(&exec, scope, ASCIILiteral("new.target is not a valid custom element constructor")); + + auto* registry = window->customElementRegistry(); + if (!registry) + return throwVMTypeError(&exec, scope, ASCIILiteral("new.target is not a valid custom element constructor")); + + JSObject* newTarget = newTargetValue.getObject(); + auto* elementInterface = registry->findInterface(newTarget); + if (!elementInterface) + return throwVMTypeError(&exec, scope, ASCIILiteral("new.target does not define a custom element")); + + if (!elementInterface->isUpgradingElement()) { + Structure* baseStructure = getDOMStructure<JSHTMLElement>(vm, *globalObject); + auto* newElementStructure = InternalFunction::createSubclassStructure(&exec, newTargetValue, baseStructure); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + + Ref<HTMLElement> element = HTMLElement::create(elementInterface->name(), document); + element->setIsDefinedCustomElement(*elementInterface); + auto* jsElement = JSHTMLElement::create(newElementStructure, globalObject, element.get()); + cacheWrapper(globalObject->world(), element.ptr(), jsElement); + return JSValue::encode(jsElement); + } + + Element* elementToUpgrade = elementInterface->lastElementInConstructionStack(); + if (!elementToUpgrade) { + throwInvalidStateError(exec, scope, ASCIILiteral("Cannot instantiate a custom element inside its own constrcutor during upgrades")); + return JSValue::encode(jsUndefined()); + } + + JSValue elementWrapperValue = toJS(&exec, jsConstructor->globalObject(), *elementToUpgrade); + ASSERT(elementWrapperValue.isObject()); + + JSValue newPrototype = newTarget->get(&exec, vm.propertyNames->prototype); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + + JSObject* elementWrapperObject = asObject(elementWrapperValue); + JSObject::setPrototype(elementWrapperObject, &exec, newPrototype, true /* shouldThrowIfCantSet */); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); + + elementInterface->didUpgradeLastElementInConstructionStack(); + + return JSValue::encode(elementWrapperValue); +} + JSScope* JSHTMLElement::pushEventHandlerScope(ExecState* exec, JSScope* scope) const { - HTMLElement& element = impl(); + HTMLElement& element = wrapped(); // The document is put on first, fall back to searching it only after the element and form. - scope = JSWithScope::create(exec, asObject(toJS(exec, globalObject(), &element.document())), scope); + // FIXME: This probably may use the wrong global object. If this is called from a native + // function, then it would be correct but not optimal since the native function would *know* + // the global object. But, it may be that globalObject() is more correct. + // https://bugs.webkit.org/show_bug.cgi?id=134932 + VM& vm = exec->vm(); + JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject(); + + scope = JSWithScope::create(vm, lexicalGlobalObject, asObject(toJS(exec, globalObject(), element.document())), scope); // The form is next, searched before the document, but after the element itself. if (HTMLFormElement* form = element.form()) - scope = JSWithScope::create(exec, asObject(toJS(exec, globalObject(), form)), scope); + scope = JSWithScope::create(vm, lexicalGlobalObject, asObject(toJS(exec, globalObject(), *form)), scope); // The element is on top, searched first. - return JSWithScope::create(exec, asObject(toJS(exec, globalObject(), &element)), scope); + return JSWithScope::create(vm, lexicalGlobalObject, asObject(toJS(exec, globalObject(), element)), scope); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSHTMLEmbedElementCustom.cpp b/Source/WebCore/bindings/js/JSHTMLEmbedElementCustom.cpp index 73f2c2bfb..919f68662 100644 --- a/Source/WebCore/bindings/js/JSHTMLEmbedElementCustom.cpp +++ b/Source/WebCore/bindings/js/JSHTMLEmbedElementCustom.cpp @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -38,9 +38,9 @@ bool JSHTMLEmbedElement::getOwnPropertySlotDelegate(ExecState* exec, PropertyNam return pluginElementCustomGetOwnPropertySlot<JSHTMLEmbedElement, Base>(exec, propertyName, slot, this); } -bool JSHTMLEmbedElement::putDelegate(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) +bool JSHTMLEmbedElement::putDelegate(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot, bool& putResult) { - return pluginElementCustomPut(exec, propertyName, value, this, slot); + return pluginElementCustomPut(exec, propertyName, value, this, slot, putResult); } CallType JSHTMLEmbedElement::getCallData(JSCell* cell, CallData& callData) diff --git a/Source/WebCore/bindings/js/JSHTMLFormControlsCollectionCustom.cpp b/Source/WebCore/bindings/js/JSHTMLFormControlsCollectionCustom.cpp index fc41eb61a..58d9b676b 100644 --- a/Source/WebCore/bindings/js/JSHTMLFormControlsCollectionCustom.cpp +++ b/Source/WebCore/bindings/js/JSHTMLFormControlsCollectionCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007-2008, 2016 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -18,54 +18,51 @@ */ #include "config.h" -#include "HTMLFormControlsCollection.h" - - -#include "HTMLAllCollection.h" -#include "JSDOMBinding.h" -#include "JSHTMLCollection.h" #include "JSHTMLFormControlsCollection.h" + +#include "HTMLFormControlsCollection.h" #include "JSNode.h" -#include "JSNodeList.h" #include "JSRadioNodeList.h" -#include "Node.h" #include "RadioNodeList.h" -#include <wtf/Vector.h> -#include <wtf/text/AtomicString.h> +#include <runtime/IdentifierInlines.h> using namespace JSC; namespace WebCore { -static JSValue getNamedItems(ExecState* exec, JSHTMLFormControlsCollection* collection, PropertyName propertyName) +static JSValue namedItems(ExecState& state, JSHTMLFormControlsCollection* collection, PropertyName propertyName) { - Vector<Ref<Element>> namedItems; const AtomicString& name = propertyNameToAtomicString(propertyName); - collection->impl().namedItems(name, namedItems); + Vector<Ref<Element>> namedItems = collection->wrapped().namedItems(name); if (namedItems.isEmpty()) return jsUndefined(); if (namedItems.size() == 1) - return toJS(exec, collection->globalObject(), &namedItems[0].get()); + return toJS(&state, collection->globalObject(), namedItems[0]); - ASSERT(collection->impl().type() == FormControls); - return toJS(exec, collection->globalObject(), collection->impl().ownerNode().radioNodeList(name).get()); + ASSERT(collection->wrapped().type() == FormControls); + return toJS(&state, collection->globalObject(), collection->wrapped().ownerNode().radioNodeList(name).get()); } -bool JSHTMLFormControlsCollection::canGetItemsForName(ExecState*, HTMLFormControlsCollection* collection, PropertyName propertyName) +bool JSHTMLFormControlsCollection::nameGetter(ExecState* state, PropertyName propertyName, JSValue& value) { - return collection->hasNamedItem(propertyNameToAtomicString(propertyName)); -} + auto items = namedItems(*state, this, propertyName); + if (items.isUndefined()) + return false; -EncodedJSValue JSHTMLFormControlsCollection::nameGetter(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName propertyName) -{ - JSHTMLFormControlsCollection* thisObj = jsCast<JSHTMLFormControlsCollection*>(JSValue::decode(slotBase)); - return JSValue::encode(getNamedItems(exec, thisObj, propertyName)); + value = items; + return true; } -JSValue JSHTMLFormControlsCollection::namedItem(ExecState* exec) +JSValue JSHTMLFormControlsCollection::namedItem(ExecState& state) { - JSValue value = getNamedItems(exec, this, Identifier(exec, exec->argument(0).toString(exec)->value(exec))); + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(state.argumentCount() < 1)) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + + JSValue value = namedItems(state, this, Identifier::fromString(&state, state.uncheckedArgument(0).toWTFString(&state))); return value.isUndefined() ? jsNull() : value; } diff --git a/Source/WebCore/bindings/js/JSHTMLFormElementCustom.cpp b/Source/WebCore/bindings/js/JSHTMLFormElementCustom.cpp deleted file mode 100644 index 416887261..000000000 --- a/Source/WebCore/bindings/js/JSHTMLFormElementCustom.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2006, 2007, 2008 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 COMPUTER, INC. ``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 COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "JSHTMLFormElement.h" - -#include "Frame.h" -#include "HTMLCollection.h" -#include "HTMLFormElement.h" -#include "JSDOMWindowCustom.h" -#include "JSNodeList.h" -#include "StaticNodeList.h" - -using namespace JSC; - -namespace WebCore { - -bool JSHTMLFormElement::canGetItemsForName(ExecState*, HTMLFormElement* form, PropertyName propertyName) -{ - return form->hasNamedElement(propertyNameToAtomicString(propertyName)); -} - -EncodedJSValue JSHTMLFormElement::nameGetter(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName propertyName) -{ - JSHTMLFormElement* jsForm = jsCast<JSHTMLFormElement*>(JSValue::decode(slotBase)); - HTMLFormElement& form = jsForm->impl(); - - Vector<Ref<Element>> namedItems; - form.getNamedElements(propertyNameToAtomicString(propertyName), namedItems); - - if (namedItems.isEmpty()) - return JSValue::encode(jsUndefined()); - if (namedItems.size() == 1) - return JSValue::encode(toJS(exec, jsForm->globalObject(), &namedItems[0].get())); - - // FIXME: HTML5 specifies that this should be a RadioNodeList. - return JSValue::encode(toJS(exec, jsForm->globalObject(), StaticElementList::adopt(namedItems).get())); -} - -} diff --git a/Source/WebCore/bindings/js/JSHTMLFrameElementCustom.cpp b/Source/WebCore/bindings/js/JSHTMLFrameElementCustom.cpp deleted file mode 100644 index 88f82c505..000000000 --- a/Source/WebCore/bindings/js/JSHTMLFrameElementCustom.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2007, 2008 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 "JSHTMLFrameElement.h" - -#include "Document.h" -#include "HTMLFrameElement.h" -#include "HTMLNames.h" -#include "HTMLParserIdioms.h" -#include "JSDOMBinding.h" - -using namespace JSC; - -namespace WebCore { - -using namespace HTMLNames; - -static inline bool allowSettingJavascriptURL(ExecState* exec, HTMLFrameElement* imp, const String& value) -{ - if (protocolIsJavaScript(stripLeadingAndTrailingHTMLSpaces(value))) { - Document* contentDocument = imp->contentDocument(); - if (contentDocument && !shouldAllowAccessToNode(exec, contentDocument)) - return false; - } - return true; -} - -void JSHTMLFrameElement::setLocation(ExecState* exec, JSValue value) -{ - HTMLFrameElement& imp = impl(); - String locationValue = valueToStringWithNullCheck(exec, value); - - if (!allowSettingJavascriptURL(exec, &imp, locationValue)) - return; - - imp.setLocation(locationValue); -} - -} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSHTMLFrameSetElementCustom.cpp b/Source/WebCore/bindings/js/JSHTMLFrameSetElementCustom.cpp index 6df61d1c1..125aef7ec 100644 --- a/Source/WebCore/bindings/js/JSHTMLFrameSetElementCustom.cpp +++ b/Source/WebCore/bindings/js/JSHTMLFrameSetElementCustom.cpp @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -30,7 +30,6 @@ #include "HTMLCollection.h" #include "HTMLFrameElement.h" #include "HTMLFrameSetElement.h" -#include "HTMLNames.h" #include "JSDOMWindow.h" #include "JSDOMWindowShell.h" #include "JSDOMBinding.h" @@ -39,23 +38,19 @@ using namespace JSC; namespace WebCore { -using namespace HTMLNames; - -bool JSHTMLFrameSetElement::canGetItemsForName(ExecState*, HTMLFrameSetElement* frameSet, PropertyName propertyName) -{ - Node* frame = frameSet->children()->namedItem(propertyNameToAtomicString(propertyName)); - return frame && frame->hasTagName(frameTag); -} - -EncodedJSValue JSHTMLFrameSetElement::nameGetter(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName propertyName) +bool JSHTMLFrameSetElement::nameGetter(ExecState* exec, PropertyName propertyName, JSValue& value) { - HTMLElement& element = jsCast<JSHTMLElement*>(JSValue::decode(slotBase))->impl(); - Node* frameElement = element.children()->namedItem(propertyNameToAtomicString(propertyName)); - if (Document* document = toHTMLFrameElement(frameElement)->contentDocument()) { - if (JSDOMWindowShell* window = toJSDOMWindowShell(document->frame(), currentWorld(exec))) - return JSValue::encode(window); + auto* frameElement = wrapped().children()->namedItem(propertyNameToAtomicString(propertyName)); + if (!is<HTMLFrameElement>(frameElement)) + return false; + + if (auto* document = downcast<HTMLFrameElement>(*frameElement).contentDocument()) { + if (JSDOMWindowShell* window = toJSDOMWindowShell(document->frame(), currentWorld(exec))) { + value = window; + return true; + } } - return JSValue::encode(jsUndefined()); + return false; } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSHTMLInputElementCustom.cpp b/Source/WebCore/bindings/js/JSHTMLInputElementCustom.cpp deleted file mode 100644 index 42ebad315..000000000 --- a/Source/WebCore/bindings/js/JSHTMLInputElementCustom.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2008 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. ``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 - * 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 "JSHTMLInputElement.h" - -#include "HTMLInputElement.h" -#include <runtime/Error.h> - -using namespace JSC; - -namespace WebCore { - -JSValue JSHTMLInputElement::selectionStart(ExecState* exec) const -{ - HTMLInputElement& input = impl(); - if (!input.canHaveSelection()) - return throwTypeError(exec); - - return jsNumber(input.selectionStart()); -} - -void JSHTMLInputElement::setSelectionStart(ExecState* exec, JSValue value) -{ - HTMLInputElement& input = impl(); - if (!input.canHaveSelection()) - throwTypeError(exec); - - input.setSelectionStart(value.toInt32(exec)); -} - -JSValue JSHTMLInputElement::selectionEnd(ExecState* exec) const -{ - HTMLInputElement& input = impl(); - if (!input.canHaveSelection()) - return throwTypeError(exec); - - return jsNumber(input.selectionEnd()); -} - -void JSHTMLInputElement::setSelectionEnd(ExecState* exec, JSValue value) -{ - HTMLInputElement& input = impl(); - if (!input.canHaveSelection()) - throwTypeError(exec); - - input.setSelectionEnd(value.toInt32(exec)); -} - -JSValue JSHTMLInputElement::selectionDirection(ExecState* exec) const -{ - HTMLInputElement& input = impl(); - if (!input.canHaveSelection()) - return throwTypeError(exec); - - return jsStringWithCache(exec, input.selectionDirection()); -} - -void JSHTMLInputElement::setSelectionDirection(ExecState* exec, JSValue value) -{ - HTMLInputElement& input = impl(); - if (!input.canHaveSelection()) { - throwTypeError(exec); - return; - } - - input.setSelectionDirection(value.toString(exec)->value(exec)); -} - -JSValue JSHTMLInputElement::setSelectionRange(ExecState* exec) -{ - HTMLInputElement& input = impl(); - if (!input.canHaveSelection()) - return throwTypeError(exec); - - int start = exec->argument(0).toInt32(exec); - int end = exec->argument(1).toInt32(exec); - String direction = exec->argument(2).toString(exec)->value(exec); - - input.setSelectionRange(start, end, direction); - return jsUndefined(); -} - -} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSHTMLObjectElementCustom.cpp b/Source/WebCore/bindings/js/JSHTMLObjectElementCustom.cpp index b791186fc..4a8647f89 100644 --- a/Source/WebCore/bindings/js/JSHTMLObjectElementCustom.cpp +++ b/Source/WebCore/bindings/js/JSHTMLObjectElementCustom.cpp @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -38,9 +38,9 @@ bool JSHTMLObjectElement::getOwnPropertySlotDelegate(ExecState* exec, PropertyNa return pluginElementCustomGetOwnPropertySlot<JSHTMLObjectElement, Base>(exec, propertyName, slot, this); } -bool JSHTMLObjectElement::putDelegate(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) +bool JSHTMLObjectElement::putDelegate(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot, bool& putResult) { - return pluginElementCustomPut(exec, propertyName, value, this, slot); + return pluginElementCustomPut(exec, propertyName, value, this, slot, putResult); } CallType JSHTMLObjectElement::getCallData(JSCell* cell, CallData& callData) diff --git a/Source/WebCore/bindings/js/JSHTMLOptionsCollectionCustom.cpp b/Source/WebCore/bindings/js/JSHTMLOptionsCollectionCustom.cpp index 74a58672f..356679a8e 100644 --- a/Source/WebCore/bindings/js/JSHTMLOptionsCollectionCustom.cpp +++ b/Source/WebCore/bindings/js/JSHTMLOptionsCollectionCustom.cpp @@ -20,72 +20,21 @@ #include "config.h" #include "JSHTMLOptionsCollection.h" +#include "CustomElementReactionQueue.h" #include "ExceptionCode.h" -#include "HTMLNames.h" -#include "HTMLOptionElement.h" -#include "HTMLOptionsCollection.h" -#include "HTMLSelectElement.h" #include "JSHTMLOptionElement.h" #include "JSHTMLSelectElement.h" #include "JSHTMLSelectElementCustom.h" -#include "JSNodeList.h" -#include "StaticNodeList.h" - #include <wtf/MathExtras.h> using namespace JSC; namespace WebCore { -void JSHTMLOptionsCollection::setLength(ExecState* exec, JSValue value) -{ - ExceptionCode ec = 0; - unsigned newLength = 0; - double lengthValue = value.toNumber(exec); - if (!std::isnan(lengthValue) && !std::isinf(lengthValue)) { - if (lengthValue < 0.0) - ec = INDEX_SIZE_ERR; - else if (lengthValue > static_cast<double>(UINT_MAX)) - newLength = UINT_MAX; - else - newLength = static_cast<unsigned>(lengthValue); - } - if (!ec) - impl().setLength(newLength, ec); - setDOMException(exec, ec); -} - -void JSHTMLOptionsCollection::indexSetter(ExecState* exec, unsigned index, JSValue value) -{ - selectIndexSetter(&impl().selectElement(), exec, index, value); -} - -JSValue JSHTMLOptionsCollection::add(ExecState* exec) -{ - HTMLOptionsCollection& imp = impl(); - HTMLOptionElement* option = toHTMLOptionElement(exec->argument(0)); - ExceptionCode ec = 0; - if (exec->argumentCount() < 2) - imp.add(option, ec); - else { - int index = exec->argument(1).toInt32(exec); - if (exec->hadException()) - return jsUndefined(); - imp.add(option, index, ec); - } - setDOMException(exec, ec); - return jsUndefined(); -} - -JSValue JSHTMLOptionsCollection::remove(ExecState* exec) +void JSHTMLOptionsCollection::indexSetter(ExecState* state, unsigned index, JSValue value) { - // The argument can be an HTMLOptionElement or an index. - JSValue argument = exec->argument(0); - if (HTMLOptionElement* option = toHTMLOptionElement(argument)) - impl().remove(option); - else - impl().remove(argument.toInt32(exec)); - return jsUndefined(); + CustomElementReactionStack customElementReactionStack; + selectElementIndexSetter(*state, wrapped().selectElement(), index, value); } } diff --git a/Source/WebCore/bindings/js/JSHTMLSelectElementCustom.cpp b/Source/WebCore/bindings/js/JSHTMLSelectElementCustom.cpp index 43f694b50..c74aed3df 100644 --- a/Source/WebCore/bindings/js/JSHTMLSelectElementCustom.cpp +++ b/Source/WebCore/bindings/js/JSHTMLSelectElementCustom.cpp @@ -21,55 +21,34 @@ #include "config.h" #include "JSHTMLSelectElementCustom.h" +#include "CustomElementReactionQueue.h" #include "ExceptionCode.h" #include "HTMLNames.h" #include "HTMLOptionElement.h" #include "HTMLSelectElement.h" #include "JSHTMLOptionElement.h" +#include "JSHTMLSelectElement.h" namespace WebCore { using namespace JSC; using namespace HTMLNames; -JSValue JSHTMLSelectElement::remove(ExecState* exec) +void selectElementIndexSetter(JSC::ExecState& state, HTMLSelectElement& element, unsigned index, JSC::JSValue value) { - HTMLSelectElement& select = impl(); + VM& vm = state.vm(); + auto throwScope = DECLARE_THROW_SCOPE(vm); - if (!exec->argumentCount()) { - // When called with no argument, we should call Element::remove() to detach. - ExceptionCode ec = 0; - select.remove(ec); - setDOMException(exec, ec); - } else { - // The HTMLSelectElement::remove() function can take either an option object or the index of an option. - if (HTMLOptionElement* option = toHTMLOptionElement(exec->argument(0))) - select.remove(option); - else - select.removeByIndex(exec->argument(0).toInt32(exec)); - } + auto* option = convert<IDLNullable<IDLInterface<HTMLOptionElement>>>(state, value); + RETURN_IF_EXCEPTION(throwScope, void()); - return jsUndefined(); + propagateException(state, throwScope, element.setItem(index, option)); } -void selectIndexSetter(HTMLSelectElement* select, JSC::ExecState* exec, unsigned index, JSC::JSValue value) +void JSHTMLSelectElement::indexSetter(JSC::ExecState* state, unsigned index, JSC::JSValue value) { - if (value.isUndefinedOrNull()) - select->removeByIndex(index); - else { - ExceptionCode ec = 0; - HTMLOptionElement* option = toHTMLOptionElement(value); - if (!option) - ec = TYPE_MISMATCH_ERR; - else - select->setOption(index, option, ec); - setDOMException(exec, ec); - } -} - -void JSHTMLSelectElement::indexSetter(JSC::ExecState* exec, unsigned index, JSC::JSValue value) -{ - selectIndexSetter(&impl(), exec, index, value); + CustomElementReactionStack customElementReactionStack; + selectElementIndexSetter(*state, wrapped(), index, value); } } diff --git a/Source/WebCore/bindings/js/JSHTMLSelectElementCustom.h b/Source/WebCore/bindings/js/JSHTMLSelectElementCustom.h index a4490380c..e012bccef 100644 --- a/Source/WebCore/bindings/js/JSHTMLSelectElementCustom.h +++ b/Source/WebCore/bindings/js/JSHTMLSelectElementCustom.h @@ -10,7 +10,7 @@ * 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -26,15 +26,17 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSHTMLSelectElementCustom_h -#define JSHTMLSelectElementCustom_h +#pragma once -#include "JSHTMLSelectElement.h" +namespace JSC { +class ExecState; +class JSValue; +} namespace WebCore { -void selectIndexSetter(HTMLSelectElement*, JSC::ExecState*, unsigned index, JSC::JSValue); +class HTMLSelectElement; -} +void selectElementIndexSetter(JSC::ExecState&, HTMLSelectElement&, unsigned index, JSC::JSValue); -#endif +} diff --git a/Source/WebCore/bindings/js/JSHTMLTemplateElementCustom.cpp b/Source/WebCore/bindings/js/JSHTMLTemplateElementCustom.cpp index e4cda2baf..ff91eada0 100644 --- a/Source/WebCore/bindings/js/JSHTMLTemplateElementCustom.cpp +++ b/Source/WebCore/bindings/js/JSHTMLTemplateElementCustom.cpp @@ -29,9 +29,6 @@ */ #include "config.h" - -#if ENABLE(TEMPLATE_ELEMENT) - #include "JSHTMLTemplateElement.h" #include "HTMLTemplateElement.h" @@ -43,22 +40,15 @@ using namespace JSC; namespace WebCore { -JSValue JSHTMLTemplateElement::content(ExecState* exec) const +JSValue JSHTMLTemplateElement::content(ExecState& state) const { - JSLockHolder lock(exec); + JSLockHolder lock(&state); - DocumentFragment* content = impl().content(); + auto wrapper = wrap(&state, globalObject(), wrapped().content()); - JSObject* wrapper = getCachedWrapper(currentWorld(exec), content); - if (wrapper) - return wrapper; - - wrapper = CREATE_DOM_WRAPPER(exec, globalObject(), DocumentFragment, content); PrivateName propertyName; const_cast<JSHTMLTemplateElement*>(this)->putDirect(globalObject()->vm(), propertyName, wrapper); return wrapper; } } // namespace WebCore - -#endif // ENABLE(TEMPLATE_ELEMENT) diff --git a/Source/WebCore/bindings/js/JSHistoryCustom.cpp b/Source/WebCore/bindings/js/JSHistoryCustom.cpp index c608f5328..1d4efac31 100644 --- a/Source/WebCore/bindings/js/JSHistoryCustom.cpp +++ b/Source/WebCore/bindings/js/JSHistoryCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,7 +10,7 @@ * 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -29,8 +29,9 @@ #include "config.h" #include "JSHistory.h" +#include "ExceptionCode.h" #include "Frame.h" -#include "History.h" +#include "JSDOMConvert.h" #include "SerializedScriptValue.h" #include <runtime/JSFunction.h> @@ -38,159 +39,72 @@ using namespace JSC; namespace WebCore { -static EncodedJSValue nonCachingStaticBackFunctionGetter(ExecState* exec, EncodedJSValue, EncodedJSValue, PropertyName propertyName) +JSValue JSHistory::state(ExecState& state) const { - return JSValue::encode(JSFunction::create(exec->vm(), exec->lexicalGlobalObject(), 0, propertyName.publicName(), jsHistoryPrototypeFunctionBack)); -} - -static EncodedJSValue nonCachingStaticForwardFunctionGetter(ExecState* exec, EncodedJSValue, EncodedJSValue, PropertyName propertyName) -{ - return JSValue::encode(JSFunction::create(exec->vm(), exec->lexicalGlobalObject(), 0, propertyName.publicName(), jsHistoryPrototypeFunctionForward)); -} - -static EncodedJSValue nonCachingStaticGoFunctionGetter(ExecState* exec, EncodedJSValue, EncodedJSValue, PropertyName propertyName) -{ - return JSValue::encode(JSFunction::create(exec->vm(), exec->lexicalGlobalObject(), 1, propertyName.publicName(), jsHistoryPrototypeFunctionGo)); -} - -bool JSHistory::getOwnPropertySlotDelegate(ExecState* exec, PropertyName propertyName, PropertySlot& slot) -{ - // When accessing History cross-domain, functions are always the native built-in ones. - // See JSDOMWindow::getOwnPropertySlotDelegate for additional details. - - // Our custom code is only needed to implement the Window cross-domain scheme, so if access is - // allowed, return false so the normal lookup will take place. - String message; - if (shouldAllowAccessToFrame(exec, impl().frame(), message)) - return false; - - // Check for the few functions that we allow, even when called cross-domain. - // Make these read-only / non-configurable to prevent writes via defineProperty. - const HashEntry* entry = JSHistoryPrototype::info()->propHashTable(exec)->entry(exec, propertyName); - if (entry) { - // Allow access to back(), forward() and go() from any frame. - if (entry->attributes() & JSC::Function) { - if (entry->function() == jsHistoryPrototypeFunctionBack) { - slot.setCustom(this, ReadOnly | DontDelete | DontEnum, nonCachingStaticBackFunctionGetter); - return true; - } else if (entry->function() == jsHistoryPrototypeFunctionForward) { - slot.setCustom(this, ReadOnly | DontDelete | DontEnum, nonCachingStaticForwardFunctionGetter); - return true; - } else if (entry->function() == jsHistoryPrototypeFunctionGo) { - slot.setCustom(this, ReadOnly | DontDelete | DontEnum, nonCachingStaticGoFunctionGetter); - return true; - } - } - } else { - // Allow access to toString() cross-domain, but always Object.toString. - if (propertyName == exec->propertyNames().toString) { - slot.setCustom(this, ReadOnly | DontDelete | DontEnum, objectToStringFunctionGetter); - return true; - } - } - - printErrorMessageForFrame(impl().frame(), message); - slot.setUndefined(); - return true; -} - -bool JSHistory::putDelegate(ExecState* exec, PropertyName, JSValue, PutPropertySlot&) -{ - if (!shouldAllowAccessToFrame(exec, impl().frame())) - return true; - return false; -} - -bool JSHistory::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) -{ - JSHistory* thisObject = jsCast<JSHistory*>(cell); - if (!shouldAllowAccessToFrame(exec, thisObject->impl().frame())) - return false; - return Base::deleteProperty(thisObject, exec, propertyName); -} - -bool JSHistory::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName) -{ - JSHistory* thisObject = jsCast<JSHistory*>(cell); - if (!shouldAllowAccessToFrame(exec, thisObject->impl().frame())) - return false; - return Base::deletePropertyByIndex(thisObject, exec, propertyName); -} - -void JSHistory::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) -{ - JSHistory* thisObject = jsCast<JSHistory*>(object); - if (!shouldAllowAccessToFrame(exec, thisObject->impl().frame())) - return; - Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode); -} - -JSValue JSHistory::state(ExecState *exec) const -{ - History& history = impl(); + History& history = wrapped(); JSValue cachedValue = m_state.get(); if (!cachedValue.isEmpty() && !history.stateChanged()) return cachedValue; RefPtr<SerializedScriptValue> serialized = history.state(); - JSValue result = serialized ? serialized->deserialize(exec, globalObject(), 0) : jsNull(); - const_cast<JSHistory*>(this)->m_state.set(exec->vm(), this, result); + JSValue result = serialized ? serialized->deserialize(state, globalObject()) : jsNull(); + m_state.set(state.vm(), this, result); return result; } -JSValue JSHistory::pushState(ExecState* exec) +JSValue JSHistory::pushState(ExecState& state) { - if (!shouldAllowAccessToFrame(exec, impl().frame())) - return jsUndefined(); + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto argCount = state.argumentCount(); + if (UNLIKELY(argCount < 2)) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); - RefPtr<SerializedScriptValue> historyState = SerializedScriptValue::create(exec, exec->argument(0), 0, 0); - if (exec->hadException()) - return jsUndefined(); + auto historyState = SerializedScriptValue::create(state, state.uncheckedArgument(0)); + RETURN_IF_EXCEPTION(scope, JSValue()); + + // FIXME: title should not be nullable. + String title = convert<IDLNullable<IDLDOMString>>(state, state.uncheckedArgument(1)); + RETURN_IF_EXCEPTION(scope, JSValue()); - String title = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(1)); - if (exec->hadException()) - return jsUndefined(); - String url; - if (exec->argumentCount() > 2) { - url = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(2)); - if (exec->hadException()) - return jsUndefined(); + if (argCount > 2) { + url = convert<IDLNullable<IDLUSVString>>(state, state.uncheckedArgument(2)); + RETURN_IF_EXCEPTION(scope, JSValue()); } - ExceptionCode ec = 0; - impl().stateObjectAdded(historyState.release(), title, url, History::StateObjectType::Push, ec); - setDOMException(exec, ec); + propagateException(state, scope, wrapped().stateObjectAdded(WTFMove(historyState), title, url, History::StateObjectType::Push)); m_state.clear(); return jsUndefined(); } -JSValue JSHistory::replaceState(ExecState* exec) +JSValue JSHistory::replaceState(ExecState& state) { - if (!shouldAllowAccessToFrame(exec, impl().frame())) - return jsUndefined(); + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto argCount = state.argumentCount(); + if (UNLIKELY(argCount < 2)) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + + auto historyState = SerializedScriptValue::create(state, state.uncheckedArgument(0)); + RETURN_IF_EXCEPTION(scope, JSValue()); - RefPtr<SerializedScriptValue> historyState = SerializedScriptValue::create(exec, exec->argument(0), 0, 0); - if (exec->hadException()) - return jsUndefined(); + // FIXME: title should not be nullable. + String title = convert<IDLNullable<IDLDOMString>>(state, state.uncheckedArgument(1)); + RETURN_IF_EXCEPTION(scope, JSValue()); - String title = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(1)); - if (exec->hadException()) - return jsUndefined(); - String url; - if (exec->argumentCount() > 2) { - url = valueToStringWithUndefinedOrNullCheck(exec, exec->argument(2)); - if (exec->hadException()) - return jsUndefined(); + if (argCount > 2) { + url = convert<IDLNullable<IDLUSVString>>(state, state.uncheckedArgument(2)); + RETURN_IF_EXCEPTION(scope, JSValue()); } - ExceptionCode ec = 0; - impl().stateObjectAdded(historyState.release(), title, url, History::StateObjectType::Replace, ec); - setDOMException(exec, ec); + propagateException(state, scope, wrapped().stateObjectAdded(WTFMove(historyState), title, url, History::StateObjectType::Replace)); m_state.clear(); diff --git a/Source/WebCore/bindings/js/JSIDBAnyCustom.cpp b/Source/WebCore/bindings/js/JSIDBAnyCustom.cpp deleted file mode 100644 index 5649c85ca..000000000 --- a/Source/WebCore/bindings/js/JSIDBAnyCustom.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#if ENABLE(INDEXED_DATABASE) - -#include "JSIDBAny.h" - -#include "IDBAny.h" -#include "IDBCursor.h" -#include "IDBCursorWithValue.h" -#include "IDBDatabase.h" -#include "IDBFactory.h" -#include "IDBIndex.h" -#include "IDBObjectStore.h" -#include "JSDOMStringList.h" -#include "JSIDBCursor.h" -#include "JSIDBCursorWithValue.h" -#include "JSIDBDatabase.h" -#include "JSIDBFactory.h" -#include "JSIDBIndex.h" -#include "JSIDBObjectStore.h" -#include "JSIDBTransaction.h" -#include "SerializedScriptValue.h" - -using namespace JSC; - -namespace WebCore { - -static JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, const IDBKeyPath& value) -{ - switch (value.type()) { - case IDBKeyPath::NullType: - return jsNull(); - case IDBKeyPath::StringType: - return jsStringWithCache(exec, value.string()); - case IDBKeyPath::ArrayType: - RefPtr<DOMStringList> keyPaths = DOMStringList::create(); - for (Vector<String>::const_iterator it = value.array().begin(); it != value.array().end(); ++it) - keyPaths->append(*it); - return toJS(exec, globalObject, keyPaths.release()); - } - - ASSERT_NOT_REACHED(); - return jsUndefined(); -} - -JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, IDBAny* idbAny) -{ - if (!idbAny) - return jsNull(); - - switch (idbAny->type()) { - case IDBAny::UndefinedType: - return jsUndefined(); - case IDBAny::NullType: - return jsNull(); - case IDBAny::DOMStringListType: - return toJS(exec, globalObject, idbAny->domStringList()); - case IDBAny::IDBCursorType: - return toJS(exec, globalObject, idbAny->idbCursor()); - case IDBAny::IDBCursorWithValueType: - return wrap<JSIDBCursorWithValue>(exec, globalObject, idbAny->idbCursorWithValue().get()); - case IDBAny::IDBDatabaseType: - return toJS(exec, globalObject, idbAny->idbDatabase()); - case IDBAny::IDBFactoryType: - return toJS(exec, globalObject, idbAny->idbFactory()); - case IDBAny::IDBIndexType: - return toJS(exec, globalObject, idbAny->idbIndex()); - case IDBAny::IDBObjectStoreType: - return toJS(exec, globalObject, idbAny->idbObjectStore()); - case IDBAny::IDBTransactionType: - return toJS(exec, globalObject, idbAny->idbTransaction()); - case IDBAny::ScriptValueType: - return idbAny->scriptValue().jsValue(); - case IDBAny::StringType: - return jsStringWithCache(exec, idbAny->string()); - case IDBAny::IntegerType: - return jsNumber(idbAny->integer()); - case IDBAny::KeyPathType: - return toJS(exec, globalObject, idbAny->keyPath()); - } - - ASSERT_NOT_REACHED(); - return jsUndefined(); -} - -} // namespace WebCore - -#endif // ENABLE(INDEXED_DATABASE) diff --git a/Source/WebCore/bindings/js/JSIDBCursorCustom.cpp b/Source/WebCore/bindings/js/JSIDBCursorCustom.cpp new file mode 100644 index 000000000..c74cb90da --- /dev/null +++ b/Source/WebCore/bindings/js/JSIDBCursorCustom.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2016 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 "JSIDBCursor.h" + +#if ENABLE(INDEXED_DATABASE) + +#include "JSDOMBinding.h" +#include "JSIDBCursorWithValue.h" + +using namespace JSC; + +namespace WebCore { + +void JSIDBCursor::visitAdditionalChildren(SlotVisitor& visitor) +{ + auto& cursor = wrapped(); + if (auto* request = cursor.request()) + visitor.addOpaqueRoot(request); +} + +JSValue toJSNewlyCreated(JSC::ExecState*, JSDOMGlobalObject* globalObject, Ref<IDBCursor>&& cursor) +{ + if (is<IDBCursorWithValue>(cursor)) + return createWrapper<IDBCursorWithValue>(globalObject, WTFMove(cursor)); + return createWrapper<IDBCursor>(globalObject, WTFMove(cursor)); +} + +JSValue toJS(JSC::ExecState* state, JSDOMGlobalObject* globalObject, IDBCursor& cursor) +{ + return wrap(state, globalObject, cursor); +} + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/Source/WebCore/bindings/js/JSRequestAnimationFrameCallbackCustom.cpp b/Source/WebCore/bindings/js/JSIDBCursorWithValueCustom.cpp index 91785a425..abbbc78fe 100644 --- a/Source/WebCore/bindings/js/JSRequestAnimationFrameCallbackCustom.cpp +++ b/Source/WebCore/bindings/js/JSIDBCursorWithValueCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,32 +24,22 @@ */ #include "config.h" +#include "JSIDBCursorWithValue.h" -#if ENABLE(REQUEST_ANIMATION_FRAME) +#if ENABLE(INDEXED_DATABASE) -#include "JSRequestAnimationFrameCallback.h" +#include "IDBCursorWithValue.h" +#include <heap/HeapInlines.h> using namespace JSC; namespace WebCore { -bool JSRequestAnimationFrameCallback::handleEvent(double highResNowMs) +void JSIDBCursorWithValue::visitAdditionalChildren(SlotVisitor& visitor) { - if (!canInvokeCallback()) - return true; - - Ref<JSRequestAnimationFrameCallback> protect(*this); - - JSLockHolder lock(m_data->globalObject()->vm()); - - MarkedArgumentBuffer args; - args.append(jsNumber(highResNowMs)); - - bool raisedException = false; - m_data->invokeCallback(args, &raisedException); - return !raisedException; + JSIDBCursor::visitAdditionalChildren(visitor); } -} +} // namespace WebCore -#endif +#endif // ENABLE(INDEXED_DATABASE) diff --git a/Source/WebCore/bindings/js/JSIDBDatabaseCustom.cpp b/Source/WebCore/bindings/js/JSIDBDatabaseCustom.cpp deleted file mode 100644 index 9eae7569c..000000000 --- a/Source/WebCore/bindings/js/JSIDBDatabaseCustom.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2012 Michael Pruett <michael@68k.org> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#if ENABLE(INDEXED_DATABASE) - -#include "JSIDBDatabase.h" - -#include "IDBBindingUtilities.h" -#include "IDBDatabase.h" -#include "IDBKeyPath.h" -#include "IDBObjectStore.h" -#include "JSIDBObjectStore.h" -#include <runtime/Error.h> -#include <runtime/JSString.h> - -using namespace JSC; - -namespace WebCore { - -JSValue JSIDBDatabase::createObjectStore(ExecState* exec) -{ - if (exec->argumentCount() < 1) - return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); - - String name = exec->argument(0).toString(exec)->value(exec); - if (exec->hadException()) - return jsUndefined(); - - JSValue optionsValue = exec->argument(1); - if (!optionsValue.isUndefinedOrNull() && !optionsValue.isObject()) - return throwTypeError(exec, "Not an object."); - - IDBKeyPath keyPath; - bool autoIncrement = false; - if (!optionsValue.isUndefinedOrNull()) { - JSValue keyPathValue = optionsValue.get(exec, Identifier(exec, "keyPath")); - if (exec->hadException()) - return jsUndefined(); - - if (!keyPathValue.isUndefinedOrNull()) { - keyPath = idbKeyPathFromValue(exec, keyPathValue); - if (exec->hadException()) - return jsUndefined(); - } - - autoIncrement = optionsValue.get(exec, Identifier(exec, "autoIncrement")).toBoolean(exec); - if (exec->hadException()) - return jsUndefined(); - } - - ExceptionCode ec = 0; - JSValue result = toJS(exec, globalObject(), impl().createObjectStore(name, keyPath, autoIncrement, ec).get()); - setDOMException(exec, ec); - return result; -} - -} - -#endif diff --git a/Source/WebCore/bindings/js/JSIDBIndexCustom.cpp b/Source/WebCore/bindings/js/JSIDBIndexCustom.cpp new file mode 100644 index 000000000..2710090f4 --- /dev/null +++ b/Source/WebCore/bindings/js/JSIDBIndexCustom.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016 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 "JSIDBIndex.h" + +#if ENABLE(INDEXED_DATABASE) + +#include "IDBIndex.h" +#include <heap/HeapInlines.h> + +using namespace JSC; + +namespace WebCore { + +void JSIDBIndex::visitAdditionalChildren(SlotVisitor& visitor) +{ + visitor.addOpaqueRoot(static_cast<IDBIndex&>(wrapped()).objectStoreAsOpaqueRoot()); +} + +} // namespace WebCore + +#endif // ENABLE(INDEXED_DATABASE) diff --git a/Source/WebCore/bindings/js/JSIDBObjectStoreCustom.cpp b/Source/WebCore/bindings/js/JSIDBObjectStoreCustom.cpp index 74fd354b2..3fe84a71f 100644 --- a/Source/WebCore/bindings/js/JSIDBObjectStoreCustom.cpp +++ b/Source/WebCore/bindings/js/JSIDBObjectStoreCustom.cpp @@ -29,56 +29,16 @@ #if ENABLE(INDEXED_DATABASE) +#include "JSDOMBinding.h" #include "JSIDBObjectStore.h" -#include "IDBBindingUtilities.h" -#include "IDBKeyPath.h" -#include "IDBObjectStore.h" -#include "JSIDBIndex.h" -#include <runtime/Error.h> -#include <runtime/JSString.h> - using namespace JSC; namespace WebCore { -JSValue JSIDBObjectStore::createIndex(ExecState* exec) +void JSIDBObjectStore::visitAdditionalChildren(SlotVisitor& visitor) { - ScriptExecutionContext* context = jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())->scriptExecutionContext(); - if (!context) - return exec->vm().throwException(exec, createReferenceError(exec, "IDBObjectStore script execution context is unavailable")); - - if (exec->argumentCount() < 2) - return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); - - String name = exec->argument(0).toString(exec)->value(exec); - if (exec->hadException()) - return jsUndefined(); - - IDBKeyPath keyPath = idbKeyPathFromValue(exec, exec->argument(1)); - if (exec->hadException()) - return jsUndefined(); - - JSValue optionsValue = exec->argument(2); - if (!optionsValue.isUndefinedOrNull() && !optionsValue.isObject()) - return throwTypeError(exec, "Not an object."); - - bool unique = false; - bool multiEntry = false; - if (!optionsValue.isUndefinedOrNull()) { - unique = optionsValue.get(exec, Identifier(exec, "unique")).toBoolean(exec); - if (exec->hadException()) - return jsUndefined(); - - multiEntry = optionsValue.get(exec, Identifier(exec, "multiEntry")).toBoolean(exec); - if (exec->hadException()) - return jsUndefined(); - } - - ExceptionCode ec = 0; - JSValue result = toJS(exec, globalObject(), impl().createIndex(context, name, keyPath, unique, multiEntry, ec).get()); - setDOMException(exec, ec); - return result; + static_cast<IDBObjectStore&>(wrapped()).visitReferencedIndexes(visitor); } } diff --git a/Source/WebCore/bindings/js/JSHTMLLinkElementCustom.cpp b/Source/WebCore/bindings/js/JSIDBTransactionCustom.cpp index d3a4b543f..0e6d383e8 100644 --- a/Source/WebCore/bindings/js/JSHTMLLinkElementCustom.cpp +++ b/Source/WebCore/bindings/js/JSIDBTransactionCustom.cpp @@ -1,6 +1,5 @@ /* - * Copyright (C) 2010 Apple Inc. All rights reserved. - * Copyright (C) 2011 Google Inc. All rights reserved. + * Copyright (C) 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,25 +24,21 @@ */ #include "config.h" -#include "JSHTMLLinkElement.h" +#include "JSIDBTransaction.h" + +#if ENABLE(INDEXED_DATABASE) -#include "HTMLLinkElement.h" #include "JSDOMBinding.h" -#include "JSDOMSettableTokenList.h" -#include <wtf/GetPtr.h> using namespace JSC; namespace WebCore { -JSValue JSHTMLLinkElement::sizes(ExecState* exec) const +void JSIDBTransaction::visitAdditionalChildren(SlotVisitor& visitor) { - return toJS(exec, globalObject(), impl().sizes()); + static_cast<IDBTransaction&>(wrapped()).visitReferencedObjectStores(visitor); } -void JSHTMLLinkElement::setSizes(ExecState* exec, JSValue value) -{ - impl().setSizes(valueToStringWithNullCheck(exec, value)); } -} // namespace WebCore +#endif diff --git a/Source/WebCore/bindings/js/JSImageConstructor.cpp b/Source/WebCore/bindings/js/JSImageConstructor.cpp deleted file mode 100644 index a86effd13..000000000 --- a/Source/WebCore/bindings/js/JSImageConstructor.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include "JSImageConstructor.h" - -#include "HTMLImageElement.h" -#include "HTMLNames.h" -#include "JSHTMLImageElement.h" -#include "JSNode.h" -#include <runtime/Error.h> - -using namespace JSC; - -namespace WebCore { - -STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSImageConstructor); - -const ClassInfo JSImageConstructor::s_info = { "ImageConstructor", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSImageConstructor) }; - -JSImageConstructor::JSImageConstructor(Structure* structure, JSDOMGlobalObject* globalObject) - : DOMConstructorWithDocument(structure, globalObject) -{ -} - -void JSImageConstructor::finishCreation(VM& vm, JSDOMGlobalObject* globalObject) -{ - Base::finishCreation(globalObject); - ASSERT(inherits(info())); - putDirect(vm, vm.propertyNames->prototype, JSHTMLImageElementPrototype::self(vm, globalObject), None); -} - -static EncodedJSValue JSC_HOST_CALL constructImage(ExecState* exec) -{ - JSImageConstructor* jsConstructor = jsCast<JSImageConstructor*>(exec->callee()); - Document* document = jsConstructor->document(); - if (!document) - return throwVMError(exec, createReferenceError(exec, "Image constructor associated document is unavailable")); - - // Calling toJS on the document causes the JS document wrapper to be - // added to the window object. This is done to ensure that JSDocument::visit - // will be called, which will cause the image element to be marked if necessary. - toJS(exec, jsConstructor->globalObject(), document); - int width; - int height; - int* optionalWidth = 0; - int* optionalHeight = 0; - if (exec->argumentCount() > 0) { - width = exec->argument(0).toInt32(exec); - optionalWidth = &width; - } - if (exec->argumentCount() > 1) { - height = exec->argument(1).toInt32(exec); - optionalHeight = &height; - } - - return JSValue::encode(asObject(toJS(exec, jsConstructor->globalObject(), - HTMLImageElement::createForJSConstructor(*document, optionalWidth, optionalHeight)))); -} - -ConstructType JSImageConstructor::getConstructData(JSCell*, ConstructData& constructData) -{ - constructData.native.function = constructImage; - return ConstructTypeHost; -} - -} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSImageConstructor.h b/Source/WebCore/bindings/js/JSImageConstructor.h deleted file mode 100644 index b923215b3..000000000 --- a/Source/WebCore/bindings/js/JSImageConstructor.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 1999 Harri Porten (porten@kde.org) - * Copyright (C) 2004, 2006, 2007, 2008 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef JSImageConstructor_h -#define JSImageConstructor_h - -#include "DOMConstructorWithDocument.h" -#include "JSDOMBinding.h" -#include "JSDocument.h" - -namespace WebCore { - - class JSImageConstructor : public DOMConstructorWithDocument { - public: - typedef DOMConstructorWithDocument Base; - - static JSImageConstructor* create(JSC::VM& vm, JSC::Structure* structure, JSDOMGlobalObject* globalObject) - { - JSImageConstructor* constructor = new (NotNull, JSC::allocateCell<JSImageConstructor>(vm.heap)) JSImageConstructor(structure, globalObject); - constructor->finishCreation(vm, globalObject); - return constructor; - } - - static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) - { - return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); - } - - DECLARE_INFO; - - private: - JSImageConstructor(JSC::Structure*, JSDOMGlobalObject*); - void finishCreation(JSC::VM&, JSDOMGlobalObject*); - static JSC::ConstructType getConstructData(JSC::JSCell*, JSC::ConstructData&); - }; - -} // namespace WebCore - -#endif // JSImageConstructor_h diff --git a/Source/WebCore/bindings/js/JSImageDataCustom.cpp b/Source/WebCore/bindings/js/JSImageDataCustom.cpp index 1576d5e58..518b5ef13 100644 --- a/Source/WebCore/bindings/js/JSImageDataCustom.cpp +++ b/Source/WebCore/bindings/js/JSImageDataCustom.cpp @@ -26,7 +26,10 @@ #include "config.h" #include "JSImageData.h" -#include "ImageData.h" +#include "JSDOMConvertBufferSource.h" +#include "JSDOMWrapperCache.h" +#include <heap/HeapInlines.h> +#include <runtime/IdentifierInlines.h> #include <wtf/StdLibExtras.h> #include <wtf/text/WTFString.h> @@ -34,21 +37,22 @@ using namespace JSC; namespace WebCore { -JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, ImageData* imageData) +JSValue toJSNewlyCreated(ExecState* state, JSDOMGlobalObject* globalObject, Ref<ImageData>&& imageData) { - if (!imageData) - return jsNull(); - - JSObject* wrapper = getCachedWrapper(currentWorld(exec), imageData); - if (wrapper) - return wrapper; - - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, ImageData, imageData); - Identifier dataName(exec, "data"); - wrapper->putDirect(exec->vm(), dataName, toJS(exec, globalObject, imageData->data()), DontDelete | ReadOnly); - exec->heap()->reportExtraMemoryCost(imageData->data()->length()); + auto* data = imageData->data(); + auto* wrapper = createWrapper<ImageData>(globalObject, WTFMove(imageData)); + Identifier dataName = Identifier::fromString(state, "data"); + wrapper->putDirect(state->vm(), dataName, toJS(state, globalObject, data), DontDelete | ReadOnly); + // FIXME: Adopt reportExtraMemoryVisited, and switch to reportExtraMemoryAllocated. + // https://bugs.webkit.org/show_bug.cgi?id=142595 + state->heap()->deprecatedReportExtraMemory(data->length()); return wrapper; } +JSValue toJS(ExecState* state, JSDOMGlobalObject* globalObject, ImageData& imageData) +{ + return wrap(state, globalObject, imageData); +} + } diff --git a/Source/WebCore/bindings/js/JSInspectorFrontendHostCustom.cpp b/Source/WebCore/bindings/js/JSInspectorFrontendHostCustom.cpp index 2175181d1..447dde627 100644 --- a/Source/WebCore/bindings/js/JSInspectorFrontendHostCustom.cpp +++ b/Source/WebCore/bindings/js/JSInspectorFrontendHostCustom.cpp @@ -31,90 +31,51 @@ */ #include "config.h" - -#if ENABLE(INSPECTOR) - #include "JSInspectorFrontendHost.h" #include "ContextMenuItem.h" #include "InspectorController.h" #include "InspectorFrontendHost.h" +#include "JSDOMBinding.h" #include "JSEvent.h" #include "MouseEvent.h" #include <runtime/JSArray.h> #include <runtime/JSLock.h> #include <runtime/JSObject.h> -#include <wtf/Vector.h> #include <wtf/text/WTFString.h> using namespace JSC; namespace WebCore { -JSValue JSInspectorFrontendHost::platform(ExecState* execState) -{ -#if PLATFORM(MAC) - DEFINE_STATIC_LOCAL(const String, platform, (ASCIILiteral("mac"))); -#elif OS(WINDOWS) - DEFINE_STATIC_LOCAL(const String, platform, (ASCIILiteral("windows"))); -#elif OS(LINUX) - DEFINE_STATIC_LOCAL(const String, platform, (ASCIILiteral("linux"))); -#elif OS(FREEBSD) - DEFINE_STATIC_LOCAL(const String, platform, (ASCIILiteral("freebsd"))); -#elif OS(OPENBSD) - DEFINE_STATIC_LOCAL(const String, platform, (ASCIILiteral("openbsd"))); -#elif OS(SOLARIS) - DEFINE_STATIC_LOCAL(const String, platform, (ASCIILiteral("solaris"))); -#else - DEFINE_STATIC_LOCAL(const String, platform, (ASCIILiteral("unknown"))); -#endif - return jsStringWithCache(execState, platform); -} - -JSValue JSInspectorFrontendHost::port(ExecState* execState) -{ -#if PLATFORM(GTK) - DEFINE_STATIC_LOCAL(const String, port, (ASCIILiteral("gtk"))); -#elif PLATFORM(EFL) - DEFINE_STATIC_LOCAL(const String, port, (ASCIILiteral("efl"))); -#else - DEFINE_STATIC_LOCAL(const String, port, (ASCIILiteral("unknown"))); -#endif - return jsStringWithCache(execState, port); -} - #if ENABLE(CONTEXT_MENUS) static void populateContextMenuItems(ExecState* exec, JSArray* array, ContextMenu& menu) { + VM& vm = exec->vm(); for (size_t i = 0; i < array->length(); ++i) { JSObject* item = asObject(array->getIndex(exec, i)); - JSValue label = item->get(exec, Identifier(exec, "label")); - JSValue type = item->get(exec, Identifier(exec, "type")); - JSValue id = item->get(exec, Identifier(exec, "id")); - JSValue enabled = item->get(exec, Identifier(exec, "enabled")); - JSValue checked = item->get(exec, Identifier(exec, "checked")); - JSValue subItems = item->get(exec, Identifier(exec, "subItems")); + JSValue label = item->get(exec, Identifier::fromString(exec, "label")); + JSValue type = item->get(exec, Identifier::fromString(exec, "type")); + JSValue id = item->get(exec, Identifier::fromString(exec, "id")); + JSValue enabled = item->get(exec, Identifier::fromString(exec, "enabled")); + JSValue checked = item->get(exec, Identifier::fromString(exec, "checked")); + JSValue subItems = item->get(exec, Identifier::fromString(exec, "subItems")); if (!type.isString()) continue; - String typeString = type.toString(exec)->value(exec); + String typeString = asString(type)->value(exec); if (typeString == "separator") { - ContextMenuItem item(SeparatorType, - ContextMenuItemCustomTagNoAction, - String()); + ContextMenuItem item(SeparatorType, ContextMenuItemTagNoAction, String()); menu.appendItem(item); - } else if (typeString == "subMenu" && subItems.inherits(JSArray::info())) { + } else if (typeString == "subMenu" && subItems.inherits(vm, JSArray::info())) { ContextMenu subMenu; JSArray* subItemsArray = asArray(subItems); populateContextMenuItems(exec, subItemsArray, subMenu); - ContextMenuItem item(SubmenuType, - ContextMenuItemCustomTagNoAction, - label.toString(exec)->value(exec), - &subMenu); + ContextMenuItem item(SubmenuType, ContextMenuItemTagNoAction, label.toWTFString(exec), &subMenu); menu.appendItem(item); } else { ContextMenuAction typedId = static_cast<ContextMenuAction>(ContextMenuItemBaseCustomTag + id.toInt32(exec)); - ContextMenuItem menuItem((typeString == "checkbox" ? CheckableActionType : ActionType), typedId, label.toString(exec)->value(exec)); + ContextMenuItem menuItem((typeString == "checkbox" ? CheckableActionType : ActionType), typedId, label.toWTFString(exec)); if (!enabled.isUndefined()) menuItem.setEnabled(enabled.toBoolean(exec)); if (!checked.isUndefined()) @@ -125,44 +86,23 @@ static void populateContextMenuItems(ExecState* exec, JSArray* array, ContextMen } #endif -JSValue JSInspectorFrontendHost::showContextMenu(ExecState* exec) +JSValue JSInspectorFrontendHost::showContextMenu(ExecState& state) { #if ENABLE(CONTEXT_MENUS) - if (exec->argumentCount() < 2) + if (state.argumentCount() < 2) return jsUndefined(); - Event* event = toEvent(exec->argument(0)); + VM& vm = state.vm(); + Event* event = JSEvent::toWrapped(vm, state.argument(0)); - JSArray* array = asArray(exec->argument(1)); + JSArray* array = asArray(state.argument(1)); ContextMenu menu; - populateContextMenuItems(exec, array, menu); + populateContextMenuItems(&state, array, menu); -#if !USE(CROSS_PLATFORM_CONTEXT_MENUS) - Vector<ContextMenuItem> items = contextMenuItemVector(menu.platformDescription()); -#else - Vector<ContextMenuItem> items = menu.items(); -#endif - impl().showContextMenu(event, items); + wrapped().showContextMenu(event, menu.items()); #else - UNUSED_PARAM(exec); + UNUSED_PARAM(state); #endif return jsUndefined(); } -JSValue JSInspectorFrontendHost::recordActionTaken(ExecState*) -{ - return jsUndefined(); -} - -JSValue JSInspectorFrontendHost::recordPanelShown(ExecState*) -{ - return jsUndefined(); -} - -JSValue JSInspectorFrontendHost::recordSettingChanged(ExecState*) -{ - return jsUndefined(); -} - } // namespace WebCore - -#endif // ENABLE(INSPECTOR) diff --git a/Source/WebCore/bindings/js/JSLazyEventListener.cpp b/Source/WebCore/bindings/js/JSLazyEventListener.cpp index 01aee7fba..d270b2696 100644 --- a/Source/WebCore/bindings/js/JSLazyEventListener.cpp +++ b/Source/WebCore/bindings/js/JSLazyEventListener.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2013 Apple Inc. All Rights Reserved. + * Copyright (C) 2003-2016 Apple Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -20,11 +20,13 @@ #include "config.h" #include "JSLazyEventListener.h" +#include "CachedScriptFetcher.h" #include "ContentSecurityPolicy.h" #include "Frame.h" #include "JSNode.h" #include "ScriptController.h" #include <runtime/FunctionConstructor.h> +#include <runtime/IdentifierInlines.h> #include <wtf/NeverDestroyed.h> #include <wtf/RefCountedLeakCounter.h> #include <wtf/StdLibExtras.h> @@ -35,13 +37,13 @@ namespace WebCore { DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, eventListenerCounter, ("JSLazyEventListener")); -JSLazyEventListener::JSLazyEventListener(const String& functionName, const String& eventParameterName, const String& code, ContainerNode* node, const String& sourceURL, const TextPosition& position, JSObject* wrapper, DOMWrapperWorld& isolatedWorld) +JSLazyEventListener::JSLazyEventListener(const String& functionName, const String& eventParameterName, const String& code, ContainerNode* node, const String& sourceURL, const TextPosition& sourcePosition, JSObject* wrapper, DOMWrapperWorld& isolatedWorld) : JSEventListener(0, wrapper, true, isolatedWorld) , m_functionName(functionName) , m_eventParameterName(eventParameterName) , m_code(code) , m_sourceURL(sourceURL) - , m_position(position) + , m_sourcePosition(sourcePosition) , m_originalNode(node) { // We don't retain the original node because we assume it @@ -52,8 +54,8 @@ JSLazyEventListener::JSLazyEventListener(const String& functionName, const Strin // A JSLazyEventListener can be created with a line number of zero when it is created with // a setAttribute call from JavaScript, so make the line number 1 in that case. - if (m_position == TextPosition::belowRangePosition()) - m_position = TextPosition::minimumPosition(); + if (m_sourcePosition == TextPosition::belowRangePosition()) + m_sourcePosition = TextPosition(); ASSERT(m_eventParameterName == "evt" || m_eventParameterName == "event"); @@ -71,57 +73,66 @@ JSLazyEventListener::~JSLazyEventListener() JSObject* JSLazyEventListener::initializeJSFunction(ScriptExecutionContext* executionContext) const { - ASSERT(executionContext); - ASSERT(executionContext->isDocument()); + ASSERT(is<Document>(executionContext)); if (!executionContext) - return 0; + return nullptr; ASSERT(!m_code.isNull()); ASSERT(!m_eventParameterName.isNull()); if (m_code.isNull() || m_eventParameterName.isNull()) - return 0; + return nullptr; - Document* document = toDocument(executionContext); + Document& document = downcast<Document>(*executionContext); - if (!document->frame()) - return 0; + if (!document.frame()) + return nullptr; - if (!document->contentSecurityPolicy()->allowInlineEventHandlers(m_sourceURL, m_position.m_line)) - return 0; + if (!document.contentSecurityPolicy()->allowInlineEventHandlers(m_sourceURL, m_sourcePosition.m_line)) + return nullptr; - ScriptController& script = document->frame()->script(); + ScriptController& script = document.frame()->script(); if (!script.canExecuteScripts(AboutToExecuteScript) || script.isPaused()) - return 0; + return nullptr; JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(executionContext, isolatedWorld()); if (!globalObject) - return 0; + return nullptr; + VM& vm = globalObject->vm(); + JSLockHolder lock(vm); + auto scope = DECLARE_CATCH_SCOPE(vm); ExecState* exec = globalObject->globalExec(); MarkedArgumentBuffer args; args.append(jsNontrivialString(exec, m_eventParameterName)); args.append(jsStringWithCache(exec, m_code)); - JSObject* jsFunction = constructFunctionSkippingEvalEnabledCheck(exec, exec->lexicalGlobalObject(), args, Identifier(exec, m_functionName), m_sourceURL, m_position); // FIXME: is globalExec ok? - if (exec->hadException()) { + // We want all errors to refer back to the line on which our attribute was + // declared, regardless of any newlines in our JavaScript source text. + int overrideLineNumber = m_sourcePosition.m_line.oneBasedInt(); + + JSObject* jsFunction = constructFunctionSkippingEvalEnabledCheck( + exec, exec->lexicalGlobalObject(), args, Identifier::fromString(exec, m_functionName), + SourceOrigin { m_sourceURL, CachedScriptFetcher::create(document.charset()) }, m_sourceURL, m_sourcePosition, overrideLineNumber); + + if (UNLIKELY(scope.exception())) { reportCurrentException(exec); - exec->clearException(); - return 0; + scope.clearException(); + return nullptr; } JSFunction* listenerAsFunction = jsCast<JSFunction*>(jsFunction); + if (m_originalNode) { if (!wrapper()) { // Ensure that 'node' has a JavaScript wrapper to mark the event listener we're creating. - JSLockHolder lock(exec); // FIXME: Should pass the global object associated with the node - setWrapper(exec->vm(), asObject(toJS(exec, globalObject, m_originalNode))); + setWrapper(vm, asObject(toJS(exec, globalObject, *m_originalNode))); } // Add the event's home element to the scope // (and the document, and the form - see JSHTMLElement::eventHandlerScope) - listenerAsFunction->setScope(exec->vm(), jsCast<JSNode*>(wrapper())->pushEventHandlerScope(exec, listenerAsFunction->scope())); + listenerAsFunction->setScope(vm, jsCast<JSNode*>(wrapper())->pushEventHandlerScope(exec, listenerAsFunction->scope())); } return jsFunction; } @@ -133,40 +144,53 @@ static const String& eventParameterName(bool isSVGEvent) return isSVGEvent ? evtString : eventString; } -PassRefPtr<JSLazyEventListener> JSLazyEventListener::createForNode(ContainerNode& node, const QualifiedName& attributeName, const AtomicString& attributeValue) +struct JSLazyEventListener::CreationArguments { + const QualifiedName& attributeName; + const AtomicString& attributeValue; + Document& document; + ContainerNode* node; + JSC::JSObject* wrapper; + bool shouldUseSVGEventName; +}; + +RefPtr<JSLazyEventListener> JSLazyEventListener::create(const CreationArguments& arguments) { - if (attributeValue.isNull()) + if (arguments.attributeValue.isNull()) return nullptr; - TextPosition position = TextPosition::minimumPosition(); - String sourceURL; - // FIXME: We should be able to provide source information for frameless documents too (e.g. for importing nodes from XMLHttpRequest.responseXML). - if (Frame* frame = node.document().frame()) { + TextPosition position; + String sourceURL; + if (Frame* frame = arguments.document.frame()) { if (!frame->script().canExecuteScripts(AboutToExecuteScript)) return nullptr; - position = frame->script().eventHandlerPosition(); - sourceURL = node.document().url().string(); + sourceURL = arguments.document.url().string(); } - return adoptRef(new JSLazyEventListener(attributeName.localName().string(), - eventParameterName(node.isSVGElement()), attributeValue, - &node, sourceURL, position, nullptr, mainThreadNormalWorld())); + return adoptRef(*new JSLazyEventListener(arguments.attributeName.localName().string(), + eventParameterName(arguments.shouldUseSVGEventName), arguments.attributeValue, + arguments.node, sourceURL, position, arguments.wrapper, mainThreadNormalWorld())); } -PassRefPtr<JSLazyEventListener> JSLazyEventListener::createForDOMWindow(Frame& frame, const QualifiedName& attributeName, const AtomicString& attributeValue) +RefPtr<JSLazyEventListener> JSLazyEventListener::create(Element& element, const QualifiedName& attributeName, const AtomicString& attributeValue) { - if (attributeValue.isNull()) - return nullptr; + return create({ attributeName, attributeValue, element.document(), &element, nullptr, element.isSVGElement() }); +} - if (!frame.script().canExecuteScripts(AboutToExecuteScript)) - return nullptr; +RefPtr<JSLazyEventListener> JSLazyEventListener::create(Document& document, const QualifiedName& attributeName, const AtomicString& attributeValue) +{ + // FIXME: This always passes false for "shouldUseSVGEventName". Is that correct for events dispatched to SVG documents? + // This has been this way for a long time, but became more obvious when refactoring to separate the Element and Document code paths. + return create({ attributeName, attributeValue, document, &document, nullptr, false }); +} - return adoptRef(new JSLazyEventListener(attributeName.localName().string(), - eventParameterName(frame.document()->isSVGDocument()), attributeValue, - nullptr, frame.document()->url().string(), frame.script().eventHandlerPosition(), - toJSDOMWindow(&frame, mainThreadNormalWorld()), mainThreadNormalWorld())); +RefPtr<JSLazyEventListener> JSLazyEventListener::create(DOMWindow& window, const QualifiedName& attributeName, const AtomicString& attributeValue) +{ + ASSERT(window.document()); + auto& document = *window.document(); + ASSERT(document.frame()); + return create({ attributeName, attributeValue, document, nullptr, toJSDOMWindow(document.frame(), mainThreadNormalWorld()), document.isSVGDocument() }); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSLazyEventListener.h b/Source/WebCore/bindings/js/JSLazyEventListener.h index 31900178c..9c2849ebb 100644 --- a/Source/WebCore/bindings/js/JSLazyEventListener.h +++ b/Source/WebCore/bindings/js/JSLazyEventListener.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2003, 2008, 2009, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2003-2016 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,42 +17,44 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef JSLazyEventListener_h -#define JSLazyEventListener_h +#pragma once #include "JSEventListener.h" -#include <wtf/text/TextPosition.h> -#include <wtf/text/WTFString.h> namespace WebCore { - class ContainerNode; - class Frame; - class QualifiedName; +class ContainerNode; +class DOMWindow; +class Document; +class Element; +class QualifiedName; - class JSLazyEventListener final : public JSEventListener { - public: - static PassRefPtr<JSLazyEventListener> createForNode(ContainerNode&, const QualifiedName& attributeName, const AtomicString& attributeValue); - static PassRefPtr<JSLazyEventListener> createForDOMWindow(Frame&, const QualifiedName& attributeName, const AtomicString& attributeValue); +class JSLazyEventListener final : public JSEventListener { +public: + static RefPtr<JSLazyEventListener> create(Element&, const QualifiedName& attributeName, const AtomicString& attributeValue); + static RefPtr<JSLazyEventListener> create(Document&, const QualifiedName& attributeName, const AtomicString& attributeValue); + static RefPtr<JSLazyEventListener> create(DOMWindow&, const QualifiedName& attributeName, const AtomicString& attributeValue); - virtual ~JSLazyEventListener(); + virtual ~JSLazyEventListener(); - private: - JSLazyEventListener(const String& functionName, const String& eventParameterName, const String& code, ContainerNode*, const String& sourceURL, const TextPosition&, JSC::JSObject* wrapper, DOMWrapperWorld& isolatedWorld); + String sourceURL() const final { return m_sourceURL; } + TextPosition sourcePosition() const final { return m_sourcePosition; } - virtual JSC::JSObject* initializeJSFunction(ScriptExecutionContext*) const override; - virtual bool wasCreatedFromMarkup() const override { return true; } +private: + struct CreationArguments; + static RefPtr<JSLazyEventListener> create(const CreationArguments&); - static void create() = delete; + JSLazyEventListener(const String& functionName, const String& eventParameterName, const String& code, ContainerNode*, const String& sourceURL, const TextPosition&, JSC::JSObject* wrapper, DOMWrapperWorld& isolatedWorld); - mutable String m_functionName; - mutable String m_eventParameterName; - mutable String m_code; - mutable String m_sourceURL; - TextPosition m_position; - ContainerNode* m_originalNode; - }; + JSC::JSObject* initializeJSFunction(ScriptExecutionContext*) const override; + bool wasCreatedFromMarkup() const override { return true; } -} // namespace WebCore + String m_functionName; + String m_eventParameterName; + String m_code; + String m_sourceURL; + TextPosition m_sourcePosition; + ContainerNode* m_originalNode; +}; -#endif // JSLazyEventListener_h +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSLocationCustom.cpp b/Source/WebCore/bindings/js/JSLocationCustom.cpp index c99f904d8..57eb752da 100644 --- a/Source/WebCore/bindings/js/JSLocationCustom.cpp +++ b/Source/WebCore/bindings/js/JSLocationCustom.cpp @@ -23,31 +23,23 @@ #include "config.h" #include "JSLocation.h" -#include "Location.h" +#include "JSDOMBinding.h" +#include "JSDOMBindingSecurity.h" +#include "JSDOMExceptionHandling.h" +#include "RuntimeApplicationChecks.h" #include <runtime/JSFunction.h> +#include <runtime/Lookup.h> using namespace JSC; namespace WebCore { -static EncodedJSValue nonCachingStaticReplaceFunctionGetter(ExecState* exec, EncodedJSValue, EncodedJSValue, PropertyName propertyName) +bool JSLocation::getOwnPropertySlotDelegate(ExecState* state, PropertyName propertyName, PropertySlot& slot) { - return JSValue::encode(JSFunction::create(exec->vm(), exec->lexicalGlobalObject(), 1, propertyName.publicName(), jsLocationPrototypeFunctionReplace)); -} - -static EncodedJSValue nonCachingStaticReloadFunctionGetter(ExecState* exec, EncodedJSValue, EncodedJSValue, PropertyName propertyName) -{ - return JSValue::encode(JSFunction::create(exec->vm(), exec->lexicalGlobalObject(), 0, propertyName.publicName(), jsLocationPrototypeFunctionReload)); -} + VM& vm = state->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); -static EncodedJSValue nonCachingStaticAssignFunctionGetter(ExecState* exec, EncodedJSValue, EncodedJSValue, PropertyName propertyName) -{ - return JSValue::encode(JSFunction::create(exec->vm(), exec->lexicalGlobalObject(), 1, propertyName.publicName(), jsLocationPrototypeFunctionAssign)); -} - -bool JSLocation::getOwnPropertySlotDelegate(ExecState* exec, PropertyName propertyName, PropertySlot& slot) -{ - Frame* frame = impl().frame(); + Frame* frame = wrapped().frame(); if (!frame) { slot.setUndefined(); return true; @@ -59,56 +51,55 @@ bool JSLocation::getOwnPropertySlotDelegate(ExecState* exec, PropertyName proper // Our custom code is only needed to implement the Window cross-domain scheme, so if access is // allowed, return false so the normal lookup will take place. String message; - if (shouldAllowAccessToFrame(exec, frame, message)) + if (BindingSecurity::shouldAllowAccessToFrame(*state, *frame, message)) return false; - // Check for the few functions that we allow, even when called cross-domain. - // Make these read-only / non-configurable to prevent writes via defineProperty. - const HashEntry* entry = JSLocationPrototype::info()->propHashTable(exec)->entry(exec, propertyName); - if (entry && (entry->attributes() & JSC::Function)) { - if (entry->function() == jsLocationPrototypeFunctionReplace) { - slot.setCustom(this, ReadOnly | DontDelete | DontEnum, nonCachingStaticReplaceFunctionGetter); - return true; - } else if (entry->function() == jsLocationPrototypeFunctionReload) { - slot.setCustom(this, ReadOnly | DontDelete | DontEnum, nonCachingStaticReloadFunctionGetter); - return true; - } else if (entry->function() == jsLocationPrototypeFunctionAssign) { - slot.setCustom(this, ReadOnly | DontDelete | DontEnum, nonCachingStaticAssignFunctionGetter); - return true; - } + // https://html.spec.whatwg.org/#crossorigingetownpropertyhelper-(-o,-p-) + if (propertyName == state->propertyNames().toStringTagSymbol || propertyName == state->propertyNames().hasInstanceSymbol || propertyName == state->propertyNames().isConcatSpreadableSymbol) { + slot.setValue(this, ReadOnly | DontEnum, jsUndefined()); + return true; } - // FIXME: Other implementers of the Window cross-domain scheme (Window, History) allow toString, - // but for now we have decided not to, partly because it seems silly to return "[Object Location]" in - // such cases when normally the string form of Location would be the URL. + // We only allow access to Location.replace() cross origin. + if (propertyName == state->propertyNames().replace) { + slot.setCustom(this, ReadOnly | DontEnum, nonCachingStaticFunctionGetter<jsLocationInstanceFunctionReplace, 1>); + return true; + } - printErrorMessageForFrame(frame, message); + // Getting location.href cross origin needs to throw. However, getOwnPropertyDescriptor() needs to return + // a descriptor that has a setter but no getter. + if (slot.internalMethodType() == PropertySlot::InternalMethodType::GetOwnProperty && propertyName == state->propertyNames().href) { + auto* entry = JSLocation::info()->staticPropHashTable->entry(propertyName); + CustomGetterSetter* customGetterSetter = CustomGetterSetter::create(vm, nullptr, entry->propertyPutter()); + slot.setCustomGetterSetter(this, DontEnum | CustomAccessor, customGetterSetter); + return true; + } + + throwSecurityError(*state, scope, message); slot.setUndefined(); return true; } -bool JSLocation::putDelegate(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) +bool JSLocation::putDelegate(ExecState* state, PropertyName propertyName, JSValue, PutPropertySlot&, bool& putResult) { - Frame* frame = impl().frame(); + putResult = false; + + Frame* frame = wrapped().frame(); if (!frame) return true; - if (propertyName == exec->propertyNames().toString || propertyName == exec->propertyNames().valueOf) + // Silently block access to toString and valueOf. + if (propertyName == state->propertyNames().toString || propertyName == state->propertyNames().valueOf) return true; - bool sameDomainAccess = shouldAllowAccessToFrame(exec, frame); - - const HashEntry* entry = JSLocation::info()->propHashTable(exec)->entry(exec, propertyName); - if (!entry) { - if (sameDomainAccess) - JSObject::put(this, exec, propertyName, value, slot); - return true; - } + // Always allow assigning to the whole location. + // However, alllowing assigning of pieces might inadvertently disclose parts of the original location. + // So fall through to the access check for those. + if (propertyName == state->propertyNames().href) + return false; - // Cross-domain access to the location is allowed when assigning the whole location, - // but not when assigning the individual pieces, since that might inadvertently - // disclose other parts of the original location. - if (entry->propertyPutter() != setJSLocationHref && !sameDomainAccess) + // Block access and throw if there is a security error. + if (!BindingSecurity::shouldAllowAccessToFrame(state, frame, ThrowSecurityError)) return true; return false; @@ -118,7 +109,7 @@ bool JSLocation::deleteProperty(JSCell* cell, ExecState* exec, PropertyName prop { JSLocation* thisObject = jsCast<JSLocation*>(cell); // Only allow deleting by frames in the same origin. - if (!shouldAllowAccessToFrame(exec, thisObject->impl().frame())) + if (!BindingSecurity::shouldAllowAccessToFrame(exec, thisObject->wrapped().frame(), ThrowSecurityError)) return false; return Base::deleteProperty(thisObject, exec, propertyName); } @@ -127,128 +118,89 @@ bool JSLocation::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned p { JSLocation* thisObject = jsCast<JSLocation*>(cell); // Only allow deleting by frames in the same origin. - if (!shouldAllowAccessToFrame(exec, thisObject->impl().frame())) + if (!BindingSecurity::shouldAllowAccessToFrame(exec, thisObject->wrapped().frame(), ThrowSecurityError)) return false; return Base::deletePropertyByIndex(thisObject, exec, propertyName); } -void JSLocation::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) +// https://html.spec.whatwg.org/#crossoriginproperties-(-o-) +static void addCrossOriginPropertyNames(ExecState& state, PropertyNameArray& propertyNames) { - JSLocation* thisObject = jsCast<JSLocation*>(object); - // Only allow the location object to enumerated by frames in the same origin. - if (!shouldAllowAccessToFrame(exec, thisObject->impl().frame())) - return; - Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode); + static const Identifier* const properties[] = { &state.propertyNames().href, &state.propertyNames().replace }; + for (auto* property : properties) + propertyNames.add(*property); } -bool JSLocation::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException) +// https://html.spec.whatwg.org/#crossoriginownpropertykeys-(-o-) +static void addCrossOriginOwnPropertyNames(ExecState& state, PropertyNameArray& propertyNames) { - if (descriptor.isAccessorDescriptor() && (propertyName == exec->propertyNames().toString || propertyName == exec->propertyNames().valueOf)) - return false; - return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException); -} + addCrossOriginPropertyNames(state, propertyNames); -void JSLocation::setHref(ExecState* exec, JSValue value) -{ - String href = value.toString(exec)->value(exec); - if (exec->hadException()) - return; - impl().setHref(href, activeDOMWindow(exec), firstDOMWindow(exec)); + propertyNames.add(state.propertyNames().toStringTagSymbol); + propertyNames.add(state.propertyNames().hasInstanceSymbol); + propertyNames.add(state.propertyNames().isConcatSpreadableSymbol); } -void JSLocation::setProtocol(ExecState* exec, JSValue value) +void JSLocation::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { - String protocol = value.toString(exec)->value(exec); - if (exec->hadException()) + JSLocation* thisObject = jsCast<JSLocation*>(object); + if (!BindingSecurity::shouldAllowAccessToFrame(exec, thisObject->wrapped().frame(), DoNotReportSecurityError)) { + if (mode.includeDontEnumProperties()) + addCrossOriginOwnPropertyNames(*exec, propertyNames); return; - ExceptionCode ec = 0; - impl().setProtocol(protocol, activeDOMWindow(exec), firstDOMWindow(exec), ec); - setDOMException(exec, ec); + } + Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode); } -void JSLocation::setHost(ExecState* exec, JSValue value) +bool JSLocation::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException) { - String host = value.toString(exec)->value(exec); - if (exec->hadException()) - return; - impl().setHost(host, activeDOMWindow(exec), firstDOMWindow(exec)); -} + JSLocation* thisObject = jsCast<JSLocation*>(object); + if (!BindingSecurity::shouldAllowAccessToFrame(exec, thisObject->wrapped().frame(), ThrowSecurityError)) + return false; -void JSLocation::setHostname(ExecState* exec, JSValue value) -{ - String hostname = value.toString(exec)->value(exec); - if (exec->hadException()) - return; - impl().setHostname(hostname, activeDOMWindow(exec), firstDOMWindow(exec)); + if (descriptor.isAccessorDescriptor() && (propertyName == exec->propertyNames().toString || propertyName == exec->propertyNames().valueOf)) + return false; + return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException); } -void JSLocation::setPort(ExecState* exec, JSValue value) +bool JSLocation::setPrototype(JSObject*, ExecState* exec, JSValue, bool shouldThrowIfCantSet) { - String port = value.toWTFString(exec); - if (exec->hadException()) - return; - impl().setPort(port, activeDOMWindow(exec), firstDOMWindow(exec)); -} + auto scope = DECLARE_THROW_SCOPE(exec->vm()); -void JSLocation::setPathname(ExecState* exec, JSValue value) -{ - String pathname = value.toString(exec)->value(exec); - if (exec->hadException()) - return; - impl().setPathname(pathname, activeDOMWindow(exec), firstDOMWindow(exec)); -} + if (shouldThrowIfCantSet) + throwTypeError(exec, scope, ASCIILiteral("Cannot set prototype of this object")); -void JSLocation::setSearch(ExecState* exec, JSValue value) -{ - String pathname = value.toString(exec)->value(exec); - if (exec->hadException()) - return; - impl().setSearch(pathname, activeDOMWindow(exec), firstDOMWindow(exec)); + return false; } -void JSLocation::setHash(ExecState* exec, JSValue value) +JSValue JSLocation::getPrototype(JSObject* object, ExecState* exec) { - String hash = value.toString(exec)->value(exec); - if (exec->hadException()) - return; - impl().setHash(hash, activeDOMWindow(exec), firstDOMWindow(exec)); -} + JSLocation* thisObject = jsCast<JSLocation*>(object); + if (!BindingSecurity::shouldAllowAccessToFrame(exec, thisObject->wrapped().frame(), DoNotReportSecurityError)) + return jsNull(); -JSValue JSLocation::replace(ExecState* exec) -{ - String urlString = exec->argument(0).toString(exec)->value(exec); - if (exec->hadException()) - return jsUndefined(); - impl().replace(urlString, activeDOMWindow(exec), firstDOMWindow(exec)); - return jsUndefined(); + return Base::getPrototype(object, exec); } -JSValue JSLocation::reload(ExecState* exec) +bool JSLocation::preventExtensions(JSObject*, ExecState* exec) { - impl().reload(activeDOMWindow(exec)); - return jsUndefined(); -} + auto scope = DECLARE_THROW_SCOPE(exec->vm()); -JSValue JSLocation::assign(ExecState* exec) -{ - String urlString = exec->argument(0).toString(exec)->value(exec); - if (exec->hadException()) - return jsUndefined(); - impl().assign(urlString, activeDOMWindow(exec), firstDOMWindow(exec)); - return jsUndefined(); + throwTypeError(exec, scope, ASCIILiteral("Cannot prevent extensions on this object")); + return false; } -JSValue JSLocation::toStringFunction(ExecState* exec) +String JSLocation::toStringName(const JSObject* object, ExecState* exec) { - Frame* frame = impl().frame(); - if (!frame || !shouldAllowAccessToFrame(exec, frame)) - return jsUndefined(); - - return jsStringWithCache(exec, impl().toString()); + auto* thisObject = jsCast<const JSLocation*>(object); + if (!BindingSecurity::shouldAllowAccessToFrame(exec, thisObject->wrapped().frame(), DoNotReportSecurityError)) + return ASCIILiteral("Object"); + return ASCIILiteral("Location"); } -bool JSLocationPrototype::putDelegate(ExecState* exec, PropertyName propertyName, JSValue, PutPropertySlot&) +bool JSLocationPrototype::putDelegate(ExecState* exec, PropertyName propertyName, JSValue, PutPropertySlot&, bool& putResult) { + putResult = false; return (propertyName == exec->propertyNames().toString || propertyName == exec->propertyNames().valueOf); } diff --git a/Source/WebCore/bindings/js/JSMainThreadExecState.cpp b/Source/WebCore/bindings/js/JSMainThreadExecState.cpp index 779b96ab0..f49f4a87e 100644 --- a/Source/WebCore/bindings/js/JSMainThreadExecState.cpp +++ b/Source/WebCore/bindings/js/JSMainThreadExecState.cpp @@ -25,11 +25,9 @@ #include "config.h" #include "JSMainThreadExecState.h" -#include "MutationObserver.h" -#if ENABLE(INDEXED_DATABASE) -#include "IDBPendingTransactionMonitor.h" -#endif +#include "Microtasks.h" +#include "MutationObserver.h" namespace WebCore { @@ -37,27 +35,21 @@ JSC::ExecState* JSMainThreadExecState::s_mainThreadState = 0; void JSMainThreadExecState::didLeaveScriptContext() { -#if ENABLE(INDEXED_DATABASE) - // Indexed DB requires that transactions are created with an internal |active| flag - // set to true, but the flag becomes false when control returns to the event loop. - IDBPendingTransactionMonitor::deactivateNewTransactions(); -#endif - - MutationObserver::deliverAllMutations(); + MicrotaskQueue::mainThreadQueue().performMicrotaskCheckpoint(); } -JSC::JSValue functionCallHandlerFromAnyThread(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args) +JSC::JSValue functionCallHandlerFromAnyThread(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args, NakedPtr<JSC::Exception>& returnedException) { if (isMainThread()) - return JSMainThreadExecState::call(exec, functionObject, callType, callData, thisValue, args); - return JSC::call(exec, functionObject, callType, callData, thisValue, args); + return JSMainThreadExecState::call(exec, functionObject, callType, callData, thisValue, args, returnedException); + return JSC::call(exec, functionObject, callType, callData, thisValue, args, returnedException); } -JSC::JSValue evaluateHandlerFromAnyThread(JSC::ExecState* exec, const JSC::SourceCode& source, JSC::JSValue thisValue, JSC::JSValue* exception) +JSC::JSValue evaluateHandlerFromAnyThread(JSC::ExecState* exec, const JSC::SourceCode& source, JSC::JSValue thisValue, NakedPtr<JSC::Exception>& returnedException) { if (isMainThread()) - return JSMainThreadExecState::evaluate(exec, source, thisValue, exception); - return JSC::evaluate(exec, source, thisValue, exception); + return JSMainThreadExecState::evaluate(exec, source, thisValue, returnedException); + return JSC::evaluate(exec, source, thisValue, returnedException); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSMainThreadExecState.h b/Source/WebCore/bindings/js/JSMainThreadExecState.h index ed023dbe2..d244efe0e 100644 --- a/Source/WebCore/bindings/js/JSMainThreadExecState.h +++ b/Source/WebCore/bindings/js/JSMainThreadExecState.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,11 +24,12 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSMainThreadExecState_h -#define JSMainThreadExecState_h +#pragma once +#include "CustomElementReactionQueue.h" #include "JSDOMBinding.h" #include <runtime/Completion.h> +#include <runtime/Microtask.h> #include <wtf/MainThread.h> #if PLATFORM(IOS) @@ -49,23 +51,82 @@ public: return s_mainThreadState; }; - static JSC::JSValue call(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args) + static JSC::JSValue call(JSC::ExecState* exec, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args, NakedPtr<JSC::Exception>& returnedException) { JSMainThreadExecState currentState(exec); - return JSC::call(exec, functionObject, callType, callData, thisValue, args); + return JSC::call(exec, functionObject, callType, callData, thisValue, args, returnedException); }; - static JSC::JSValue evaluate(JSC::ExecState* exec, const JSC::SourceCode& source, JSC::JSValue thisValue, JSC::JSValue* exception) + static JSC::JSValue evaluate(JSC::ExecState* exec, const JSC::SourceCode& source, JSC::JSValue thisValue, NakedPtr<JSC::Exception>& returnedException) { JSMainThreadExecState currentState(exec); - JSC::JSLockHolder lock(exec); - return JSC::evaluate(exec, source, thisValue, exception); + return JSC::evaluate(exec, source, thisValue, returnedException); }; + static JSC::JSValue evaluate(JSC::ExecState* exec, const JSC::SourceCode& source, JSC::JSValue thisValue = JSC::JSValue()) + { + NakedPtr<JSC::Exception> unused; + return evaluate(exec, source, thisValue, unused); + }; + + static JSC::JSValue profiledCall(JSC::ExecState* exec, JSC::ProfilingReason reason, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args, NakedPtr<JSC::Exception>& returnedException) + { + JSMainThreadExecState currentState(exec); + return JSC::profiledCall(exec, reason, functionObject, callType, callData, thisValue, args, returnedException); + } + + static JSC::JSValue profiledEvaluate(JSC::ExecState* exec, JSC::ProfilingReason reason, const JSC::SourceCode& source, JSC::JSValue thisValue, NakedPtr<JSC::Exception>& returnedException) + { + JSMainThreadExecState currentState(exec); + return JSC::profiledEvaluate(exec, reason, source, thisValue, returnedException); + } + + static JSC::JSValue profiledEvaluate(JSC::ExecState* exec, JSC::ProfilingReason reason, const JSC::SourceCode& source, JSC::JSValue thisValue = JSC::JSValue()) + { + NakedPtr<JSC::Exception> unused; + return profiledEvaluate(exec, reason, source, thisValue, unused); + } + + static void runTask(JSC::ExecState* exec, JSC::Microtask& task) + { + JSMainThreadExecState currentState(exec); + task.run(exec); + } + + static JSC::JSInternalPromise& loadModule(JSC::ExecState& state, const String& moduleName, JSC::JSValue scriptFetcher) + { + JSMainThreadExecState currentState(&state); + return *JSC::loadModule(&state, moduleName, scriptFetcher); + } + + static JSC::JSInternalPromise& loadModule(JSC::ExecState& state, const JSC::SourceCode& sourceCode, JSC::JSValue scriptFetcher) + { + JSMainThreadExecState currentState(&state); + return *JSC::loadModule(&state, sourceCode, scriptFetcher); + } + + static JSC::JSValue linkAndEvaluateModule(JSC::ExecState& state, const JSC::Identifier& moduleKey, JSC::JSValue scriptFetcher, NakedPtr<JSC::Exception>& returnedException) + { + JSC::VM& vm = state.vm(); + auto scope = DECLARE_CATCH_SCOPE(vm); + + JSMainThreadExecState currentState(&state); + auto returnValue = JSC::linkAndEvaluateModule(&state, moduleKey, scriptFetcher); + if (UNLIKELY(scope.exception())) { + returnedException = scope.exception(); + scope.clearException(); + return JSC::jsUndefined(); + } + return returnValue; + } + static InspectorInstrumentationCookie instrumentFunctionCall(ScriptExecutionContext*, JSC::CallType, const JSC::CallData&); + static InspectorInstrumentationCookie instrumentFunctionConstruct(ScriptExecutionContext*, JSC::ConstructType, const JSC::ConstructData&); +private: explicit JSMainThreadExecState(JSC::ExecState* exec) : m_previousState(s_mainThreadState) + , m_lock(exec) { ASSERT(isMainThread()); s_mainThreadState = exec; @@ -73,7 +134,10 @@ public: ~JSMainThreadExecState() { + JSC::VM& vm = s_mainThreadState->vm(); + auto scope = DECLARE_CATCH_SCOPE(vm); ASSERT(isMainThread()); + ASSERT_UNUSED(scope, !scope.exception()); bool didExitJavaScript = s_mainThreadState && !m_previousState; @@ -83,9 +147,11 @@ public: didLeaveScriptContext(); } -private: - static JSC::ExecState* s_mainThreadState; + template<typename Type, Type jsType, typename DataType> static InspectorInstrumentationCookie instrumentFunctionInternal(ScriptExecutionContext*, Type, const DataType&); + + WEBCORE_EXPORT static JSC::ExecState* s_mainThreadState; JSC::ExecState* m_previousState; + JSC::JSLockHolder m_lock; static void didLeaveScriptContext(); }; @@ -110,11 +176,10 @@ public: private: JSC::ExecState* m_previousState; + CustomElementReactionStack m_customElementReactionStack; }; -JSC::JSValue functionCallHandlerFromAnyThread(JSC::ExecState*, JSC::JSValue functionObject, JSC::CallType callType, const JSC::CallData& callData, JSC::JSValue thisValue, const JSC::ArgList& args); -JSC::JSValue evaluateHandlerFromAnyThread(JSC::ExecState*, const JSC::SourceCode&, JSC::JSValue thisValue, JSC::JSValue* exception); +JSC::JSValue functionCallHandlerFromAnyThread(JSC::ExecState*, JSC::JSValue functionObject, JSC::CallType, const JSC::CallData&, JSC::JSValue thisValue, const JSC::ArgList& args, NakedPtr<JSC::Exception>& returnedException); +JSC::JSValue evaluateHandlerFromAnyThread(JSC::ExecState*, const JSC::SourceCode&, JSC::JSValue thisValue, NakedPtr<JSC::Exception>& returnedException); } // namespace WebCore - -#endif // JSMainThreadExecState_h diff --git a/Source/WebCore/bindings/js/JSMainThreadExecStateInstrumentation.h b/Source/WebCore/bindings/js/JSMainThreadExecStateInstrumentation.h index de4524696..4ad6e3201 100644 --- a/Source/WebCore/bindings/js/JSMainThreadExecStateInstrumentation.h +++ b/Source/WebCore/bindings/js/JSMainThreadExecStateInstrumentation.h @@ -24,29 +24,37 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSMainThreadExecStateInstrumentation_h -#define JSMainThreadExecStateInstrumentation_h +#pragma once #include "InspectorInstrumentation.h" #include "JSMainThreadExecState.h" -#include <runtime/Executable.h> +#include <runtime/FunctionExecutable.h> namespace WebCore { -inline InspectorInstrumentationCookie JSMainThreadExecState::instrumentFunctionCall(ScriptExecutionContext* context, JSC::CallType callType, const JSC::CallData& callData) +template<typename Type, Type jsType, class DataType> +inline InspectorInstrumentationCookie JSMainThreadExecState::instrumentFunctionInternal(ScriptExecutionContext* context, Type callType, const DataType& callData) { if (!InspectorInstrumentation::timelineAgentEnabled(context)) return InspectorInstrumentationCookie(); String resourceName; int lineNumber = 1; - if (callType == JSC::CallTypeJS) { + if (callType == jsType) { resourceName = callData.js.functionExecutable->sourceURL(); - lineNumber = callData.js.functionExecutable->lineNo(); + lineNumber = callData.js.functionExecutable->firstLine(); } else resourceName = "undefined"; return InspectorInstrumentation::willCallFunction(context, resourceName, lineNumber); } -} // namespace WebCore +inline InspectorInstrumentationCookie JSMainThreadExecState::instrumentFunctionCall(ScriptExecutionContext* context, JSC::CallType type, const JSC::CallData& data) +{ + return instrumentFunctionInternal<JSC::CallType, JSC::CallType::JS, JSC::CallData>(context, type, data); +} -#endif // JSMainThreadExecStateInstrumentation_h +inline InspectorInstrumentationCookie JSMainThreadExecState::instrumentFunctionConstruct(ScriptExecutionContext* context, JSC::ConstructType type, const JSC::ConstructData& data) +{ + return instrumentFunctionInternal<JSC::ConstructType, JSC::ConstructType::JS, JSC::ConstructData>(context, type, data); +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSMediaKeySessionCustom.cpp b/Source/WebCore/bindings/js/JSMediaKeySessionCustom.cpp new file mode 100644 index 000000000..4227ccd39 --- /dev/null +++ b/Source/WebCore/bindings/js/JSMediaKeySessionCustom.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016 Metrological Group B.V. + * Copyright (C) 2016 Igalia S.L. + * + * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(ENCRYPTED_MEDIA) + +#include "JSMediaKeySession.h" + +namespace WebCore { + +JSC::JSValue JSMediaKeySession::closed(JSC::ExecState& state) const +{ + if (!m_closed) { + auto promise = createDeferredPromise(state, domWindow()); + m_closed.set(state.vm(), this, promise->promise()); + wrapped().registerClosedPromise(WTFMove(promise)); + } + return m_closed.get(); +} + +} // namespace WebCore + +#endif // ENABLE(ENCRYPTED_MEDIA) diff --git a/Source/WebCore/bindings/js/JSMediaListCustom.h b/Source/WebCore/bindings/js/JSMediaListCustom.h index 8f4ff7aeb..af934b75c 100644 --- a/Source/WebCore/bindings/js/JSMediaListCustom.h +++ b/Source/WebCore/bindings/js/JSMediaListCustom.h @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,8 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSMediaListCustom_h -#define JSMediaListCustom_h +#pragma once #include "CSSRule.h" #include "CSSStyleSheet.h" @@ -44,5 +43,3 @@ inline void* root(MediaList* mediaList) } } // namespace WebCore - -#endif // JSMediaListCustom_h diff --git a/Source/WebCore/bindings/js/JSMediaSourceStatesCustom.cpp b/Source/WebCore/bindings/js/JSMediaSourceStatesCustom.cpp deleted file mode 100644 index 4123e08b7..000000000 --- a/Source/WebCore/bindings/js/JSMediaSourceStatesCustom.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2013 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 COMPUTER, INC. ``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 COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#if ENABLE(MEDIA_STREAM) - -#include "JSMediaSourceStates.h" - -#include "MediaSourceStates.h" - -using namespace JSC; - -namespace WebCore { - -JSValue JSMediaSourceStates::width(ExecState*) const -{ - if (!impl().hasVideoSource()) - return jsUndefined(); - - return jsNumber(impl().width()); -} - -JSValue JSMediaSourceStates::height(ExecState*) const -{ - if (!impl().hasVideoSource()) - return jsUndefined(); - - return jsNumber(impl().height()); -} - -JSValue JSMediaSourceStates::frameRate(ExecState*) const -{ - if (!impl().hasVideoSource()) - return jsUndefined(); - - return jsNumber(impl().frameRate()); -} - -JSValue JSMediaSourceStates::aspectRatio(ExecState*) const -{ - if (!impl().hasVideoSource()) - return jsUndefined(); - - return jsNumber(impl().aspectRatio()); -} - -JSValue JSMediaSourceStates::facingMode(ExecState* exec) const -{ - if (!impl().hasVideoSource()) - return jsUndefined(); - - const AtomicString& mode = impl().facingMode(); - if (mode.isEmpty()) - return jsUndefined(); - - return jsStringWithCache(exec, impl().facingMode()); -} - -JSValue JSMediaSourceStates::volume(ExecState*) const -{ - if (impl().hasVideoSource()) - return jsUndefined(); - - return jsNumber(impl().volume()); -} - -} // namespace WebCore - -#endif diff --git a/Source/WebCore/bindings/js/JSMediaStreamCapabilitiesCustom.cpp b/Source/WebCore/bindings/js/JSMediaStreamCapabilitiesCustom.cpp index 9ad691de1..b2c6257b7 100644 --- a/Source/WebCore/bindings/js/JSMediaStreamCapabilitiesCustom.cpp +++ b/Source/WebCore/bindings/js/JSMediaStreamCapabilitiesCustom.cpp @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -31,21 +31,22 @@ #include "JSAllAudioCapabilities.h" #include "JSAllVideoCapabilities.h" -#include "MediaStreamCapabilities.h" +#include "JSDOMBinding.h" using namespace JSC; namespace WebCore { -JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, MediaStreamCapabilities* object) +JSC::JSValue toJSNewlyCreated(JSC::ExecState*, JSDOMGlobalObject* globalObject, Ref<MediaStreamCapabilities>&& object) { - if (!object) - return jsNull(); - - if (object->hasVideoSource()) - return wrap<JSAllVideoCapabilities>(exec, globalObject, static_cast<AllVideoCapabilities*>(object)); + if (object.hasVideoSource()) + return CREATE_DOM_WRAPPER(globalObject, AllVideoCapabilities, WTFMove(object)); + return CREATE_DOM_WRAPPER(globalObject, AllAudioCapabilities, WTFMove(object)); +} - return wrap<JSAllAudioCapabilities>(exec, globalObject, static_cast<AllAudioCapabilities*>(object)); +JSValue toJS(ExecState* state, JSDOMGlobalObject* globalObject, MediaStreamCapabilities& object) +{ + return wrap(state, globalObject, object); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSMessageChannelCustom.cpp b/Source/WebCore/bindings/js/JSMessageChannelCustom.cpp index 3b2b26189..375dd4b5f 100644 --- a/Source/WebCore/bindings/js/JSMessageChannelCustom.cpp +++ b/Source/WebCore/bindings/js/JSMessageChannelCustom.cpp @@ -27,27 +27,18 @@ #if ENABLE(CHANNEL_MESSAGING) +#include "DOMWrapperWorld.h" #include "JSMessageChannel.h" - -#include "MessageChannel.h" -#include <runtime/Error.h> - -using namespace JSC; +#include <heap/SlotVisitorInlines.h> namespace WebCore { -void JSMessageChannel::visitChildren(JSCell* cell, SlotVisitor& visitor) +void JSMessageChannel::visitAdditionalChildren(JSC::SlotVisitor& visitor) { - JSMessageChannel* thisObject = jsCast<JSMessageChannel*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(thisObject, visitor); - - if (MessagePort* port = thisObject->m_impl->port1()) + if (MessagePort* port = wrapped().port1()) visitor.addOpaqueRoot(port); - if (MessagePort* port = thisObject->m_impl->port2()) + if (MessagePort* port = wrapped().port2()) visitor.addOpaqueRoot(port); } diff --git a/Source/WebCore/bindings/js/JSMessageEventCustom.cpp b/Source/WebCore/bindings/js/JSMessageEventCustom.cpp index c84ca0d9a..e0886ab25 100644 --- a/Source/WebCore/bindings/js/JSMessageEventCustom.cpp +++ b/Source/WebCore/bindings/js/JSMessageEventCustom.cpp @@ -33,9 +33,10 @@ #include "JSBlob.h" #include "JSDOMBinding.h" +#include "JSDOMConvert.h" #include "JSDOMWindow.h" #include "JSEventTarget.h" -#include "JSMessagePortCustom.h" +#include "JSMessagePort.h" #include "MessageEvent.h" #include <runtime/JSArray.h> #include <runtime/JSArrayBuffer.h> @@ -44,85 +45,104 @@ using namespace JSC; namespace WebCore { -JSValue JSMessageEvent::data(ExecState* exec) const +JSValue JSMessageEvent::data(ExecState& state) const { - if (JSValue cachedValue = m_data.get()) - return cachedValue; + if (JSValue cachedValue = m_data.get()) { + // We cannot use a cached object if we are in a different world than the one it was created in. + if (!cachedValue.isObject() || &worldForDOMObject(cachedValue.getObject()) == ¤tWorld(&state)) + return cachedValue; + ASSERT_NOT_REACHED(); + } - MessageEvent& event = impl(); + MessageEvent& event = wrapped(); JSValue result; switch (event.dataType()) { case MessageEvent::DataTypeScriptValue: { - Deprecated::ScriptValue scriptValue = event.dataAsScriptValue(); - if (scriptValue.hasNoValue()) + JSValue dataValue = event.dataAsScriptValue(); + if (!dataValue) result = jsNull(); - else - result = scriptValue.jsValue(); + else { + // We need to make sure MessageEvents do not leak objects in their state property across isolated DOM worlds. + // Ideally, we would check that the worlds have different privileges but that's not possible yet. + if (dataValue.isObject() && &worldForDOMObject(dataValue.getObject()) != ¤tWorld(&state)) { + RefPtr<SerializedScriptValue> serializedValue = event.trySerializeData(&state); + if (serializedValue) + result = serializedValue->deserialize(state, globalObject()); + else + result = jsNull(); + } else + result = dataValue; + } break; } case MessageEvent::DataTypeSerializedScriptValue: if (RefPtr<SerializedScriptValue> serializedValue = event.dataAsSerializedScriptValue()) { - MessagePortArray ports = impl().ports(); - result = serializedValue->deserialize(exec, globalObject(), &ports, NonThrowing); - } - else + Vector<RefPtr<MessagePort>> ports = wrapped().ports(); + // FIXME: Why does this suppress exceptions? + result = serializedValue->deserialize(state, globalObject(), ports, SerializationErrorMode::NonThrowing); + } else result = jsNull(); break; case MessageEvent::DataTypeString: - result = jsStringWithCache(exec, event.dataAsString()); + result = jsStringWithCache(&state, event.dataAsString()); break; case MessageEvent::DataTypeBlob: - result = toJS(exec, globalObject(), event.dataAsBlob()); + result = toJS(&state, globalObject(), event.dataAsBlob()); break; case MessageEvent::DataTypeArrayBuffer: - result = toJS(exec, globalObject(), event.dataAsArrayBuffer()); + result = toJS(&state, globalObject(), event.dataAsArrayBuffer()); break; } // Save the result so we don't have to deserialize the value again. - const_cast<JSMessageEvent*>(this)->m_data.set(exec->vm(), this, result); + m_data.set(state.vm(), this, result); return result; } -static JSC::JSValue handleInitMessageEvent(JSMessageEvent* jsEvent, JSC::ExecState* exec) +static JSC::JSValue handleInitMessageEvent(JSMessageEvent* jsEvent, JSC::ExecState& state) { - const String& typeArg = exec->argument(0).toString(exec)->value(exec); - bool canBubbleArg = exec->argument(1).toBoolean(exec); - bool cancelableArg = exec->argument(2).toBoolean(exec); - const String originArg = exec->argument(4).toString(exec)->value(exec); - const String lastEventIdArg = exec->argument(5).toString(exec)->value(exec); - DOMWindow* sourceArg = toDOMWindow(exec->argument(6)); - OwnPtr<MessagePortArray> messagePorts; - OwnPtr<ArrayBufferArray> arrayBuffers; - if (!exec->argument(7).isUndefinedOrNull()) { - messagePorts = adoptPtr(new MessagePortArray); - arrayBuffers = adoptPtr(new ArrayBufferArray); - fillMessagePortArray(exec, exec->argument(7), *messagePorts, *arrayBuffers); - if (exec->hadException()) - return jsUndefined(); + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + const String& typeArg = state.argument(0).toWTFString(&state); + RETURN_IF_EXCEPTION(scope, JSValue()); + + bool canBubbleArg = state.argument(1).toBoolean(&state); + RETURN_IF_EXCEPTION(scope, JSValue()); + + bool cancelableArg = state.argument(2).toBoolean(&state); + RETURN_IF_EXCEPTION(scope, JSValue()); + + JSValue dataArg = state.argument(3); + + const String originArg = convert<IDLUSVString>(state, state.argument(4)); + RETURN_IF_EXCEPTION(scope, JSValue()); + + const String lastEventIdArg = state.argument(5).toWTFString(&state); + RETURN_IF_EXCEPTION(scope, JSValue()); + + auto sourceArg = convert<IDLNullable<IDLUnion<IDLInterface<DOMWindow>, IDLInterface<MessagePort>>>>(state, state.argument(6)); + RETURN_IF_EXCEPTION(scope, JSValue()); + + Vector<RefPtr<MessagePort>> messagePorts; + if (!state.argument(7).isUndefinedOrNull()) { + messagePorts = convert<IDLSequence<IDLInterface<MessagePort>>>(state, state.argument(7)); + RETURN_IF_EXCEPTION(scope, JSValue()); } - Deprecated::ScriptValue dataArg = Deprecated::ScriptValue(exec->vm(), exec->argument(3)); - if (exec->hadException()) - return jsUndefined(); - MessageEvent& event = jsEvent->impl(); - event.initMessageEvent(typeArg, canBubbleArg, cancelableArg, dataArg, originArg, lastEventIdArg, sourceArg, messagePorts.release()); - jsEvent->m_data.set(exec->vm(), jsEvent, dataArg.jsValue()); + MessageEvent& event = jsEvent->wrapped(); + event.initMessageEvent(state, typeArg, canBubbleArg, cancelableArg, dataArg, originArg, lastEventIdArg, WTFMove(sourceArg), WTFMove(messagePorts)); + jsEvent->m_data.set(vm, jsEvent, dataArg); return jsUndefined(); } -JSC::JSValue JSMessageEvent::initMessageEvent(JSC::ExecState* exec) -{ - return handleInitMessageEvent(this, exec); -} - -JSC::JSValue JSMessageEvent::webkitInitMessageEvent(JSC::ExecState* exec) +JSC::JSValue JSMessageEvent::webkitInitMessageEvent(JSC::ExecState& state) { - return handleInitMessageEvent(this, exec); + return handleInitMessageEvent(this, state); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSMessagePortCustom.cpp b/Source/WebCore/bindings/js/JSMessagePortCustom.cpp index 33ed4dc3a..b168cf22f 100644 --- a/Source/WebCore/bindings/js/JSMessagePortCustom.cpp +++ b/Source/WebCore/bindings/js/JSMessagePortCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved. + * Copyright (C) 2008-2009, 2016 Apple Inc. All Rights Reserved. * Copyright (C) 2011 Google Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,87 +27,15 @@ #include "config.h" #include "JSMessagePort.h" -#include "Event.h" -#include "ExceptionCode.h" -#include "Frame.h" -#include "JSDOMGlobalObject.h" -#include "JSEvent.h" -#include "JSEventListener.h" -#include "JSMessagePortCustom.h" -#include "MessagePort.h" -#include <runtime/Error.h> -#include <runtime/JSArrayBuffer.h> -#include <wtf/text/AtomicString.h> - using namespace JSC; namespace WebCore { -void JSMessagePort::visitChildren(JSCell* cell, SlotVisitor& visitor) +void JSMessagePort::visitAdditionalChildren(SlotVisitor& visitor) { - JSMessagePort* thisObject = jsCast<JSMessagePort*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(thisObject, visitor); - // If we have a locally entangled port, we can directly mark it as reachable. Ports that are remotely entangled are marked in-use by markActiveObjectsForContext(). - if (MessagePort* port = thisObject->m_impl->locallyEntangledPort()) + if (MessagePort* port = wrapped().locallyEntangledPort()) visitor.addOpaqueRoot(port); - - thisObject->m_impl->visitJSEventListeners(visitor); -} - -JSC::JSValue JSMessagePort::postMessage(JSC::ExecState* exec) -{ - return handlePostMessage(exec, &impl()); -} - -void fillMessagePortArray(JSC::ExecState* exec, JSC::JSValue value, MessagePortArray& portArray, ArrayBufferArray& arrayBuffers) -{ - // Convert from the passed-in JS array-like object to a MessagePortArray. - // Also validates the elements per sections 4.1.13 and 4.1.15 of the WebIDL spec and section 8.3.3 of the HTML5 spec. - if (value.isUndefinedOrNull()) { - portArray.resize(0); - arrayBuffers.resize(0); - return; - } - - // Validation of sequence types, per WebIDL spec 4.1.13. - unsigned length = 0; - JSObject* object = toJSSequence(exec, value, length); - if (exec->hadException()) - return; - - for (unsigned i = 0 ; i < length; ++i) { - JSValue value = object->get(exec, i); - if (exec->hadException()) - return; - // Validation of non-null objects, per HTML5 spec 10.3.3. - if (value.isUndefinedOrNull()) { - setDOMException(exec, INVALID_STATE_ERR); - return; - } - - // Validation of Objects implementing an interface, per WebIDL spec 4.1.15. - RefPtr<MessagePort> port = toMessagePort(value); - if (port) { - // Check for duplicate ports. - if (portArray.contains(port)) { - setDOMException(exec, INVALID_STATE_ERR); - return; - } - portArray.append(port.release()); - } else { - RefPtr<ArrayBuffer> arrayBuffer = toArrayBuffer(value); - if (arrayBuffer) - arrayBuffers.append(arrayBuffer); - else { - throwTypeError(exec); - return; - } - } - } } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSMessagePortCustom.h b/Source/WebCore/bindings/js/JSMessagePortCustom.h deleted file mode 100644 index bbd566299..000000000 --- a/Source/WebCore/bindings/js/JSMessagePortCustom.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2009 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef JSMessagePortCustom_h -#define JSMessagePortCustom_h - -#include "MessagePort.h" -#include <runtime/JSCJSValue.h> -#include <runtime/Operations.h> -#include <wtf/Forward.h> - -namespace WebCore { - - typedef int ExceptionCode; - - // Helper function which pulls the values out of a JS sequence and into a MessagePortArray. - // Also validates the elements per sections 4.1.13 and 4.1.15 of the WebIDL spec and section 8.3.3 of the HTML5 spec. - // May generate an exception via the passed ExecState. - void fillMessagePortArray(JSC::ExecState*, JSC::JSValue, MessagePortArray&, ArrayBufferArray&); - - // Helper function to convert from JS postMessage arguments to WebCore postMessage arguments. - template <typename T> - inline JSC::JSValue handlePostMessage(JSC::ExecState* exec, T* impl) - { - MessagePortArray portArray; - ArrayBufferArray arrayBufferArray; - fillMessagePortArray(exec, exec->argument(1), portArray, arrayBufferArray); - RefPtr<SerializedScriptValue> message = SerializedScriptValue::create(exec, exec->argument(0), &portArray, &arrayBufferArray); - if (exec->hadException()) - return JSC::jsUndefined(); - - ExceptionCode ec = 0; - impl->postMessage(message.release(), &portArray, ec); - setDOMException(exec, ec); - return JSC::jsUndefined(); - } - -} -#endif // JSMessagePortCustom_h diff --git a/Source/WebCore/bindings/js/JSMockContentFilterSettingsCustom.cpp b/Source/WebCore/bindings/js/JSMockContentFilterSettingsCustom.cpp new file mode 100644 index 000000000..cbce60cf5 --- /dev/null +++ b/Source/WebCore/bindings/js/JSMockContentFilterSettingsCustom.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2015-2016 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 "JSMockContentFilterSettings.h" + +#if ENABLE(CONTENT_FILTERING) + +#include "JSDOMBinding.h" +#include "JSDOMConvert.h" +#include "MockContentFilterSettings.h" + +using namespace JSC; + +namespace WebCore { + +using Decision = MockContentFilterSettings::Decision; +using DecisionPoint = MockContentFilterSettings::DecisionPoint; + +JSValue JSMockContentFilterSettings::decisionPoint(ExecState&) const +{ + DecisionPoint decisionPoint = wrapped().decisionPoint(); + switch (decisionPoint) { + case DecisionPoint::AfterWillSendRequest: + case DecisionPoint::AfterRedirect: + case DecisionPoint::AfterResponse: + case DecisionPoint::AfterAddData: + case DecisionPoint::AfterFinishedAddingData: + case DecisionPoint::Never: + return jsNumber(static_cast<uint8_t>(decisionPoint)); + } + + ASSERT_NOT_REACHED(); + return jsUndefined(); +} + +void JSMockContentFilterSettings::setDecisionPoint(ExecState& state, JSValue value) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + uint8_t nativeValue { convert<IDLOctet>(state, value, IntegerConversionConfiguration::EnforceRange) }; + RETURN_IF_EXCEPTION(scope, void()); + + DecisionPoint decisionPoint { static_cast<DecisionPoint>(nativeValue) }; + switch (decisionPoint) { + case DecisionPoint::AfterWillSendRequest: + case DecisionPoint::AfterRedirect: + case DecisionPoint::AfterResponse: + case DecisionPoint::AfterAddData: + case DecisionPoint::AfterFinishedAddingData: + case DecisionPoint::Never: + wrapped().setDecisionPoint(decisionPoint); + return; + } + + throwTypeError(&state, scope, String::format("%u is not a valid decisionPoint value.", nativeValue)); +} + +static inline JSValue toJSValue(Decision decision) +{ + switch (decision) { + case Decision::Allow: + case Decision::Block: + return jsNumber(static_cast<uint8_t>(decision)); + } + + ASSERT_NOT_REACHED(); + return jsUndefined(); +} + +static inline Decision toDecision(ExecState& state, JSValue value) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + uint8_t nativeValue { convert<IDLOctet>(state, value, IntegerConversionConfiguration::EnforceRange) }; + RETURN_IF_EXCEPTION(scope, Decision::Allow); + + Decision decision { static_cast<Decision>(nativeValue) }; + switch (decision) { + case Decision::Allow: + case Decision::Block: + return decision; + } + + throwTypeError(&state, scope, String::format("%u is not a valid decision value.", nativeValue)); + return Decision::Allow; +} + +JSValue JSMockContentFilterSettings::decision(ExecState&) const +{ + return toJSValue(wrapped().decision()); +} + +void JSMockContentFilterSettings::setDecision(ExecState& state, JSValue value) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + Decision decision { toDecision(state, value) }; + RETURN_IF_EXCEPTION(scope, void()); + + wrapped().setDecision(decision); +} + +JSValue JSMockContentFilterSettings::unblockRequestDecision(ExecState&) const +{ + return toJSValue(wrapped().unblockRequestDecision()); +} + +void JSMockContentFilterSettings::setUnblockRequestDecision(ExecState& state, JSValue value) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + Decision unblockRequestDecision { toDecision(state, value) }; + RETURN_IF_EXCEPTION(scope, void()); + + wrapped().setUnblockRequestDecision(unblockRequestDecision); +} + +}; // namespace WebCore + +#endif // ENABLE(CONTENT_FILTERING) diff --git a/Source/WebCore/bindings/js/JSMutationCallback.cpp b/Source/WebCore/bindings/js/JSMutationCallback.cpp index adabc7eb7..afc422f36 100644 --- a/Source/WebCore/bindings/js/JSMutationCallback.cpp +++ b/Source/WebCore/bindings/js/JSMutationCallback.cpp @@ -51,12 +51,12 @@ JSMutationCallback::~JSMutationCallback() { } -void JSMutationCallback::call(const Vector<RefPtr<MutationRecord>>& mutations, MutationObserver* observer) +void JSMutationCallback::call(const Vector<Ref<MutationRecord>>& mutations, MutationObserver* observer) { if (!canInvokeCallback()) return; - Ref<JSMutationCallback> protect(*this); + Ref<JSMutationCallback> protectedThis(*this); JSLockHolder lock(m_isolatedWorld->vm()); @@ -66,7 +66,7 @@ void JSMutationCallback::call(const Vector<RefPtr<MutationRecord>>& mutations, M JSValue callback = m_callback.get(); CallData callData; CallType callType = getCallData(callback, callData); - if (callType == CallTypeNone) { + if (callType == CallType::None) { ASSERT_NOT_REACHED(); return; } @@ -82,17 +82,18 @@ void JSMutationCallback::call(const Vector<RefPtr<MutationRecord>>& mutations, M JSValue jsObserver = toJS(exec, globalObject, observer); MarkedArgumentBuffer args; - args.append(jsArray(exec, globalObject, mutations)); + args.append(toJS<IDLSequence<IDLInterface<MutationRecord>>>(*exec, *globalObject, mutations)); args.append(jsObserver); InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(context, callType, callData); - JSMainThreadExecState::call(exec, callback, callType, callData, jsObserver, args); + NakedPtr<JSC::Exception> exception; + JSMainThreadExecState::profiledCall(exec, JSC::ProfilingReason::Other, callback, callType, callData, jsObserver, args, exception); - InspectorInstrumentation::didCallFunction(cookie); + InspectorInstrumentation::didCallFunction(cookie, context); - if (exec->hadException()) - reportCurrentException(exec); + if (exception) + reportException(exec, exception); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSMutationCallback.h b/Source/WebCore/bindings/js/JSMutationCallback.h index d7bd8483b..427d6243a 100644 --- a/Source/WebCore/bindings/js/JSMutationCallback.h +++ b/Source/WebCore/bindings/js/JSMutationCallback.h @@ -23,8 +23,7 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSMutationCallback_h -#define JSMutationCallback_h +#pragma once #include "ActiveDOMCallback.h" #include "DOMWrapperWorld.h" @@ -37,18 +36,17 @@ namespace WebCore { class JSDOMGlobalObject; -class JSMutationCallback : public MutationCallback, public ActiveDOMCallback { +class JSMutationCallback final : public MutationCallback, public ActiveDOMCallback { public: - static PassRefPtr<JSMutationCallback> create(JSC::JSObject* callback, JSDOMGlobalObject* globalObject) + static Ref<JSMutationCallback> create(JSC::JSObject* callback, JSDOMGlobalObject* globalObject) { - return adoptRef(new JSMutationCallback(callback, globalObject)); + return adoptRef(*new JSMutationCallback(callback, globalObject)); } virtual ~JSMutationCallback(); - virtual void call(const Vector<RefPtr<MutationRecord>>&, MutationObserver*) override; - - virtual ScriptExecutionContext* scriptExecutionContext() const override { return ContextDestructionObserver::scriptExecutionContext(); } + void call(const Vector<Ref<MutationRecord>>&, MutationObserver*) override; + bool canInvokeCallback() const override { return ActiveDOMCallback::canInvokeCallback(); } private: JSMutationCallback(JSC::JSObject* callback, JSDOMGlobalObject*); @@ -58,5 +56,3 @@ private: }; } // namespace WebCore - -#endif diff --git a/Source/WebCore/bindings/js/JSMutationObserverCustom.cpp b/Source/WebCore/bindings/js/JSMutationObserverCustom.cpp index 09760945e..33c5509ae 100644 --- a/Source/WebCore/bindings/js/JSMutationObserverCustom.cpp +++ b/Source/WebCore/bindings/js/JSMutationObserverCustom.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2011 Google Inc. All rights reserved. + * Copyright (C) 2016 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 @@ -29,10 +30,10 @@ */ #include "config.h" - #include "JSMutationObserver.h" #include "ExceptionCode.h" +#include "JSDOMConstructorBase.h" #include "JSMutationCallback.h" #include "JSNodeCustom.h" #include "MutationObserver.h" @@ -43,30 +44,31 @@ using namespace JSC; namespace WebCore { -EncodedJSValue JSC_HOST_CALL JSMutationObserverConstructor::constructJSMutationObserver(ExecState* exec) +EncodedJSValue JSC_HOST_CALL constructJSMutationObserver(ExecState& exec) { - if (exec->argumentCount() < 1) - return throwVMError(exec, createNotEnoughArgumentsError(exec)); + VM& vm = exec.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (exec.argumentCount() < 1) + return throwVMError(&exec, scope, createNotEnoughArgumentsError(&exec)); - JSObject* object = exec->argument(0).getObject(); + JSObject* object = exec.uncheckedArgument(0).getObject(); CallData callData; - if (!object || object->methodTable()->getCallData(object, callData) == CallTypeNone) - return throwVMError(exec, createTypeError(exec, "Callback argument must be a function")); + if (!object || object->methodTable()->getCallData(object, callData) == CallType::None) + return throwArgumentTypeError(exec, scope, 0, "callback", "MutationObserver", nullptr, "MutationCallback"); - JSMutationObserverConstructor* jsConstructor = jsCast<JSMutationObserverConstructor*>(exec->callee()); - RefPtr<JSMutationCallback> callback = JSMutationCallback::create(object, jsConstructor->globalObject()); - JSObject* jsObserver = asObject(toJS(exec, jsConstructor->globalObject(), MutationObserver::create(callback.release()))); + auto* jsConstructor = jsCast<JSDOMConstructorBase*>(exec.jsCallee()); + auto callback = JSMutationCallback::create(object, jsConstructor->globalObject()); + JSObject* jsObserver = asObject(toJSNewlyCreated(&exec, jsConstructor->globalObject(), MutationObserver::create(WTFMove(callback)))); PrivateName propertyName; - jsObserver->putDirect(jsConstructor->globalObject()->vm(), propertyName, object); + jsObserver->putDirect(vm, propertyName, object); return JSValue::encode(jsObserver); } bool JSMutationObserverOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor) { - MutationObserver& observer = jsCast<JSMutationObserver*>(handle.get().asCell())->impl(); - auto observedNodes = observer.getObservedNodes(); - for (auto it = observedNodes.begin(), end = observedNodes.end(); it != end; ++it) { - if (visitor.containsOpaqueRoot(root(*it))) + for (auto* node : jsCast<JSMutationObserver*>(handle.slot()->asCell())->wrapped().observedNodes()) { + if (visitor.containsOpaqueRoot(root(node))) return true; } return false; diff --git a/Source/WebCore/bindings/js/JSNamedNodeMapCustom.cpp b/Source/WebCore/bindings/js/JSNamedNodeMapCustom.cpp deleted file mode 100644 index 5e3c898fb..000000000 --- a/Source/WebCore/bindings/js/JSNamedNodeMapCustom.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2007, 2008, 2009, 2013 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 COMPUTER, INC. ``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 COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "JSNamedNodeMap.h" - -#include "JSNode.h" - -#include "Element.h" -#include "NamedNodeMap.h" - -using namespace JSC; - -namespace WebCore { - -bool JSNamedNodeMap::canGetItemsForName(ExecState*, NamedNodeMap* impl, PropertyName propertyName) -{ - return impl->getNamedItem(propertyNameToAtomicString(propertyName)); -} - -EncodedJSValue JSNamedNodeMap::nameGetter(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName propertyName) -{ - JSNamedNodeMap* thisObj = jsCast<JSNamedNodeMap*>(JSValue::decode(slotBase)); - return JSValue::encode(toJS(exec, thisObj->globalObject(), thisObj->impl().getNamedItem(propertyNameToAtomicString(propertyName)))); -} - -} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSNodeCustom.cpp b/Source/WebCore/bindings/js/JSNodeCustom.cpp index 3c2468cd8..32548720c 100644 --- a/Source/WebCore/bindings/js/JSNodeCustom.cpp +++ b/Source/WebCore/bindings/js/JSNodeCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2009-2010, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -32,8 +32,6 @@ #include "Document.h" #include "DocumentFragment.h" #include "DocumentType.h" -#include "Entity.h" -#include "EntityReference.h" #include "ExceptionCode.h" #include "HTMLAudioElement.h" #include "HTMLCanvasElement.h" @@ -51,29 +49,22 @@ #include "JSDocument.h" #include "JSDocumentFragment.h" #include "JSDocumentType.h" -#include "JSEntity.h" -#include "JSEntityReference.h" #include "JSEventListener.h" #include "JSHTMLElement.h" #include "JSHTMLElementWrapperFactory.h" -#include "JSNotation.h" #include "JSProcessingInstruction.h" +#include "JSSVGElementWrapperFactory.h" +#include "JSShadowRoot.h" #include "JSText.h" #include "Node.h" -#include "Notation.h" #include "ProcessingInstruction.h" #include "RegisteredEventListener.h" +#include "SVGElement.h" +#include "ScriptState.h" #include "ShadowRoot.h" #include "StyleSheet.h" #include "StyledElement.h" #include "Text.h" -#include <wtf/PassRefPtr.h> -#include <wtf/RefPtr.h> - -#if ENABLE(SVG) -#include "JSSVGElementWrapperFactory.h" -#include "SVGElement.h" -#endif using namespace JSC; @@ -81,40 +72,28 @@ namespace WebCore { using namespace HTMLNames; -static inline bool isObservable(JSNode* jsNode, Node* node) +static inline bool isReachableFromDOM(Node* node, SlotVisitor& visitor) { - // The root node keeps the tree intact. - if (!node->parentNode()) - return true; - - if (jsNode->hasCustomProperties()) - return true; - - // A node's JS wrapper is responsible for marking its JS event listeners. - if (node->hasEventListeners()) - return true; - - return false; -} + if (!node->isConnected()) { + if (is<Element>(*node)) { + auto& element = downcast<Element>(*node); -static inline bool isReachableFromDOM(JSNode* jsNode, Node* node, SlotVisitor& visitor) -{ - if (!node->inDocument()) { - // If a wrapper is the last reference to an image 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 element is destroyed, its load event will not fire. - // FIXME: The DOM should manage this issue without the help of JavaScript wrappers. - if (isHTMLImageElement(node)) { - if (toHTMLImageElement(node)->hasPendingActivity()) - return true; - } - #if ENABLE(VIDEO) - else if (isHTMLAudioElement(node)) { - if (!toHTMLAudioElement(node)->paused()) - return true; + // If a wrapper is the last reference to an image 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 element is destroyed, its load event will not fire. + // FIXME: The DOM should manage this issue without the help of JavaScript wrappers. + if (is<HTMLImageElement>(element)) { + if (downcast<HTMLImageElement>(element).hasPendingActivity()) + return true; + } +#if ENABLE(VIDEO) + else if (is<HTMLAudioElement>(element)) { + if (!downcast<HTMLAudioElement>(element).paused()) + return true; + } +#endif } - #endif // If a node is firing event listeners, its wrapper is observable because // its wrapper is responsible for marking those event listeners. @@ -122,144 +101,155 @@ static inline bool isReachableFromDOM(JSNode* jsNode, Node* node, SlotVisitor& v return true; } - return isObservable(jsNode, node) && visitor.containsOpaqueRoot(root(node)); + return visitor.containsOpaqueRoot(root(node)); } bool JSNodeOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor) { - JSNode* jsNode = jsCast<JSNode*>(handle.get().asCell()); - return isReachableFromDOM(jsNode, &jsNode->impl(), visitor); + JSNode* jsNode = jsCast<JSNode*>(handle.slot()->asCell()); + return isReachableFromDOM(&jsNode->wrapped(), visitor); } -JSValue JSNode::insertBefore(ExecState* exec) +JSValue JSNode::insertBefore(ExecState& state) { - ExceptionCode ec = 0; - bool ok = impl().insertBefore(toNode(exec->argument(0)), toNode(exec->argument(1)), ec); - setDOMException(exec, ec); - if (ok) - return exec->argument(0); - return jsNull(); + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(state.argumentCount() < 2)) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + + JSValue newChildValue = state.uncheckedArgument(0); + auto* newChild = JSNode::toWrapped(vm, newChildValue); + if (UNLIKELY(!newChild)) + return JSValue::decode(throwArgumentTypeError(state, scope, 0, "node", "Node", "insertBefore", "Node")); + + propagateException(state, scope, wrapped().insertBefore(*newChild, JSNode::toWrapped(vm, state.uncheckedArgument(1)))); + return newChildValue; } -JSValue JSNode::replaceChild(ExecState* exec) +JSValue JSNode::replaceChild(ExecState& state) { - ExceptionCode ec = 0; - bool ok = impl().replaceChild(toNode(exec->argument(0)), toNode(exec->argument(1)), ec); - setDOMException(exec, ec); - if (ok) - return exec->argument(1); - return jsNull(); + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(state.argumentCount() < 2)) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + + auto* newChild = JSNode::toWrapped(vm, state.uncheckedArgument(0)); + JSValue oldChildValue = state.uncheckedArgument(1); + auto* oldChild = JSNode::toWrapped(vm, oldChildValue); + if (UNLIKELY(!newChild || !oldChild)) { + if (!newChild) + return JSValue::decode(throwArgumentTypeError(state, scope, 0, "node", "Node", "replaceChild", "Node")); + return JSValue::decode(throwArgumentTypeError(state, scope, 1, "child", "Node", "replaceChild", "Node")); + } + + propagateException(state, scope, wrapped().replaceChild(*newChild, *oldChild)); + return oldChildValue; } -JSValue JSNode::removeChild(ExecState* exec) +JSValue JSNode::removeChild(ExecState& state) { - ExceptionCode ec = 0; - bool ok = impl().removeChild(toNode(exec->argument(0)), ec); - setDOMException(exec, ec); - if (ok) - return exec->argument(0); - return jsNull(); + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSValue childValue = state.argument(0); + auto* child = JSNode::toWrapped(vm, childValue); + if (UNLIKELY(!child)) + return JSValue::decode(throwArgumentTypeError(state, scope, 0, "child", "Node", "removeChild", "Node")); + + propagateException(state, scope, wrapped().removeChild(*child)); + return childValue; } -JSValue JSNode::appendChild(ExecState* exec) +JSValue JSNode::appendChild(ExecState& state) { - ExceptionCode ec = 0; - bool ok = impl().appendChild(toNode(exec->argument(0)), ec); - setDOMException(exec, ec); - if (ok) - return exec->argument(0); - return jsNull(); + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + JSValue newChildValue = state.argument(0); + auto newChild = JSNode::toWrapped(vm, newChildValue); + if (UNLIKELY(!newChild)) + return JSValue::decode(throwArgumentTypeError(state, scope, 0, "node", "Node", "appendChild", "Node")); + + propagateException(state, scope, wrapped().appendChild(*newChild)); + return newChildValue; } JSScope* JSNode::pushEventHandlerScope(ExecState* exec, JSScope* node) const { - if (inherits(JSHTMLElement::info())) + if (inherits(exec->vm(), JSHTMLElement::info())) return jsCast<const JSHTMLElement*>(this)->pushEventHandlerScope(exec, node); return node; } -void JSNode::visitChildren(JSCell* cell, SlotVisitor& visitor) +void JSNode::visitAdditionalChildren(SlotVisitor& visitor) { - JSNode* thisObject = jsCast<JSNode*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(thisObject, visitor); - - Node& node = thisObject->impl(); - node.visitJSEventListeners(visitor); - - visitor.addOpaqueRoot(root(node)); + visitor.addOpaqueRoot(root(wrapped())); } -static ALWAYS_INLINE JSValue createWrapperInline(ExecState* exec, JSDOMGlobalObject* globalObject, Node* node) +static ALWAYS_INLINE JSValue createWrapperInline(ExecState* exec, JSDOMGlobalObject* globalObject, Ref<Node>&& node) { - ASSERT(node); - ASSERT(!getCachedWrapper(currentWorld(exec), node)); + ASSERT(!getCachedWrapper(globalObject->world(), node)); - JSDOMWrapper* wrapper; + JSDOMObject* wrapper; switch (node->nodeType()) { case Node::ELEMENT_NODE: - if (node->isHTMLElement()) - wrapper = createJSHTMLWrapper(exec, globalObject, toHTMLElement(node)); -#if ENABLE(SVG) - else if (node->isSVGElement()) - wrapper = createJSSVGWrapper(exec, globalObject, toSVGElement(node)); -#endif + if (is<HTMLElement>(node.get())) + wrapper = createJSHTMLWrapper(globalObject, static_reference_cast<HTMLElement>(WTFMove(node))); + else if (is<SVGElement>(node.get())) + wrapper = createJSSVGWrapper(globalObject, static_reference_cast<SVGElement>(WTFMove(node))); else - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, Element, node); + wrapper = createWrapper<Element>(globalObject, WTFMove(node)); break; case Node::ATTRIBUTE_NODE: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, Attr, node); + wrapper = createWrapper<Attr>(globalObject, WTFMove(node)); break; case Node::TEXT_NODE: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, Text, node); + wrapper = createWrapper<Text>(globalObject, WTFMove(node)); break; case Node::CDATA_SECTION_NODE: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, CDATASection, node); - break; - case Node::ENTITY_NODE: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, Entity, node); + wrapper = createWrapper<CDATASection>(globalObject, WTFMove(node)); break; case Node::PROCESSING_INSTRUCTION_NODE: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, ProcessingInstruction, node); + wrapper = createWrapper<ProcessingInstruction>(globalObject, WTFMove(node)); break; case Node::COMMENT_NODE: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, Comment, node); + wrapper = createWrapper<Comment>(globalObject, WTFMove(node)); break; case Node::DOCUMENT_NODE: // we don't want to cache the document itself in the per-document dictionary - return toJS(exec, globalObject, toDocument(node)); + return toJS(exec, globalObject, downcast<Document>(node.get())); case Node::DOCUMENT_TYPE_NODE: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, DocumentType, node); - break; - case Node::NOTATION_NODE: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, Notation, node); + wrapper = createWrapper<DocumentType>(globalObject, WTFMove(node)); break; case Node::DOCUMENT_FRAGMENT_NODE: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, DocumentFragment, node); - break; - case Node::ENTITY_REFERENCE_NODE: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, EntityReference, node); + if (node->isShadowRoot()) + wrapper = createWrapper<ShadowRoot>(globalObject, WTFMove(node)); + else + wrapper = createWrapper<DocumentFragment>(globalObject, WTFMove(node)); break; default: - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, Node, node); + wrapper = createWrapper<Node>(globalObject, WTFMove(node)); } - return wrapper; + return wrapper; } -JSValue createWrapper(ExecState* exec, JSDOMGlobalObject* globalObject, Node* node) +JSValue createWrapper(ExecState* exec, JSDOMGlobalObject* globalObject, Ref<Node>&& node) { - return createWrapperInline(exec, globalObject, node); + return createWrapperInline(exec, globalObject, WTFMove(node)); } -JSValue toJSNewlyCreated(ExecState* exec, JSDOMGlobalObject* globalObject, Node* node) +JSValue toJSNewlyCreated(ExecState* exec, JSDOMGlobalObject* globalObject, Ref<Node>&& node) { - if (!node) - return jsNull(); - - return createWrapperInline(exec, globalObject, node); + return createWrapperInline(exec, globalObject, WTFMove(node)); +} + +JSC::JSObject* getOutOfLineCachedWrapper(JSDOMGlobalObject* globalObject, Node& node) +{ + ASSERT(!globalObject->world().isNormal()); + return globalObject->world().m_wrappers.get(&node); } void willCreatePossiblyOrphanedTreeByRemovalSlowCase(Node* root) @@ -269,7 +259,7 @@ void willCreatePossiblyOrphanedTreeByRemovalSlowCase(Node* root) return; JSLockHolder lock(scriptState); - toJS(scriptState, static_cast<JSDOMGlobalObject*>(scriptState->lexicalGlobalObject()), root); + toJS(scriptState, static_cast<JSDOMGlobalObject*>(scriptState->lexicalGlobalObject()), *root); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSNodeCustom.h b/Source/WebCore/bindings/js/JSNodeCustom.h index 2880274ed..6779dad32 100644 --- a/Source/WebCore/bindings/js/JSNodeCustom.h +++ b/Source/WebCore/bindings/js/JSNodeCustom.h @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,26 +23,26 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSNodeCustom_h -#define JSNodeCustom_h +#pragma once #include "JSDOMBinding.h" #include "JSNode.h" -#include "ScriptState.h" #include "ShadowRoot.h" namespace WebCore { -JSC::JSValue createWrapper(JSC::ExecState*, JSDOMGlobalObject*, Node*); +WEBCORE_EXPORT JSC::JSValue createWrapper(JSC::ExecState*, JSDOMGlobalObject*, Ref<Node>&&); +WEBCORE_EXPORT JSC::JSObject* getOutOfLineCachedWrapper(JSDOMGlobalObject*, Node&); -inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, Node* node) +inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, Node& node) { - if (!node) - return JSC::jsNull(); - - JSNode* wrapper = JSC::jsCast<JSNode*>(getCachedWrapper(currentWorld(exec), node)); - if (wrapper) - return wrapper; + if (LIKELY(globalObject->worldIsNormal())) { + if (auto* wrapper = node.wrapper()) + return wrapper; + } else { + if (auto* wrapper = getOutOfLineCachedWrapper(globalObject, node)) + return wrapper; + } return createWrapper(exec, globalObject, node); } @@ -65,12 +65,7 @@ inline void willCreatePossiblyOrphanedTreeByRemoval(Node* root) inline void* root(Node* node) { - if (node->inDocument()) - return &node->document(); - - while (node->parentOrShadowHostNode()) - node = node->parentOrShadowHostNode(); - return node; + return node->opaqueRoot(); } inline void* root(Node& node) @@ -78,6 +73,15 @@ inline void* root(Node& node) return root(&node); } -} // namespace WebCore +template<typename From> +ALWAYS_INLINE JSDynamicCastResult<JSNode, From> jsNodeCast(From* value) +{ + return value->type() >= JSNodeType ? JSC::jsCast<JSDynamicCastResult<JSNode, From>>(value) : nullptr; +} -#endif // JSDOMNodeCustom_h +ALWAYS_INLINE JSC::JSValue JSNode::nodeType(JSC::ExecState&) const +{ + return JSC::jsNumber(static_cast<uint8_t>(type()) & JSNodeTypeMask); +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSNodeFilterCondition.cpp b/Source/WebCore/bindings/js/JSNodeFilterCondition.cpp deleted file mode 100644 index d1b472135..000000000 --- a/Source/WebCore/bindings/js/JSNodeFilterCondition.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include "JSNodeFilterCondition.h" - -#include "JSMainThreadExecState.h" -#include "JSNode.h" -#include "JSNodeFilter.h" -#include "NodeFilter.h" -#include <runtime/Error.h> -#include <runtime/JSLock.h> - -namespace WebCore { - -using namespace JSC; - -JSNodeFilterCondition::JSNodeFilterCondition(VM&, NodeFilter* owner, JSValue filter) - : m_filter(filter.isObject() ? Weak<JSObject>(jsCast<JSObject*>(filter), &m_weakOwner, owner) : nullptr) -{ -} - -short JSNodeFilterCondition::acceptNode(JSC::ExecState* exec, Node* filterNode) const -{ - JSLockHolder lock(exec); - - if (!m_filter) - return NodeFilter::FILTER_ACCEPT; - - // Exec is null if we've been called from a non-JavaScript language and the document - // is no longer able to run JavaScript (e.g., it's disconnected from its frame). - if (!exec) - return NodeFilter::FILTER_REJECT; - - JSValue filter = m_filter.get(); - CallData callData; - CallType callType = getCallData(filter, callData); - if (callType == CallTypeNone) { - filter = filter.get(exec, Identifier(exec, "acceptNode")); - callType = getCallData(filter, callData); - if (callType == CallTypeNone) { - exec->vm().throwException(exec, createTypeError(exec, "NodeFilter object does not have an acceptNode function")); - return NodeFilter::FILTER_REJECT; - } - } - - MarkedArgumentBuffer args; - // FIXME: The node should have the prototype chain that came from its document, not - // whatever prototype chain might be on the window this filter came from. Bug 27662 - args.append(toJS(exec, deprecatedGlobalObjectForPrototype(exec), filterNode)); - if (exec->hadException()) - return NodeFilter::FILTER_REJECT; - - JSValue result = JSMainThreadExecState::call(exec, filter, callType, callData, m_filter.get(), args); - if (exec->hadException()) - return NodeFilter::FILTER_REJECT; - - int intResult = result.toInt32(exec); - if (exec->hadException()) - return NodeFilter::FILTER_REJECT; - - return intResult; -} - -bool JSNodeFilterCondition::WeakOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, SlotVisitor& visitor) -{ - return visitor.containsOpaqueRoot(context); -} - -} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSNodeFilterCondition.h b/Source/WebCore/bindings/js/JSNodeFilterCondition.h deleted file mode 100644 index 3b175815a..000000000 --- a/Source/WebCore/bindings/js/JSNodeFilterCondition.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef JSNodeFilterCondition_h -#define JSNodeFilterCondition_h - -#include "NodeFilterCondition.h" -#include <heap/Weak.h> -#include <heap/WeakInlines.h> -#include <runtime/JSCJSValue.h> -#include <runtime/Operations.h> -#include <wtf/PassRefPtr.h> - -namespace WebCore { - - class Node; - class NodeFilter; - - class JSNodeFilterCondition : public NodeFilterCondition { - public: - static PassRefPtr<JSNodeFilterCondition> create(JSC::VM& vm, NodeFilter* owner, JSC::JSValue filter) - { - return adoptRef(new JSNodeFilterCondition(vm, owner, filter)); - } - - private: - JSNodeFilterCondition(JSC::VM&, NodeFilter* owner, JSC::JSValue filter); - - virtual short acceptNode(JSC::ExecState*, Node*) const; - - class WeakOwner : public JSC::WeakHandleOwner { - virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&); - }; - WeakOwner m_weakOwner; - mutable JSC::Weak<JSC::JSObject> m_filter; - }; - -} // namespace WebCore - -#endif // JSNodeFilterCondition_h diff --git a/Source/WebCore/bindings/js/JSNodeFilterCustom.cpp b/Source/WebCore/bindings/js/JSNodeFilterCustom.cpp index 877c98543..fd3089b53 100644 --- a/Source/WebCore/bindings/js/JSNodeFilterCustom.cpp +++ b/Source/WebCore/bindings/js/JSNodeFilterCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2015-2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,50 +10,61 @@ * 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 COMPUTER, INC. ``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 COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 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 "JSNodeFilter.h" -#include "JSDOMWindowBase.h" +#include "JSCallbackData.h" +#include "JSDOMConvert.h" #include "JSNode.h" -#include "JSNodeFilterCondition.h" #include "NodeFilter.h" -#include "JSDOMBinding.h" - -using namespace JSC; namespace WebCore { -void JSNodeFilter::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - JSNodeFilter* thisObject = jsCast<JSNodeFilter*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(thisObject, visitor); - visitor.addOpaqueRoot(&thisObject->impl()); -} +using namespace JSC; -PassRefPtr<NodeFilter> toNodeFilter(VM& vm, JSValue value) +// FIXME: The bindings generator is currently not able to generate +// callback function calls if they return something other than a +// boolean. +uint16_t JSNodeFilter::acceptNode(Node* node) { - if (value.inherits(JSNodeFilter::info())) - return &jsCast<JSNodeFilter*>(asObject(value))->impl(); + Ref<JSNodeFilter> protectedThis(*this); + + VM& vm = m_data->globalObject()->vm(); + JSLockHolder lock(vm); + auto scope = DECLARE_THROW_SCOPE(vm); + + ExecState* state = m_data->globalObject()->globalExec(); + MarkedArgumentBuffer args; + args.append(toJS(state, m_data->globalObject(), node)); + RETURN_IF_EXCEPTION(scope, NodeFilter::FILTER_REJECT); + + NakedPtr<JSC::Exception> returnedException; + JSValue value = m_data->invokeCallback(args, JSCallbackData::CallbackType::FunctionOrObject, Identifier::fromString(state, "acceptNode"), returnedException); + ASSERT(!scope.exception() || returnedException); + if (returnedException) { + // Rethrow exception. + throwException(state, scope, returnedException); + + return NodeFilter::FILTER_REJECT; + } + + auto result = convert<IDLUnsignedShort>(*state, value, IntegerConversionConfiguration::Normal); + RETURN_IF_EXCEPTION(scope, NodeFilter::FILTER_REJECT); - RefPtr<NodeFilter> result = NodeFilter::create(); - result->setCondition(JSNodeFilterCondition::create(vm, result.get(), value)); - return result.release(); + return result; } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSNodeIteratorCustom.cpp b/Source/WebCore/bindings/js/JSNodeIteratorCustom.cpp index 49cde01cc..b3f036139 100644 --- a/Source/WebCore/bindings/js/JSNodeIteratorCustom.cpp +++ b/Source/WebCore/bindings/js/JSNodeIteratorCustom.cpp @@ -20,24 +20,14 @@ #include "config.h" #include "JSNodeIterator.h" -#include "JSNode.h" #include "Node.h" -#include "NodeFilter.h" -#include "NodeIterator.h" - -using namespace JSC; +#include <heap/SlotVisitorInlines.h> namespace WebCore { -void JSNodeIterator::visitChildren(JSCell* cell, SlotVisitor& visitor) +void JSNodeIterator::visitAdditionalChildren(JSC::SlotVisitor& visitor) { - JSNodeIterator* thisObject = jsCast<JSNodeIterator*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(thisObject, visitor); - - if (NodeFilter* filter = thisObject->m_impl->filter()) + if (NodeFilter* filter = wrapped().filter()) visitor.addOpaqueRoot(filter); } diff --git a/Source/WebCore/bindings/js/JSNodeListCustom.cpp b/Source/WebCore/bindings/js/JSNodeListCustom.cpp index a58d980ef..513bbdfda 100644 --- a/Source/WebCore/bindings/js/JSNodeListCustom.cpp +++ b/Source/WebCore/bindings/js/JSNodeListCustom.cpp @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -39,25 +39,29 @@ namespace WebCore { bool JSNodeListOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor) { - JSNodeList* jsNodeList = jsCast<JSNodeList*>(handle.get().asCell()); + JSNodeList* jsNodeList = jsCast<JSNodeList*>(handle.slot()->asCell()); if (!jsNodeList->hasCustomProperties()) return false; - if (jsNodeList->impl().isLiveNodeList()) - return visitor.containsOpaqueRoot(root(static_cast<LiveNodeList&>(jsNodeList->impl()).ownerNode())); - if (jsNodeList->impl().isChildNodeList()) - return visitor.containsOpaqueRoot(root(static_cast<ChildNodeList&>(jsNodeList->impl()).ownerNode())); - if (jsNodeList->impl().isEmptyNodeList()) - return visitor.containsOpaqueRoot(root(static_cast<EmptyNodeList&>(jsNodeList->impl()).ownerNode())); + if (jsNodeList->wrapped().isLiveNodeList()) + return visitor.containsOpaqueRoot(root(static_cast<LiveNodeList&>(jsNodeList->wrapped()).ownerNode())); + if (jsNodeList->wrapped().isChildNodeList()) + return visitor.containsOpaqueRoot(root(static_cast<ChildNodeList&>(jsNodeList->wrapped()).ownerNode())); + if (jsNodeList->wrapped().isEmptyNodeList()) + return visitor.containsOpaqueRoot(root(static_cast<EmptyNodeList&>(jsNodeList->wrapped()).ownerNode())); return false; } -bool JSNodeList::getOwnPropertySlotDelegate(ExecState* exec, PropertyName propertyName, PropertySlot& slot) +JSC::JSValue createWrapper(JSDOMGlobalObject& globalObject, Ref<NodeList>&& nodeList) { - if (Node* item = impl().namedItem(propertyNameToAtomicString(propertyName))) { - slot.setValue(this, ReadOnly | DontDelete | DontEnum, toJS(exec, globalObject(), item)); - return true; - } - return false; + // FIXME: Adopt reportExtraMemoryVisited, and switch to reportExtraMemoryAllocated. + // https://bugs.webkit.org/show_bug.cgi?id=142595 + globalObject.vm().heap.deprecatedReportExtraMemory(nodeList->memoryCost()); + return createWrapper<NodeList>(&globalObject, WTFMove(nodeList)); +} + +JSC::JSValue toJSNewlyCreated(ExecState*, JSDOMGlobalObject* globalObject, Ref<NodeList>&& nodeList) +{ + return createWrapper(*globalObject, WTFMove(nodeList)); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSNodeListCustom.h b/Source/WebCore/bindings/js/JSNodeListCustom.h new file mode 100644 index 000000000..845bb409a --- /dev/null +++ b/Source/WebCore/bindings/js/JSNodeListCustom.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014 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. ``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 + * 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. + */ + +#pragma once + +#include "JSDOMBinding.h" +#include "JSNodeList.h" + +namespace WebCore { + +WEBCORE_EXPORT JSC::JSValue createWrapper(JSDOMGlobalObject&, Ref<NodeList>&&); + +ALWAYS_INLINE JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject* globalObject, NodeList& nodeList) +{ + if (auto wrapper = getCachedWrapper(globalObject->world(), nodeList)) + return wrapper; + return createWrapper(*globalObject, nodeList); +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSOscillatorNodeCustom.cpp b/Source/WebCore/bindings/js/JSOscillatorNodeCustom.cpp deleted file mode 100644 index f44625c0f..000000000 --- a/Source/WebCore/bindings/js/JSOscillatorNodeCustom.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2012, 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. - */ - -#include "config.h" - -#if ENABLE(WEB_AUDIO) - -#include "JSOscillatorNode.h" - -#include "ExceptionCode.h" -#include "OscillatorNode.h" -#include <runtime/Error.h> - -using namespace JSC; - -namespace WebCore { - -void JSOscillatorNode::setType(ExecState* exec, JSValue value) -{ - OscillatorNode& imp = impl(); - -#if ENABLE(LEGACY_WEB_AUDIO) - if (value.isNumber()) { - uint32_t type = value.toUInt32(exec); - if (!imp.setType(type)) - exec->vm().throwException(exec, createTypeError(exec, "Illegal OscillatorNode type")); - return; - } -#endif - - if (value.isString()) { - String type = value.toString(exec)->value(exec); - if (type == "sine" || type == "square" || type == "sawtooth" || type == "triangle") { - imp.setType(type); - return; - } - } - - exec->vm().throwException(exec, createTypeError(exec, "Illegal OscillatorNode type")); -} - -} // namespace WebCore - -#endif // ENABLE(WEB_AUDIO) diff --git a/Source/WebCore/bindings/js/JSPannerNodeCustom.cpp b/Source/WebCore/bindings/js/JSPannerNodeCustom.cpp deleted file mode 100644 index f28978520..000000000 --- a/Source/WebCore/bindings/js/JSPannerNodeCustom.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2012, 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. - */ - -#include "config.h" - -#if ENABLE(WEB_AUDIO) - -#include "JSPannerNode.h" - -#include "ExceptionCode.h" -#include "PannerNode.h" -#include <runtime/Error.h> - -using namespace JSC; - -namespace WebCore { - -void JSPannerNode::setPanningModel(ExecState* exec, JSValue value) -{ - PannerNode& imp = impl(); - -#if ENABLE(LEGACY_WEB_AUDIO) - if (value.isNumber()) { - uint32_t model = value.toUInt32(exec); - if (!imp.setPanningModel(model)) - exec->vm().throwException(exec, createTypeError(exec, "Illegal panningModel")); - return; - } -#endif - - if (value.isString()) { - String model = value.toString(exec)->value(exec); - if (model == "equalpower" || model == "HRTF" || model == "soundfield") { - imp.setPanningModel(model); - return; - } - } - - exec->vm().throwException(exec, createTypeError(exec, "Illegal panningModel")); -} - -void JSPannerNode::setDistanceModel(ExecState* exec, JSValue value) -{ - PannerNode& imp = impl(); - -#if ENABLE(LEGACY_WEB_AUDIO) - if (value.isNumber()) { - uint32_t model = value.toUInt32(exec); - if (!imp.setDistanceModel(model)) - exec->vm().throwException(exec, createTypeError(exec, "Illegal distanceModel")); - return; - } -#endif - - if (value.isString()) { - String model = value.toString(exec)->value(exec); - if (model == "linear" || model == "inverse" || model == "exponential") { - imp.setDistanceModel(model); - return; - } - } - - exec->vm().throwException(exec, createTypeError(exec, "Illegal distanceModel")); -} - -} // namespace WebCore - -#endif // ENABLE(WEB_AUDIO) diff --git a/Source/WebCore/bindings/js/JSPerformanceEntryCustom.cpp b/Source/WebCore/bindings/js/JSPerformanceEntryCustom.cpp index 0b6f98ce1..471897834 100644 --- a/Source/WebCore/bindings/js/JSPerformanceEntryCustom.cpp +++ b/Source/WebCore/bindings/js/JSPerformanceEntryCustom.cpp @@ -30,7 +30,7 @@ #include "config.h" -#if ENABLE(PERFORMANCE_TIMELINE) +#if ENABLE(WEB_TIMING) #include "JSPerformanceEntry.h" @@ -46,27 +46,25 @@ using namespace JSC; namespace WebCore { -JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, PerformanceEntry* entry) +JSValue toJSNewlyCreated(ExecState*, JSDOMGlobalObject* globalObject, Ref<PerformanceEntry>&& entry) { - if (!entry) - return jsNull(); + if (is<PerformanceResourceTiming>(entry)) + return createWrapper<PerformanceResourceTiming>(globalObject, WTFMove(entry)); -#if ENABLE(RESOURCE_TIMING) - if (entry->isResource()) - return wrap<JSPerformanceResourceTiming>(exec, globalObject, static_cast<PerformanceResourceTiming*>(entry)); -#endif + if (is<PerformanceMark>(entry)) + return createWrapper<PerformanceMark>(globalObject, WTFMove(entry)); -#if ENABLE(USER_TIMING) - if (entry->isMark()) - return wrap<JSPerformanceMark>(exec, globalObject, static_cast<PerformanceMark*>(entry)); + if (is<PerformanceMeasure>(entry)) + return createWrapper<PerformanceMeasure>(globalObject, WTFMove(entry)); - if (entry->isMeasure()) - return wrap<JSPerformanceMeasure>(exec, globalObject, static_cast<PerformanceMeasure*>(entry)); -#endif + return createWrapper<PerformanceEntry>(globalObject, WTFMove(entry)); +} - return wrap<JSPerformanceEntry>(exec, globalObject, entry); +JSValue toJS(JSC::ExecState* state, JSDOMGlobalObject* globalObject, PerformanceEntry& entry) +{ + return wrap(state, globalObject, entry); } } // namespace WebCore -#endif // ENABLE(PERFORMANCE_TIMELINE) +#endif // ENABLE(WEB_TIMING) diff --git a/Source/WebCore/bindings/js/JSPluginElementFunctions.cpp b/Source/WebCore/bindings/js/JSPluginElementFunctions.cpp index 7f62aa2a7..88b5b123a 100644 --- a/Source/WebCore/bindings/js/JSPluginElementFunctions.cpp +++ b/Source/WebCore/bindings/js/JSPluginElementFunctions.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) - * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2004-2017 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -35,77 +35,73 @@ using namespace HTMLNames; // JavaScript access to plug-in-exported properties for JSHTMLAppletElement, JSHTMLEmbedElement and JSHTMLObjectElement. -static inline bool isPluginElement(HTMLElement& element) -{ - return element.hasTagName(objectTag) || element.hasTagName(embedTag) || element.hasTagName(appletTag); -} - Instance* pluginInstance(HTMLElement& element) { // The plugin element holds an owning reference, so we don't have to. - if (!isPluginElement(element)) - return 0; - Instance* instance = toHTMLPlugInElement(element).getInstance().get(); + if (!is<HTMLPlugInElement>(element)) + return nullptr; + auto* instance = downcast<HTMLPlugInElement>(element).bindingsInstance(); if (!instance || !instance->rootObject()) - return 0; + return nullptr; return instance; } static JSObject* pluginScriptObjectFromPluginViewBase(HTMLPlugInElement& pluginElement, JSGlobalObject* globalObject) { Widget* pluginWidget = pluginElement.pluginWidget(); - if (!pluginWidget) - return 0; - - if (!pluginWidget->isPluginViewBase()) - return 0; + if (!is<PluginViewBase>(pluginWidget)) + return nullptr; - PluginViewBase* pluginViewBase = toPluginViewBase(pluginWidget); - return pluginViewBase->scriptObject(globalObject); + return downcast<PluginViewBase>(*pluginWidget).scriptObject(globalObject); } static JSObject* pluginScriptObjectFromPluginViewBase(JSHTMLElement* jsHTMLElement) { - HTMLElement& element = jsHTMLElement->impl(); - if (!isPluginElement(element)) - return 0; + HTMLElement& element = jsHTMLElement->wrapped(); + if (!is<HTMLPlugInElement>(element)) + return nullptr; - HTMLPlugInElement& pluginElement = toHTMLPlugInElement(element); + HTMLPlugInElement& pluginElement = downcast<HTMLPlugInElement>(element); return pluginScriptObjectFromPluginViewBase(pluginElement, jsHTMLElement->globalObject()); } JSObject* pluginScriptObject(ExecState* exec, JSHTMLElement* jsHTMLElement) { - HTMLElement& element = jsHTMLElement->impl(); - if (!isPluginElement(element)) - return 0; + HTMLElement& element = jsHTMLElement->wrapped(); + if (!is<HTMLPlugInElement>(element)) + return nullptr; + + auto& pluginElement = downcast<HTMLPlugInElement>(element); - HTMLPlugInElement& pluginElement = toHTMLPlugInElement(element); + // Choke point for script/plugin interaction; notify DOMTimer of the event. + DOMTimer::scriptDidInteractWithPlugin(pluginElement); // First, see if the element has a plug-in replacement with a script. - if (JSObject* scriptObject = pluginElement.scriptObjectForPluginReplacement()) + if (auto* scriptObject = pluginElement.scriptObjectForPluginReplacement()) return scriptObject; // Next, see if we can ask the plug-in view for its script object. - if (JSObject* scriptObject = pluginScriptObjectFromPluginViewBase(pluginElement, jsHTMLElement->globalObject())) + if (auto* scriptObject = pluginScriptObjectFromPluginViewBase(pluginElement, jsHTMLElement->globalObject())) return scriptObject; // Otherwise, fall back to getting the object from the instance. // The plugin element holds an owning reference, so we don't have to. - Instance* instance = pluginElement.getInstance().get(); + auto* instance = pluginElement.bindingsInstance(); if (!instance || !instance->rootObject()) - return 0; + return nullptr; return instance->createRuntimeObject(exec); } -EncodedJSValue pluginElementPropertyGetter(ExecState* exec, EncodedJSValue, EncodedJSValue thisValue, PropertyName propertyName) +EncodedJSValue pluginElementPropertyGetter(ExecState* exec, EncodedJSValue thisValue, PropertyName propertyName) { + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); - JSHTMLElement* thisObject = jsDynamicCast<JSHTMLElement*>(JSValue::decode(thisValue)); + JSHTMLElement* thisObject = jsDynamicDowncast<JSHTMLElement*>(vm, JSValue::decode(thisValue)); if (!thisObject) - return throwVMTypeError(exec); + return throwVMTypeError(exec, scope); JSObject* scriptObject = pluginScriptObject(exec, thisObject); if (!scriptObject) return JSValue::encode(jsUndefined()); @@ -125,20 +121,20 @@ bool pluginElementCustomGetOwnPropertySlot(ExecState* exec, PropertyName propert return true; } -bool pluginElementCustomPut(ExecState* exec, PropertyName propertyName, JSValue value, JSHTMLElement* element, PutPropertySlot& slot) +bool pluginElementCustomPut(ExecState* exec, PropertyName propertyName, JSValue value, JSHTMLElement* element, PutPropertySlot& slot, bool& putResult) { JSObject* scriptObject = pluginScriptObject(exec, element); if (!scriptObject) - return 0; + return false; if (!scriptObject->hasProperty(exec, propertyName)) return false; - scriptObject->methodTable()->put(scriptObject, exec, propertyName, value, slot); + putResult = scriptObject->methodTable()->put(scriptObject, exec, propertyName, value, slot); return true; } static EncodedJSValue JSC_HOST_CALL callPlugin(ExecState* exec) { - JSHTMLElement* element = jsCast<JSHTMLElement*>(exec->callee()); + JSHTMLElement* element = jsCast<JSHTMLElement*>(exec->jsCallee()); // Get the plug-in script object. JSObject* scriptObject = pluginScriptObject(exec, element); @@ -151,10 +147,10 @@ static EncodedJSValue JSC_HOST_CALL callPlugin(ExecState* exec) CallData callData; CallType callType = getCallData(scriptObject, callData); - ASSERT(callType == CallTypeHost); + ASSERT(callType == CallType::Host); // Call the object. - JSValue result = call(exec, scriptObject, callType, callData, exec->hostThisValue(), argumentList); + JSValue result = call(exec, scriptObject, callType, callData, exec->thisValue(), argumentList); return JSValue::encode(result); } @@ -164,18 +160,18 @@ CallType pluginElementGetCallData(JSHTMLElement* element, CallData& callData) if (JSObject* scriptObject = pluginScriptObjectFromPluginViewBase(element)) { CallData scriptObjectCallData; - if (scriptObject->methodTable()->getCallData(scriptObject, scriptObjectCallData) == CallTypeNone) - return CallTypeNone; + if (scriptObject->methodTable()->getCallData(scriptObject, scriptObjectCallData) == CallType::None) + return CallType::None; callData.native.function = callPlugin; - return CallTypeHost; + return CallType::Host; } - Instance* instance = pluginInstance(element->impl()); + Instance* instance = pluginInstance(element->wrapped()); if (!instance || !instance->supportsInvokeDefaultMethod()) - return CallTypeNone; + return CallType::None; callData.native.function = callPlugin; - return CallTypeHost; + return CallType::Host; } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSPluginElementFunctions.h b/Source/WebCore/bindings/js/JSPluginElementFunctions.h index 8a2e99d59..f4f5f4ca9 100644 --- a/Source/WebCore/bindings/js/JSPluginElementFunctions.h +++ b/Source/WebCore/bindings/js/JSPluginElementFunctions.h @@ -17,8 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef JSPluginElementFunctions_h -#define JSPluginElementFunctions_h +#pragma once #include "JSDOMBinding.h" @@ -36,27 +35,22 @@ namespace WebCore { // JavaScript access to plug-in-exported properties for JSHTMLAppletElement, JSHTMLEmbedElement and JSHTMLObjectElement. JSC::Bindings::Instance* pluginInstance(HTMLElement&); - JSC::JSObject* pluginScriptObject(JSC::ExecState*, JSHTMLElement*); + WEBCORE_EXPORT JSC::JSObject* pluginScriptObject(JSC::ExecState*, JSHTMLElement*); - JSC::EncodedJSValue pluginElementPropertyGetter(JSC::ExecState*, JSC::EncodedJSValue, JSC::EncodedJSValue, JSC::PropertyName); + JSC::EncodedJSValue pluginElementPropertyGetter(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName); bool pluginElementCustomGetOwnPropertySlot(JSC::ExecState*, JSC::PropertyName, JSC::PropertySlot&, JSHTMLElement*); - bool pluginElementCustomPut(JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSHTMLElement*, JSC::PutPropertySlot&); + bool pluginElementCustomPut(JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSHTMLElement*, JSC::PutPropertySlot&, bool& putResult); JSC::CallType pluginElementGetCallData(JSHTMLElement*, JSC::CallData&); template <class Type, class Base> bool pluginElementCustomGetOwnPropertySlot(JSC::ExecState* exec, JSC::PropertyName propertyName, JSC::PropertySlot& slot, Type* element) { if (!element->globalObject()->world().isNormal()) { - if (JSC::getStaticValueSlot<Type, Base>(exec, *Type::info()->staticPropHashTable, element, propertyName, slot)) - return true; - - JSC::JSValue proto = element->prototype(); + JSC::JSValue proto = element->getPrototypeDirect(); if (proto.isObject() && JSC::jsCast<JSC::JSObject*>(asObject(proto))->hasProperty(exec, propertyName)) return false; } - + return pluginElementCustomGetOwnPropertySlot(exec, propertyName, slot, element); } } // namespace WebCore - -#endif // JSPluginElementFunctions_h diff --git a/Source/WebCore/bindings/js/JSPopStateEventCustom.cpp b/Source/WebCore/bindings/js/JSPopStateEventCustom.cpp index e4d46f792..aadb860a3 100644 --- a/Source/WebCore/bindings/js/JSPopStateEventCustom.cpp +++ b/Source/WebCore/bindings/js/JSPopStateEventCustom.cpp @@ -29,36 +29,51 @@ */ #include "config.h" +#include "JSPopStateEvent.h" -#include "History.h" +#include "DOMWrapperWorld.h" #include "JSHistory.h" -#include "JSPopStateEvent.h" +#include <heap/HeapInlines.h> +#include <runtime/JSCJSValueInlines.h> using namespace JSC; namespace WebCore { // Save the state value to the m_state member of a JSPopStateEvent, and return it, for convenience. -static const JSValue& cacheState(ExecState* exec, JSPopStateEvent* event, const JSValue& state) +static const JSValue& cacheState(ExecState& state, const JSPopStateEvent* event, const JSValue& eventState) { - event->m_state.set(exec->vm(), event, state); - return state; + event->m_state.set(state.vm(), event, eventState); + return eventState; } -JSValue JSPopStateEvent::state(ExecState* exec) const +JSValue JSPopStateEvent::state(ExecState& state) const { JSValue cachedValue = m_state.get(); - if (!cachedValue.isEmpty()) - return cachedValue; - - PopStateEvent& event = impl(); + if (!cachedValue.isEmpty()) { + // We cannot use a cached object if we are in a different world than the one it was created in. + if (!cachedValue.isObject() || &worldForDOMObject(cachedValue.getObject()) == ¤tWorld(&state)) + return cachedValue; + ASSERT_NOT_REACHED(); + } - if (!event.state().hasNoValue()) - return cacheState(exec, const_cast<JSPopStateEvent*>(this), event.state().jsValue()); + PopStateEvent& event = wrapped(); + if (auto eventState = event.state()) { + // We need to make sure a PopStateEvent does not leak objects in its state property across isolated DOM worlds. + // Ideally, we would check that the worlds have different privileges but that's not possible yet. + if (eventState.isObject() && &worldForDOMObject(eventState.getObject()) != ¤tWorld(&state)) { + if (auto serializedValue = event.trySerializeState(state)) + eventState = serializedValue->deserialize(state, globalObject()); + else + eventState = jsNull(); + } + return cacheState(state, this, eventState); + } + History* history = event.history(); if (!history || !event.serializedState()) - return cacheState(exec, const_cast<JSPopStateEvent*>(this), jsNull()); + return cacheState(state, this, jsNull()); // There's no cached value from a previous invocation, nor a state value was provided by the // event, but there is a history object, so first we need to see if the state object has been @@ -66,16 +81,16 @@ JSValue JSPopStateEvent::state(ExecState* exec) const // The current history state object might've changed in the meantime, so we need to take care // of using the correct one, and always share the same deserialization with history.state. - bool isSameState = history->isSameAsCurrentState(event.serializedState().get()); + bool isSameState = history->isSameAsCurrentState(event.serializedState()); JSValue result; if (isSameState) { - JSHistory* jsHistory = jsCast<JSHistory*>(toJS(exec, globalObject(), history).asCell()); - result = jsHistory->state(exec); + JSHistory* jsHistory = jsCast<JSHistory*>(toJS(&state, globalObject(), *history).asCell()); + result = jsHistory->state(state); } else - result = event.serializedState()->deserialize(exec, globalObject(), 0); + result = event.serializedState()->deserialize(state, globalObject()); - return cacheState(exec, const_cast<JSPopStateEvent*>(this), result); + return cacheState(state, this, result); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSRTCIceCandidateCustom.cpp b/Source/WebCore/bindings/js/JSRTCIceCandidateCustom.cpp deleted file mode 100644 index 148ff1154..000000000 --- a/Source/WebCore/bindings/js/JSRTCIceCandidateCustom.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). - * - * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#if ENABLE(MEDIA_STREAM) - -#include "JSRTCIceCandidate.h" - -#include "Dictionary.h" -#include "ExceptionCode.h" - -using namespace JSC; - -namespace WebCore { - -EncodedJSValue JSC_HOST_CALL JSRTCIceCandidateConstructor::constructJSRTCIceCandidate(ExecState* exec) -{ - ExceptionCode ec = 0; - Dictionary sessionInit; - if (exec->argumentCount() > 0) { - sessionInit = Dictionary(exec, exec->argument(0)); - if (!sessionInit.isObject()) - return throwVMError(exec, createTypeError(exec, "Optional RTCIceCandidate constructor argument must be a valid Dictionary")); - - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - } - - JSRTCIceCandidateConstructor* jsConstructor = jsCast<JSRTCIceCandidateConstructor*>(exec->callee()); - RefPtr<RTCIceCandidate> iceCandidate = RTCIceCandidate::create(sessionInit, ec); - if (ec == TYPE_MISMATCH_ERR) { - setDOMException(exec, ec); - return throwVMError(exec, createTypeError(exec, "Invalid RTCIceCandidate constructor arguments")); - } - - if (ec) { - setDOMException(exec, ec); - return throwVMError(exec, createTypeError(exec, "Error creating RTCIceCandidate")); - } - - return JSValue::encode(CREATE_DOM_WRAPPER(exec, jsConstructor->globalObject(), RTCIceCandidate, iceCandidate.get())); -} - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) - diff --git a/Source/WebCore/bindings/js/JSRTCPeerConnectionCustom.cpp b/Source/WebCore/bindings/js/JSRTCPeerConnectionCustom.cpp deleted file mode 100644 index f24bec22a..000000000 --- a/Source/WebCore/bindings/js/JSRTCPeerConnectionCustom.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). - * - * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#if ENABLE(MEDIA_STREAM) - -#include "JSRTCPeerConnection.h" - -#include "ExceptionCode.h" - -using namespace JSC; - -namespace WebCore { - -EncodedJSValue JSC_HOST_CALL JSRTCPeerConnectionConstructor::constructJSRTCPeerConnection(ExecState* exec) -{ - // Spec says that we must have at least one arument, the RTCConfiguration. - if (exec->argumentCount() < 1) - return throwVMError(exec, createNotEnoughArgumentsError(exec)); - - ExceptionCode ec = 0; - Dictionary rtcConfiguration(exec, exec->argument(0)); - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - - if (!rtcConfiguration.isObject()) - return throwVMError(exec, createTypeError(exec, "First argument of RTCPeerConnection must be a valid Dictionary")); - - Dictionary mediaConstraints; - if (exec->argumentCount() > 1) { - mediaConstraints = Dictionary(exec, exec->argument(1)); - if (!mediaConstraints.isObject()) - return throwVMError(exec, createTypeError(exec, "Optional constraints argument of RTCPeerConnection must be a valid Dictionary")); - - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - } - - JSRTCPeerConnectionConstructor* jsConstructor = jsCast<JSRTCPeerConnectionConstructor*>(exec->callee()); - ScriptExecutionContext* scriptExecutionContext = jsConstructor->scriptExecutionContext(); - if (!scriptExecutionContext) - return throwVMError(exec, createReferenceError(exec, "RTCPeerConnection constructor associated document is unavailable")); - - RefPtr<RTCPeerConnection> peerConnection = RTCPeerConnection::create(*scriptExecutionContext, rtcConfiguration, mediaConstraints, ec); - if (ec == TYPE_MISMATCH_ERR) { - setDOMException(exec, ec); - return throwVMError(exec, createTypeError(exec, "Invalid RTCPeerConnection constructor arguments")); - } - - if (ec) { - setDOMException(exec, ec); - return throwVMError(exec, createTypeError(exec, "Error creating RTCPeerConnection")); - } - - return JSValue::encode(CREATE_DOM_WRAPPER(exec, jsConstructor->globalObject(), RTCPeerConnection, peerConnection.get())); -} - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) diff --git a/Source/WebCore/bindings/js/JSRTCSessionDescriptionCustom.cpp b/Source/WebCore/bindings/js/JSRTCSessionDescriptionCustom.cpp deleted file mode 100644 index ddf03f3e7..000000000 --- a/Source/WebCore/bindings/js/JSRTCSessionDescriptionCustom.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies). - * - * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#if ENABLE(MEDIA_STREAM) - -#include "JSRTCSessionDescription.h" - -#include "Dictionary.h" -#include "ExceptionCode.h" - -using namespace JSC; - -namespace WebCore { - -EncodedJSValue JSC_HOST_CALL JSRTCSessionDescriptionConstructor::constructJSRTCSessionDescription(ExecState* exec) -{ - ExceptionCode ec = 0; - Dictionary sessionInit; - if (exec->argumentCount() > 0) { - sessionInit = Dictionary(exec, exec->argument(0)); - if (!sessionInit.isObject()) - return throwVMError(exec, createTypeError(exec, "Optional RTCSessionDescription constructor argument must be a valid Dictionary")); - - if (exec->hadException()) - return JSValue::encode(jsUndefined()); - } - - JSRTCSessionDescriptionConstructor* jsConstructor = jsCast<JSRTCSessionDescriptionConstructor*>(exec->callee()); - RefPtr<RTCSessionDescription> sessionDescription = RTCSessionDescription::create(sessionInit, ec); - if (ec == TYPE_MISMATCH_ERR) { - setDOMException(exec, ec); - return throwVMError(exec, createTypeError(exec, "Invalid RTCSessionDescription constructor arguments")); - } - - if (ec) { - setDOMException(exec, ec); - return throwVMError(exec, createTypeError(exec, "Error creating RTCSessionDescription")); - } - - return JSValue::encode(CREATE_DOM_WRAPPER(exec, jsConstructor->globalObject(), RTCSessionDescription, sessionDescription.get())); -} - -} // namespace WebCore - -#endif // ENABLE(MEDIA_STREAM) - diff --git a/Source/WebCore/bindings/js/JSReadableStreamPrivateConstructors.cpp b/Source/WebCore/bindings/js/JSReadableStreamPrivateConstructors.cpp new file mode 100644 index 000000000..984cfc315 --- /dev/null +++ b/Source/WebCore/bindings/js/JSReadableStreamPrivateConstructors.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2015 Canon Inc. All rights reserved. + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "JSReadableStreamPrivateConstructors.h" + +#if ENABLE(READABLE_STREAM_API) + +#include "JSDOMBuiltinConstructor.h" +#include "JSReadableByteStreamController.h" +#include "JSReadableStream.h" +#include "JSReadableStreamDefaultController.h" +#include "JSReadableStreamDefaultReader.h" +#include "ReadableByteStreamInternalsBuiltins.h" +#include "ReadableStreamInternalsBuiltins.h" +#include "WebCoreJSClientData.h" +#include <runtime/JSCInlines.h> + +using namespace JSC; + +namespace WebCore { + +// Public JS ReadableStreamReader and ReadableStreamDefaultController constructor callbacks. +EncodedJSValue JSC_HOST_CALL constructJSReadableStreamDefaultController(ExecState& exec) +{ + VM& vm = exec.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(&exec, scope, ASCIILiteral("ReadableStreamDefaultController constructor should not be called directly")); +} + +#if ENABLE(READABLE_BYTE_STREAM_API) +// Public JS ReadableByteStreamController constructor callback. +EncodedJSValue JSC_HOST_CALL constructJSReadableByteStreamController(ExecState& exec) +{ + VM& vm = exec.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + return throwVMTypeError(&exec, scope, ASCIILiteral("ReadableByteStreamController constructor should not be called directly")); +} +#endif + +EncodedJSValue JSC_HOST_CALL constructJSReadableStreamDefaultReader(ExecState& exec) +{ + VM& vm = exec.vm(); + JSVMClientData& clientData = *static_cast<JSVMClientData*>(vm.clientData); + JSDOMGlobalObject& globalObject = *static_cast<JSDOMGlobalObject*>(exec.lexicalGlobalObject()); + + JSC::JSObject* constructor = JSC::asObject(globalObject.get(&exec, clientData.builtinNames().ReadableStreamDefaultReaderPrivateName())); + ConstructData constructData; + ConstructType constructType = constructor->methodTable(vm)->getConstructData(constructor, constructData); + ASSERT(constructType != ConstructType::None); + + MarkedArgumentBuffer args; + args.append(exec.argument(0)); + return JSValue::encode(JSC::construct(&exec, constructor, constructType, constructData, args)); +} + +// Private JS ReadableStreamDefaultReader and ReadableStreamDefaultController constructors. +using JSBuiltinReadableStreamDefaultReaderPrivateConstructor = JSDOMBuiltinConstructor<JSReadableStreamDefaultReader>; +using JSBuiltinReadableStreamDefaultControllerPrivateConstructor = JSDOMBuiltinConstructor<JSReadableStreamDefaultController>; +#if ENABLE(READABLE_BYTE_STREAM_API) +// Private JS ReadableByteStreamController constructor. +using JSBuiltinReadableByteStreamControllerPrivateConstructor = JSDOMBuiltinConstructor<JSReadableByteStreamController>; +#endif + +STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSBuiltinReadableStreamDefaultReaderPrivateConstructor); +STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSBuiltinReadableStreamDefaultControllerPrivateConstructor); +#if ENABLE(READABLE_BYTE_STREAM_API) +STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSBuiltinReadableByteStreamControllerPrivateConstructor); +#endif + +template<> const ClassInfo JSBuiltinReadableStreamDefaultReaderPrivateConstructor::s_info = { "ReadableStreamDefaultReaderPrivateConstructor", &Base::s_info, 0, CREATE_METHOD_TABLE(JSBuiltinReadableStreamDefaultReaderPrivateConstructor) }; +template<> const ClassInfo JSBuiltinReadableStreamDefaultControllerPrivateConstructor::s_info = { "ReadableStreamDefaultControllerPrivateConstructor", &Base::s_info, 0, CREATE_METHOD_TABLE(JSBuiltinReadableStreamDefaultControllerPrivateConstructor) }; +#if ENABLE(READABLE_BYTE_STREAM_API) +template<> const ClassInfo JSBuiltinReadableByteStreamControllerPrivateConstructor::s_info = { "ReadableByteStreamControllerPrivateConstructor", &Base::s_info, 0, CREATE_METHOD_TABLE(JSBuiltinReadableByteStreamControllerPrivateConstructor) }; +#endif + +template<> FunctionExecutable* JSBuiltinReadableStreamDefaultReaderPrivateConstructor::initializeExecutable(JSC::VM& vm) +{ + return readableStreamInternalsPrivateInitializeReadableStreamDefaultReaderCodeGenerator(vm); +} + +template<> FunctionExecutable* JSBuiltinReadableStreamDefaultControllerPrivateConstructor::initializeExecutable(JSC::VM& vm) +{ + return readableStreamInternalsPrivateInitializeReadableStreamDefaultControllerCodeGenerator(vm); +} + +#if ENABLE(READABLE_BYTE_STREAM_API) +template<> FunctionExecutable* JSBuiltinReadableByteStreamControllerPrivateConstructor::initializeExecutable(JSC::VM& vm) +{ + return readableByteStreamInternalsPrivateInitializeReadableByteStreamControllerCodeGenerator(vm); +} +#endif + +JSObject* createReadableStreamDefaultReaderPrivateConstructor(VM& vm, JSDOMGlobalObject& globalObject) +{ + return JSBuiltinReadableStreamDefaultReaderPrivateConstructor::create(vm, JSBuiltinReadableStreamDefaultReaderPrivateConstructor::createStructure(vm, globalObject, globalObject.objectPrototype()), globalObject); +} + +JSObject* createReadableStreamDefaultControllerPrivateConstructor(VM& vm, JSDOMGlobalObject& globalObject) +{ + return JSBuiltinReadableStreamDefaultControllerPrivateConstructor::create(vm, JSBuiltinReadableStreamDefaultControllerPrivateConstructor::createStructure(vm, globalObject, globalObject.objectPrototype()), globalObject); +} + +#if ENABLE(READABLE_BYTE_STREAM_API) +JSObject* createReadableByteStreamControllerPrivateConstructor(VM& vm, JSDOMGlobalObject& globalObject) +{ + return JSBuiltinReadableByteStreamControllerPrivateConstructor::create(vm, JSBuiltinReadableByteStreamControllerPrivateConstructor::createStructure(vm, globalObject, globalObject.objectPrototype()), globalObject); +} +#endif + +} // namespace WebCore + +#endif diff --git a/Source/WebCore/bindings/js/JSDOMStringListCustom.cpp b/Source/WebCore/bindings/js/JSReadableStreamPrivateConstructors.h index b73378d37..ac16afdef 100644 --- a/Source/WebCore/bindings/js/JSDOMStringListCustom.cpp +++ b/Source/WebCore/bindings/js/JSReadableStreamPrivateConstructors.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Research In Motion Inc. All rights reserved. + * Copyright (C) 2015 Canon Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,27 +16,26 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "config.h" -#include "JSDOMStringList.h" +#pragma once -using namespace JSC; +#if ENABLE(READABLE_STREAM_API) + +namespace JSC { +class JSObject; +class VM; +} namespace WebCore { -PassRefPtr<DOMStringList> toDOMStringList(ExecState* exec, JSValue value) -{ - if (value.inherits(JSDOMStringList::info())) - return &jsCast<JSDOMStringList*>(asObject(value))->impl(); +class JSDOMGlobalObject; - if (!isJSArray(value)) - return 0; +JSC::JSObject* createReadableStreamDefaultReaderPrivateConstructor(JSC::VM&, JSDOMGlobalObject&); +JSC::JSObject* createReadableStreamDefaultControllerPrivateConstructor(JSC::VM&, JSDOMGlobalObject&); - JSArray* array = asArray(value); - RefPtr<DOMStringList> stringList = DOMStringList::create(); - for (unsigned i = 0; i < array->length(); ++i) - stringList->append(array->getIndex(exec, i).toString(exec)->value(exec)); - - return stringList.release(); -} +#if ENABLE(READABLE_BYTE_STREAM_API) +JSC::JSObject* createReadableByteStreamControllerPrivateConstructor(JSC::VM&, JSDOMGlobalObject&); +#endif } // namespace WebCore + +#endif // ENABLE(READABLE_STREAM_API) diff --git a/Source/WebCore/bindings/js/JSReadableStreamSourceCustom.cpp b/Source/WebCore/bindings/js/JSReadableStreamSourceCustom.cpp new file mode 100644 index 000000000..5cf0a8478 --- /dev/null +++ b/Source/WebCore/bindings/js/JSReadableStreamSourceCustom.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2016 Canon Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted, provided that the following conditions + * are required to be 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. + * 3. Neither the name of Canon Inc. nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CANON 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 CANON INC. AND 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 "JSReadableStreamSource.h" + +#if ENABLE(READABLE_STREAM_API) + +using namespace JSC; + +namespace WebCore { + +static void startReadableStream(JSC::ExecState& state, Ref<DeferredPromise>&& promise) +{ + VM& vm = state.vm(); + JSReadableStreamSource* source = jsDynamicDowncast<JSReadableStreamSource*>(vm, state.thisValue()); + ASSERT(source); + + ASSERT(state.argumentCount()); + JSReadableStreamDefaultController* controller = jsDynamicDowncast<JSReadableStreamDefaultController*>(vm, state.uncheckedArgument(0)); + ASSERT(controller); + + source->wrapped().start(ReadableStreamDefaultController(controller), WTFMove(promise)); +} + +JSValue JSReadableStreamSource::start(ExecState& state) +{ + VM& vm = state.vm(); + ASSERT(state.argumentCount()); + JSReadableStreamDefaultController* controller = jsDynamicDowncast<JSReadableStreamDefaultController*>(vm, state.uncheckedArgument(0)); + ASSERT(controller); + + m_controller.set(vm, this, controller); + + return callPromiseFunction<startReadableStream, PromiseExecutionScope::WindowOrWorker>(state); +} + +static void pullReadableStream(JSC::ExecState& state, Ref<DeferredPromise>&& promise) +{ + VM& vm = state.vm(); + JSReadableStreamSource* source = jsDynamicDowncast<JSReadableStreamSource*>(vm, state.thisValue()); + ASSERT(source); + + source->wrapped().pull(WTFMove(promise)); +} + +JSValue JSReadableStreamSource::pull(ExecState& state) +{ + return callPromiseFunction<pullReadableStream, PromiseExecutionScope::WindowOrWorker>(state); +} + +JSValue JSReadableStreamSource::controller(ExecState&) const +{ + ASSERT_NOT_REACHED(); + return jsUndefined(); +} + +} + +#endif // ENABLE(READABLE_STREAM_API) diff --git a/Source/WebCore/bindings/js/JSSQLResultSetRowListCustom.cpp b/Source/WebCore/bindings/js/JSSQLResultSetRowListCustom.cpp deleted file mode 100644 index c0b240d11..000000000 --- a/Source/WebCore/bindings/js/JSSQLResultSetRowListCustom.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2007 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE 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 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" - -#if ENABLE(SQL_DATABASE) - -#include "JSSQLResultSetRowList.h" - -#include "ExceptionCode.h" -#include "SQLValue.h" -#include "SQLResultSetRowList.h" -#include <runtime/ObjectConstructor.h> - -using namespace JSC; - -namespace WebCore { - -JSValue JSSQLResultSetRowList::item(ExecState* exec) -{ - bool indexOk; - int index = finiteInt32Value(exec->argument(0), exec, indexOk); - if (!indexOk) { - setDOMException(exec, TYPE_MISMATCH_ERR); - return jsUndefined(); - } - if (index < 0 || (unsigned)index >= m_impl->length()) { - setDOMException(exec, INDEX_SIZE_ERR); - return jsUndefined(); - } - - JSObject* object = constructEmptyObject(exec); - - unsigned numColumns = m_impl->columnNames().size(); - unsigned valuesIndex = index * numColumns; - for (unsigned i = 0; i < numColumns; i++) { - const SQLValue& value = m_impl->values()[valuesIndex + i]; - JSValue jsValue; - - switch (value.type()) { - case SQLValue::StringValue: - jsValue = jsStringWithCache(exec, value.string()); - break; - case SQLValue::NullValue: - jsValue = jsNull(); - break; - case SQLValue::NumberValue: - jsValue = jsNumber(value.number()); - break; - default: - ASSERT_NOT_REACHED(); - } - - object->putDirect(exec->vm(), Identifier(exec, m_impl->columnNames()[i]), jsValue, DontDelete | ReadOnly); - } - - return object; -} - -} // namespace WebCore - -#endif // ENABLE(SQL_DATABASE) diff --git a/Source/WebCore/bindings/js/JSCustomSQLStatementErrorCallback.cpp b/Source/WebCore/bindings/js/JSSQLStatementErrorCallbackCustom.cpp index b4e315e6e..0030f0178 100644 --- a/Source/WebCore/bindings/js/JSCustomSQLStatementErrorCallback.cpp +++ b/Source/WebCore/bindings/js/JSSQLStatementErrorCallbackCustom.cpp @@ -10,7 +10,7 @@ * 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -27,14 +27,13 @@ */ #include "config.h" - -#if ENABLE(SQL_DATABASE) - #include "JSSQLStatementErrorCallback.h" +#include "JSDOMExceptionHandling.h" #include "JSSQLError.h" #include "JSSQLTransaction.h" #include "ScriptExecutionContext.h" +#include <runtime/Exception.h> #include <runtime/JSLock.h> #include <wtf/Ref.h> @@ -47,7 +46,7 @@ bool JSSQLStatementErrorCallback::handleEvent(SQLTransaction* transaction, SQLEr if (!m_data || !m_data->globalObject() || !canInvokeCallback()) return true; - Ref<JSSQLStatementErrorCallback> protect(*this); + Ref<JSSQLStatementErrorCallback> protectedThis(*this); JSC::JSLockHolder lock(m_data->globalObject()->vm()); @@ -56,9 +55,11 @@ bool JSSQLStatementErrorCallback::handleEvent(SQLTransaction* transaction, SQLEr args.append(toJS(exec, m_data->globalObject(), transaction)); args.append(toJS(exec, m_data->globalObject(), error)); - bool raisedException = false; - JSValue result = m_data->invokeCallback(args, &raisedException); - if (raisedException) { + NakedPtr<JSC::Exception> returnedException; + JSValue result = m_data->invokeCallback(args, JSCallbackData::CallbackType::Function, Identifier(), returnedException); + if (returnedException) { + reportException(exec, returnedException); + // The spec says: // "If the error callback returns false, then move on to the next statement..." // "Otherwise, the error callback did not return false, or there was no error callback" @@ -69,5 +70,3 @@ bool JSSQLStatementErrorCallback::handleEvent(SQLTransaction* transaction, SQLEr } } - -#endif // ENABLE(SQL_DATABASE) diff --git a/Source/WebCore/bindings/js/JSSQLTransactionCustom.cpp b/Source/WebCore/bindings/js/JSSQLTransactionCustom.cpp deleted file mode 100644 index 7a90c43bf..000000000 --- a/Source/WebCore/bindings/js/JSSQLTransactionCustom.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2007 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE 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 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" - -#if ENABLE(SQL_DATABASE) - -#include "JSSQLTransaction.h" - -#include "DOMWindow.h" -#include "ExceptionCode.h" -#include "JSSQLStatementCallback.h" -#include "JSSQLStatementErrorCallback.h" -#include "JSDOMWindowCustom.h" -#include "SQLTransaction.h" - -using namespace JSC; - -namespace WebCore { - -JSValue JSSQLTransaction::executeSql(ExecState* exec) -{ - if (!exec->argumentCount()) { - setDOMException(exec, SYNTAX_ERR); - return jsUndefined(); - } - - String sqlStatement = exec->argument(0).toString(exec)->value(exec); - if (exec->hadException()) - return jsUndefined(); - - // Now assemble the list of SQL arguments - Vector<SQLValue> sqlValues; - if (!exec->argument(1).isUndefinedOrNull()) { - JSObject* object = exec->argument(1).getObject(); - if (!object) { - setDOMException(exec, TYPE_MISMATCH_ERR); - return jsUndefined(); - } - - JSValue lengthValue = object->get(exec, exec->propertyNames().length); - if (exec->hadException()) - return jsUndefined(); - unsigned length = lengthValue.toUInt32(exec); - if (exec->hadException()) - return jsUndefined(); - - for (unsigned i = 0 ; i < length; ++i) { - JSValue value = object->get(exec, i); - if (exec->hadException()) - return jsUndefined(); - - if (value.isUndefinedOrNull()) - sqlValues.append(SQLValue()); - else if (value.isNumber()) - sqlValues.append(value.asNumber()); - else { - // Convert the argument to a string and append it - sqlValues.append(value.toString(exec)->value(exec)); - if (exec->hadException()) - return jsUndefined(); - } - } - } - - RefPtr<SQLStatementCallback> callback; - if (!exec->argument(2).isUndefinedOrNull()) { - JSObject* object = exec->argument(2).getObject(); - if (!object) { - setDOMException(exec, TYPE_MISMATCH_ERR); - return jsUndefined(); - } - - callback = JSSQLStatementCallback::create(object, jsCast<JSDOMGlobalObject*>(globalObject())); - } - - RefPtr<SQLStatementErrorCallback> errorCallback; - if (!exec->argument(3).isUndefinedOrNull()) { - JSObject* object = exec->argument(3).getObject(); - if (!object) { - setDOMException(exec, TYPE_MISMATCH_ERR); - return jsUndefined(); - } - - errorCallback = JSSQLStatementErrorCallback::create(object, jsCast<JSDOMGlobalObject*>(globalObject())); - } - - ExceptionCode ec = 0; - m_impl->executeSQL(sqlStatement, sqlValues, callback.release(), errorCallback.release(), ec); - setDOMException(exec, ec); - - return jsUndefined(); -} - -} // namespace WebCore - -#endif // ENABLE(SQL_DATABASE) diff --git a/Source/WebCore/bindings/js/JSSQLTransactionSyncCustom.cpp b/Source/WebCore/bindings/js/JSSQLTransactionSyncCustom.cpp deleted file mode 100644 index b682c451d..000000000 --- a/Source/WebCore/bindings/js/JSSQLTransactionSyncCustom.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2010 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE 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 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" - -#if ENABLE(SQL_DATABASE) - -#include "JSSQLTransactionSync.h" - -#include "ExceptionCode.h" -#include "JSSQLResultSet.h" -#include "SQLResultSet.h" -#include "SQLTransactionSync.h" -#include "SQLValue.h" - -using namespace JSC; - -namespace WebCore { - -JSValue JSSQLTransactionSync::executeSql(ExecState* exec) -{ - if (!exec->argumentCount()) { - setDOMException(exec, SYNTAX_ERR); - return jsUndefined(); - } - - String sqlStatement = exec->uncheckedArgument(0).toString(exec)->value(exec); - if (exec->hadException()) - return jsUndefined(); - - // Now assemble the list of SQL arguments - Vector<SQLValue> sqlValues; - if (!exec->argument(1).isUndefinedOrNull()) { - JSObject* object = exec->argument(1).getObject(); - if (!object) { - setDOMException(exec, TYPE_MISMATCH_ERR); - return jsUndefined(); - } - - JSValue lengthValue = object->get(exec, exec->propertyNames().length); - if (exec->hadException()) - return jsUndefined(); - unsigned length = lengthValue.toUInt32(exec); - if (exec->hadException()) - return jsUndefined(); - - for (unsigned i = 0 ; i < length; ++i) { - JSValue value = object->get(exec, i); - if (exec->hadException()) - return jsUndefined(); - - if (value.isUndefinedOrNull()) - sqlValues.append(SQLValue()); - else if (value.isNumber()) - sqlValues.append(value.asNumber()); - else { - // Convert the argument to a string and append it - sqlValues.append(value.toString(exec)->value(exec)); - if (exec->hadException()) - return jsUndefined(); - } - } - } - - ExceptionCode ec = 0; - JSValue result = toJS(exec, globalObject(), WTF::getPtr(m_impl->executeSQL(sqlStatement, sqlValues, ec))); - setDOMException(exec, ec); - - return result; -} - -} // namespace WebCore - -#endif // ENABLE(SQL_DATABASE) diff --git a/Source/WebCore/bindings/js/JSSVGElementInstanceCustom.cpp b/Source/WebCore/bindings/js/JSSVGElementInstanceCustom.cpp deleted file mode 100644 index b28e7cf59..000000000 --- a/Source/WebCore/bindings/js/JSSVGElementInstanceCustom.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2008 Nikolas Zimmermann <zimmermann@kde.org> - * Copyright (C) 2009 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 COMPUTER, INC. ``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 COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#if ENABLE(SVG) - -#include "JSSVGElementInstance.h" - -#include "JSEventTarget.h" -#include "JSNodeCustom.h" - -namespace WebCore { - -void JSSVGElementInstance::visitChildren(JSC::JSCell* cell, JSC::SlotVisitor& visitor) -{ - JSSVGElementInstance* thisObject = JSC::jsCast<JSSVGElementInstance*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & JSC::OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); - // Skip JSEventTarget::visitChildren because event listener registration is - // forwarded to the corresponding element. - JSEventTarget::Base::visitChildren(thisObject, visitor); - visitor.addOpaqueRoot(root(thisObject->impl().correspondingElement())); -} - -} // namespace WebCore - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/bindings/js/JSSVGLengthCustom.cpp b/Source/WebCore/bindings/js/JSSVGLengthCustom.cpp deleted file mode 100644 index cf78a03ad..000000000 --- a/Source/WebCore/bindings/js/JSSVGLengthCustom.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* - Copyright (C) 2008 Nikolas Zimmermann <zimmermann@kde.org> - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "config.h" - -#if ENABLE(SVG) -#include "JSSVGLength.h" - -#include "ExceptionCode.h" -#include "SVGAnimatedProperty.h" -#include "SVGException.h" -#include "SVGLengthContext.h" -#include <runtime/Error.h> - -using namespace JSC; - -namespace WebCore { - -JSValue JSSVGLength::value(ExecState* exec) const -{ - SVGLength& podImp = impl().propertyReference(); - ExceptionCode ec = 0; - SVGLengthContext lengthContext(impl().contextElement()); - float value = podImp.value(lengthContext, ec); - if (ec) { - setDOMException(exec, ec); - return jsUndefined(); - } - - return jsNumber(value); -} - -void JSSVGLength::setValue(ExecState* exec, JSValue value) -{ - if (impl().isReadOnly()) { - setDOMException(exec, NO_MODIFICATION_ALLOWED_ERR); - return; - } - - if (!value.isUndefinedOrNull() && !value.isNumber() && !value.isBoolean()) { - throwVMTypeError(exec); - return; - } - - SVGLength& podImp = impl().propertyReference(); - - ExceptionCode ec = 0; - SVGLengthContext lengthContext(impl().contextElement()); - podImp.setValue(value.toFloat(exec), lengthContext, ec); - if (ec) { - setDOMException(exec, ec); - return; - } - - impl().commitChange(); -} - -JSValue JSSVGLength::convertToSpecifiedUnits(ExecState* exec) -{ - if (impl().isReadOnly()) { - setDOMException(exec, NO_MODIFICATION_ALLOWED_ERR); - return jsUndefined(); - } - - SVGLength& podImp = impl().propertyReference(); - - if (exec->argumentCount() < 1) - return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); - - unsigned short unitType = exec->uncheckedArgument(0).toUInt32(exec); - if (exec->hadException()) - return jsUndefined(); - - ExceptionCode ec = 0; - SVGLengthContext lengthContext(impl().contextElement()); - podImp.convertToSpecifiedUnits(unitType, lengthContext, ec); - if (ec) { - setDOMException(exec, ec); - return jsUndefined(); - } - - impl().commitChange(); - return jsUndefined(); -} - -} - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/bindings/js/JSSVGPathSegCustom.cpp b/Source/WebCore/bindings/js/JSSVGPathSegCustom.cpp index 9d6bf2d39..b4747184a 100644 --- a/Source/WebCore/bindings/js/JSSVGPathSegCustom.cpp +++ b/Source/WebCore/bindings/js/JSSVGPathSegCustom.cpp @@ -18,8 +18,6 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "JSSVGPathSeg.h" #include "JSDOMBinding.h" @@ -61,59 +59,56 @@ using namespace JSC; namespace WebCore { -JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, SVGPathSeg* object) +JSValue toJSNewlyCreated(ExecState*, JSDOMGlobalObject* globalObject, Ref<SVGPathSeg>&& object) { - if (!object) - return jsNull(); - - if (JSObject* wrapper = getCachedWrapper(currentWorld(exec), object)) - return wrapper; - switch (object->pathSegType()) { case SVGPathSeg::PATHSEG_CLOSEPATH: - return CREATE_DOM_WRAPPER(exec, globalObject, SVGPathSegClosePath, object); + return createWrapper<SVGPathSegClosePath>(globalObject, WTFMove(object)); case SVGPathSeg::PATHSEG_MOVETO_ABS: - return CREATE_DOM_WRAPPER(exec, globalObject, SVGPathSegMovetoAbs, object); + return createWrapper<SVGPathSegMovetoAbs>(globalObject, WTFMove(object)); case SVGPathSeg::PATHSEG_MOVETO_REL: - return CREATE_DOM_WRAPPER(exec, globalObject, SVGPathSegMovetoRel, object); + return createWrapper<SVGPathSegMovetoRel>(globalObject, WTFMove(object)); case SVGPathSeg::PATHSEG_LINETO_ABS: - return CREATE_DOM_WRAPPER(exec, globalObject, SVGPathSegLinetoAbs, object); + return createWrapper<SVGPathSegLinetoAbs>(globalObject, WTFMove(object)); case SVGPathSeg::PATHSEG_LINETO_REL: - return CREATE_DOM_WRAPPER(exec, globalObject, SVGPathSegLinetoRel, object); + return createWrapper<SVGPathSegLinetoRel>(globalObject, WTFMove(object)); case SVGPathSeg::PATHSEG_CURVETO_CUBIC_ABS: - return CREATE_DOM_WRAPPER(exec, globalObject, SVGPathSegCurvetoCubicAbs, object); + return createWrapper<SVGPathSegCurvetoCubicAbs>(globalObject, WTFMove(object)); case SVGPathSeg::PATHSEG_CURVETO_CUBIC_REL: - return CREATE_DOM_WRAPPER(exec, globalObject, SVGPathSegCurvetoCubicRel, object); + return createWrapper<SVGPathSegCurvetoCubicRel>(globalObject, WTFMove(object)); case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_ABS: - return CREATE_DOM_WRAPPER(exec, globalObject, SVGPathSegCurvetoQuadraticAbs, object); + return createWrapper<SVGPathSegCurvetoQuadraticAbs>(globalObject, WTFMove(object)); case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_REL: - return CREATE_DOM_WRAPPER(exec, globalObject, SVGPathSegCurvetoQuadraticRel, object); + return createWrapper<SVGPathSegCurvetoQuadraticRel>(globalObject, WTFMove(object)); case SVGPathSeg::PATHSEG_ARC_ABS: - return CREATE_DOM_WRAPPER(exec, globalObject, SVGPathSegArcAbs, object); + return createWrapper<SVGPathSegArcAbs>(globalObject, WTFMove(object)); case SVGPathSeg::PATHSEG_ARC_REL: - return CREATE_DOM_WRAPPER(exec, globalObject, SVGPathSegArcRel, object); + return createWrapper<SVGPathSegArcRel>(globalObject, WTFMove(object)); case SVGPathSeg::PATHSEG_LINETO_HORIZONTAL_ABS: - return CREATE_DOM_WRAPPER(exec, globalObject, SVGPathSegLinetoHorizontalAbs, object); + return createWrapper<SVGPathSegLinetoHorizontalAbs>(globalObject, WTFMove(object)); case SVGPathSeg::PATHSEG_LINETO_HORIZONTAL_REL: - return CREATE_DOM_WRAPPER(exec, globalObject, SVGPathSegLinetoHorizontalRel, object); + return createWrapper<SVGPathSegLinetoHorizontalRel>(globalObject, WTFMove(object)); case SVGPathSeg::PATHSEG_LINETO_VERTICAL_ABS: - return CREATE_DOM_WRAPPER(exec, globalObject, SVGPathSegLinetoVerticalAbs, object); + return createWrapper<SVGPathSegLinetoVerticalAbs>(globalObject, WTFMove(object)); case SVGPathSeg::PATHSEG_LINETO_VERTICAL_REL: - return CREATE_DOM_WRAPPER(exec, globalObject, SVGPathSegLinetoVerticalRel, object); + return createWrapper<SVGPathSegLinetoVerticalRel>(globalObject, WTFMove(object)); case SVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS: - return CREATE_DOM_WRAPPER(exec, globalObject, SVGPathSegCurvetoCubicSmoothAbs, object); + return createWrapper<SVGPathSegCurvetoCubicSmoothAbs>(globalObject, WTFMove(object)); case SVGPathSeg::PATHSEG_CURVETO_CUBIC_SMOOTH_REL: - return CREATE_DOM_WRAPPER(exec, globalObject, SVGPathSegCurvetoCubicSmoothRel, object); + return createWrapper<SVGPathSegCurvetoCubicSmoothRel>(globalObject, WTFMove(object)); case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS: - return CREATE_DOM_WRAPPER(exec, globalObject, SVGPathSegCurvetoQuadraticSmoothAbs, object); + return createWrapper<SVGPathSegCurvetoQuadraticSmoothAbs>(globalObject, WTFMove(object)); case SVGPathSeg::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL: - return CREATE_DOM_WRAPPER(exec, globalObject, SVGPathSegCurvetoQuadraticSmoothRel, object); + return createWrapper<SVGPathSegCurvetoQuadraticSmoothRel>(globalObject, WTFMove(object)); case SVGPathSeg::PATHSEG_UNKNOWN: default: - return CREATE_DOM_WRAPPER(exec, globalObject, SVGPathSeg, object); + return createWrapper<SVGPathSeg>(globalObject, WTFMove(object)); } } +JSValue toJS(ExecState* state, JSDOMGlobalObject* globalObject, SVGPathSeg& object) +{ + return wrap(state, globalObject, object); } -#endif // ENABLE(SVG) +} diff --git a/Source/WebCore/bindings/js/JSSharedWorkerCustom.cpp b/Source/WebCore/bindings/js/JSSharedWorkerCustom.cpp deleted file mode 100644 index 2c2786417..000000000 --- a/Source/WebCore/bindings/js/JSSharedWorkerCustom.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2009 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#if ENABLE(SHARED_WORKERS) - -#include "JSSharedWorker.h" - -#include "Document.h" -#include "JSDOMGlobalObject.h" -#include "JSDOMWindowCustom.h" -#include "SharedWorker.h" -#include <runtime/Error.h> - -using namespace JSC; - -namespace WebCore { - -void JSSharedWorker::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - JSSharedWorker* thisObject = jsCast<JSSharedWorker*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(thisObject, visitor); - - if (MessagePort* port = thisObject->impl().port()) - visitor.addOpaqueRoot(port); -} - -EncodedJSValue JSC_HOST_CALL JSSharedWorkerConstructor::constructJSSharedWorker(ExecState* exec) -{ - JSSharedWorkerConstructor* jsConstructor = jsCast<JSSharedWorkerConstructor*>(exec->callee()); - - if (exec->argumentCount() < 1) - return throwVMError(exec, createNotEnoughArgumentsError(exec)); - - String scriptURL = exec->uncheckedArgument(0).toString(exec)->value(exec); - String name; - if (exec->argumentCount() > 1) - name = exec->uncheckedArgument(1).toString(exec)->value(exec); - - if (exec->hadException()) - return JSValue::encode(JSValue()); - - // FIXME: We need to use both the dynamic scope and the lexical scope (dynamic scope for resolving the worker URL) - DOMWindow& window = asJSDOMWindow(exec->lexicalGlobalObject())->impl(); - ExceptionCode ec = 0; - ASSERT(window.document()); - RefPtr<SharedWorker> worker = SharedWorker::create(*window.document(), scriptURL, name, ec); - if (ec) { - setDOMException(exec, ec); - return JSValue::encode(JSValue()); - } - - return JSValue::encode(asObject(toJS(exec, jsConstructor->globalObject(), worker.release()))); -} - -} // namespace WebCore - -#endif // ENABLE(SHARED_WORKERS) diff --git a/Source/WebCore/bindings/js/JSStorageCustom.cpp b/Source/WebCore/bindings/js/JSStorageCustom.cpp index f2e22a3b6..044044361 100644 --- a/Source/WebCore/bindings/js/JSStorageCustom.cpp +++ b/Source/WebCore/bindings/js/JSStorageCustom.cpp @@ -26,7 +26,9 @@ #include "config.h" #include "JSStorage.h" -#include "Storage.h" +#include "JSDOMConvertStrings.h" +#include "JSDOMExceptionHandling.h" +#include <runtime/JSCInlines.h> #include <runtime/PropertyNameArray.h> #include <wtf/text/WTFString.h> @@ -34,45 +36,25 @@ using namespace JSC; namespace WebCore { -bool JSStorage::canGetItemsForName(ExecState* exec, Storage* impl, PropertyName propertyName) +bool JSStorage::deleteProperty(JSCell* cell, ExecState* state, PropertyName propertyName) { - ExceptionCode ec = 0; - bool result = impl->contains(propertyNameToString(propertyName), ec); - setDOMException(exec, ec); - return result; -} - -EncodedJSValue JSStorage::nameGetter(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName propertyName) -{ - JSStorage* thisObj = jsCast<JSStorage*>(JSValue::decode(slotBase)); - - JSValue prototype = asObject(JSValue::decode(slotBase))->prototype(); - if (prototype.isObject() && asObject(prototype)->hasProperty(exec, propertyName)) - return JSValue::encode(asObject(prototype)->get(exec, propertyName)); - - ExceptionCode ec = 0; - JSValue result = jsStringOrNull(exec, thisObj->impl().getItem(propertyNameToString(propertyName), ec)); - setDOMException(exec, ec); - return JSValue::encode(result); -} + auto& thisObject = *jsCast<JSStorage*>(cell); -bool JSStorage::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName) -{ - JSStorage* thisObject = jsCast<JSStorage*>(cell); // Only perform the custom delete if the object doesn't have a native property by this name. // Since hasProperty() would end up calling canGetItemsForName() and be fooled, we need to check // the native property slots manually. - PropertySlot slot(thisObject); - if (getStaticValueSlot<JSStorage, Base>(exec, *s_info.propHashTable(exec), thisObject, propertyName, slot)) - return false; - - JSValue prototype = thisObject->prototype(); - if (prototype.isObject() && asObject(prototype)->hasProperty(exec, propertyName)) - return false; + PropertySlot slot(&thisObject, PropertySlot::InternalMethodType::GetOwnProperty); + + JSValue prototype = thisObject.getPrototypeDirect(); + if (prototype.isObject() && asObject(prototype)->getPropertySlot(state, propertyName, slot)) + return Base::deleteProperty(&thisObject, state, propertyName); - ExceptionCode ec = 0; - thisObject->m_impl->removeItem(propertyNameToString(propertyName), ec); - setDOMException(exec, ec); + if (propertyName.isSymbol()) + return Base::deleteProperty(&thisObject, state, propertyName); + + VM& vm = state->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + propagateException(*state, scope, thisObject.wrapped().removeItem(propertyNameToString(propertyName))); return true; } @@ -81,45 +63,57 @@ bool JSStorage::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned pr return deleteProperty(cell, exec, Identifier::from(exec, propertyName)); } -void JSStorage::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) +void JSStorage::getOwnPropertyNames(JSObject* object, ExecState* state, PropertyNameArray& propertyNames, EnumerationMode mode) { - JSStorage* thisObject = jsCast<JSStorage*>(object); - ExceptionCode ec = 0; - unsigned length = thisObject->m_impl->length(ec); - setDOMException(exec, ec); - if (exec->hadException()) + VM& vm = state->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto& thisObject = *jsCast<JSStorage*>(object); + auto lengthResult = thisObject.wrapped().length(); + if (lengthResult.hasException()) { + propagateException(*state, scope, lengthResult.releaseException()); return; + } + unsigned length = lengthResult.releaseReturnValue(); for (unsigned i = 0; i < length; ++i) { - propertyNames.add(Identifier(exec, thisObject->m_impl->key(i, ec))); - setDOMException(exec, ec); - if (exec->hadException()) + auto keyResult = thisObject.wrapped().key(i); + if (keyResult.hasException()) { + propagateException(*state, scope, lengthResult.releaseException()); return; + } + propertyNames.add(Identifier::fromString(state, keyResult.releaseReturnValue())); } - Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode); + Base::getOwnPropertyNames(&thisObject, state, propertyNames, mode); } -bool JSStorage::putDelegate(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot&) +bool JSStorage::putDelegate(ExecState* state, PropertyName propertyName, JSValue value, PutPropertySlot&, bool& putResult) { + VM& vm = state->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + // Only perform the custom put if the object doesn't have a native property by this name. // Since hasProperty() would end up calling canGetItemsForName() and be fooled, we need to check // the native property slots manually. - PropertySlot slot(this); - if (getStaticValueSlot<JSStorage, Base>(exec, *s_info.propHashTable(exec), this, propertyName, slot)) + PropertySlot slot { this, PropertySlot::InternalMethodType::GetOwnProperty }; + + JSValue prototype = this->getPrototypeDirect(); + if (prototype.isObject() && asObject(prototype)->getPropertySlot(state, propertyName, slot)) return false; - - JSValue prototype = this->prototype(); - if (prototype.isObject() && asObject(prototype)->hasProperty(exec, propertyName)) + + if (propertyName.isSymbol()) return false; - - String stringValue = value.toString(exec)->value(exec); - if (exec->hadException()) + + String stringValue = value.toWTFString(state); + RETURN_IF_EXCEPTION(scope, true); + + auto setItemResult = wrapped().setItem(propertyNameToString(propertyName), stringValue); + if (setItemResult.hasException()) { + propagateException(*state, scope, setItemResult.releaseException()); return true; - - ExceptionCode ec = 0; - impl().setItem(propertyNameToString(propertyName), stringValue, ec); - setDOMException(exec, ec); + } + putResult = true; return true; } diff --git a/Source/WebCore/bindings/js/JSStyleSheetCustom.cpp b/Source/WebCore/bindings/js/JSStyleSheetCustom.cpp index f7063061f..5c3b82f13 100644 --- a/Source/WebCore/bindings/js/JSStyleSheetCustom.cpp +++ b/Source/WebCore/bindings/js/JSStyleSheetCustom.cpp @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,40 +26,25 @@ #include "config.h" #include "JSStyleSheet.h" -#include "CSSStyleSheet.h" -#include "Node.h" #include "JSCSSStyleSheet.h" -#include "JSNode.h" - -using namespace JSC; namespace WebCore { -void JSStyleSheet::visitChildren(JSCell* cell, SlotVisitor& visitor) +void JSStyleSheet::visitAdditionalChildren(JSC::SlotVisitor& visitor) { - JSStyleSheet* thisObject = jsCast<JSStyleSheet*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(thisObject, visitor); - visitor.addOpaqueRoot(root(&thisObject->impl())); + visitor.addOpaqueRoot(root(&wrapped())); } -JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, StyleSheet* styleSheet) +JSC::JSValue toJSNewlyCreated(JSC::ExecState*, JSDOMGlobalObject* globalObject, Ref<StyleSheet>&& styleSheet) { - if (!styleSheet) - return jsNull(); - - JSObject* wrapper = getCachedWrapper(currentWorld(exec), styleSheet); - if (wrapper) - return wrapper; - if (styleSheet->isCSSStyleSheet()) - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, CSSStyleSheet, styleSheet); - else - wrapper = CREATE_DOM_WRAPPER(exec, globalObject, StyleSheet, styleSheet); + return createWrapper<CSSStyleSheet>(globalObject, WTFMove(styleSheet)); + return createWrapper<StyleSheet>(globalObject, WTFMove(styleSheet)); +} - return wrapper; +JSC::JSValue toJS(JSC::ExecState* state, JSDOMGlobalObject* globalObject, StyleSheet& stylesheet) +{ + return wrap(state, globalObject, stylesheet); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSStyleSheetCustom.h b/Source/WebCore/bindings/js/JSStyleSheetCustom.h index 8c9c18756..95777fc53 100644 --- a/Source/WebCore/bindings/js/JSStyleSheetCustom.h +++ b/Source/WebCore/bindings/js/JSStyleSheetCustom.h @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,8 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSStyleSheetCustom_h -#define JSStyleSheetCustom_h +#pragma once #include "CSSImportRule.h" #include "CSSStyleSheet.h" @@ -43,5 +42,3 @@ inline void* root(StyleSheet* styleSheet) } } // namespace WebCore - -#endif // JSStyleSheetCustom_h diff --git a/Source/WebCore/bindings/js/JSStyleSheetListCustom.cpp b/Source/WebCore/bindings/js/JSStyleSheetListCustom.cpp deleted file mode 100644 index a5b4eef85..000000000 --- a/Source/WebCore/bindings/js/JSStyleSheetListCustom.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2007, 2009 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 COMPUTER, INC. ``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 COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "JSStyleSheetList.h" - -#include "HTMLStyleElement.h" -#include "JSStyleSheet.h" -#include "StyleSheet.h" -#include "StyleSheetList.h" - -using namespace JSC; - -namespace WebCore { - -bool JSStyleSheetList::canGetItemsForName(ExecState*, StyleSheetList* styleSheetList, PropertyName propertyName) -{ - return styleSheetList->getNamedItem(propertyNameToString(propertyName)); -} - -EncodedJSValue JSStyleSheetList::nameGetter(ExecState* exec, EncodedJSValue slotBase, EncodedJSValue, PropertyName propertyName) -{ - JSStyleSheetList* thisObj = jsCast<JSStyleSheetList*>(JSValue::decode(slotBase)); - HTMLStyleElement* element = thisObj->impl().getNamedItem(propertyNameToString(propertyName)); - ASSERT(element); - return JSValue::encode(toJS(exec, thisObj->globalObject(), element->sheet())); -} - -} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSSubtleCryptoCustom.cpp b/Source/WebCore/bindings/js/JSSubtleCryptoCustom.cpp new file mode 100644 index 000000000..86b95d71a --- /dev/null +++ b/Source/WebCore/bindings/js/JSSubtleCryptoCustom.cpp @@ -0,0 +1,1113 @@ +/* + * Copyright (C) 2016 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 "JSSubtleCrypto.h" + +#if ENABLE(SUBTLE_CRYPTO) + +#include "CryptoAlgorithm.h" +#include "CryptoAlgorithmRegistry.h" +#include "JSAesCbcParams.h" +#include "JSAesKeyGenParams.h" +#include "JSCryptoAlgorithmParameters.h" +#include "JSCryptoKey.h" +#include "JSCryptoKeyPair.h" +#include "JSDOMPromise.h" +#include "JSDOMWrapper.h" +#include "JSHmacKeyParams.h" +#include "JSJsonWebKey.h" +#include "JSRsaHashedImportParams.h" +#include "JSRsaHashedKeyGenParams.h" +#include "JSRsaKeyGenParams.h" +#include "JSRsaOaepParams.h" +#include "ScriptState.h" +#include <runtime/Error.h> +#include <runtime/JSArray.h> +#include <runtime/JSONObject.h> + +using namespace JSC; + +namespace WebCore { + +enum class Operations { + Encrypt, + Decrypt, + Sign, + Verify, + Digest, + DeriveKey, + DeriveBits, + GenerateKey, + ImportKey, + WrapKey, + UnwrapKey +}; + +static std::unique_ptr<CryptoAlgorithmParameters> normalizeCryptoAlgorithmParameters(ExecState&, JSValue, Operations); + +static CryptoAlgorithmIdentifier toHashIdentifier(ExecState& state, JSValue value) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto digestParams = normalizeCryptoAlgorithmParameters(state, value, Operations::Digest); + RETURN_IF_EXCEPTION(scope, { }); + return digestParams->identifier; +} + +static std::unique_ptr<CryptoAlgorithmParameters> normalizeCryptoAlgorithmParameters(ExecState& state, JSValue value, Operations operation) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (value.isString()) { + JSObject* newParams = constructEmptyObject(&state); + newParams->putDirect(vm, Identifier::fromString(&vm, "name"), value); + return normalizeCryptoAlgorithmParameters(state, newParams, operation); + } + + if (value.isObject()) { + auto params = convertDictionary<CryptoAlgorithmParameters>(state, value); + RETURN_IF_EXCEPTION(scope, nullptr); + + auto identifier = CryptoAlgorithmRegistry::singleton().identifier(params.name); + if (UNLIKELY(!identifier)) { + throwNotSupportedError(state, scope); + return nullptr; + } + + std::unique_ptr<CryptoAlgorithmParameters> result; + switch (operation) { + case Operations::Encrypt: + case Operations::Decrypt: + switch (*identifier) { + case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: + result = std::make_unique<CryptoAlgorithmParameters>(params); + break; + case CryptoAlgorithmIdentifier::RSA_OAEP: { + auto params = convertDictionary<CryptoAlgorithmRsaOaepParams>(state, value); + RETURN_IF_EXCEPTION(scope, nullptr); + result = std::make_unique<CryptoAlgorithmRsaOaepParams>(params); + break; + } + case CryptoAlgorithmIdentifier::AES_CBC: { + auto params = convertDictionary<CryptoAlgorithmAesCbcParams>(state, value); + RETURN_IF_EXCEPTION(scope, nullptr); + result = std::make_unique<CryptoAlgorithmAesCbcParams>(params); + break; + } + default: + throwNotSupportedError(state, scope); + return nullptr; + } + break; + case Operations::Sign: + case Operations::Verify: + switch (*identifier) { + case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::HMAC: + result = std::make_unique<CryptoAlgorithmParameters>(params); + break; + default: + throwNotSupportedError(state, scope); + return nullptr; + } + break; + case Operations::Digest: + switch (*identifier) { + case CryptoAlgorithmIdentifier::SHA_1: + case CryptoAlgorithmIdentifier::SHA_224: + case CryptoAlgorithmIdentifier::SHA_256: + case CryptoAlgorithmIdentifier::SHA_384: + case CryptoAlgorithmIdentifier::SHA_512: + result = std::make_unique<CryptoAlgorithmParameters>(params); + break; + default: + throwNotSupportedError(state, scope); + return nullptr; + } + break; + case Operations::DeriveKey: + case Operations::DeriveBits: + throwNotSupportedError(state, scope); + return nullptr; + case Operations::GenerateKey: + switch (*identifier) { + case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: { + auto params = convertDictionary<CryptoAlgorithmRsaKeyGenParams>(state, value); + RETURN_IF_EXCEPTION(scope, nullptr); + result = std::make_unique<CryptoAlgorithmRsaKeyGenParams>(params); + break; + } + case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSA_PSS: + case CryptoAlgorithmIdentifier::RSA_OAEP: { + auto params = convertDictionary<CryptoAlgorithmRsaHashedKeyGenParams>(state, value); + RETURN_IF_EXCEPTION(scope, nullptr); + params.hashIdentifier = toHashIdentifier(state, params.hash); + RETURN_IF_EXCEPTION(scope, nullptr); + result = std::make_unique<CryptoAlgorithmRsaHashedKeyGenParams>(params); + break; + } + case CryptoAlgorithmIdentifier::AES_CTR: + case CryptoAlgorithmIdentifier::AES_CBC: + case CryptoAlgorithmIdentifier::AES_CMAC: + case CryptoAlgorithmIdentifier::AES_GCM: + case CryptoAlgorithmIdentifier::AES_CFB: + case CryptoAlgorithmIdentifier::AES_KW: { + auto params = convertDictionary<CryptoAlgorithmAesKeyGenParams>(state, value); + RETURN_IF_EXCEPTION(scope, nullptr); + result = std::make_unique<CryptoAlgorithmAesKeyGenParams>(params); + break; + } + case CryptoAlgorithmIdentifier::HMAC: { + auto params = convertDictionary<CryptoAlgorithmHmacKeyParams>(state, value); + RETURN_IF_EXCEPTION(scope, nullptr); + params.hashIdentifier = toHashIdentifier(state, params.hash); + RETURN_IF_EXCEPTION(scope, nullptr); + result = std::make_unique<CryptoAlgorithmHmacKeyParams>(params); + break; + } + default: + throwNotSupportedError(state, scope); + return nullptr; + } + break; + case Operations::ImportKey: + switch (*identifier) { + case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: + result = std::make_unique<CryptoAlgorithmParameters>(params); + break; + case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSA_PSS: + case CryptoAlgorithmIdentifier::RSA_OAEP: { + auto params = convertDictionary<CryptoAlgorithmRsaHashedImportParams>(state, value); + RETURN_IF_EXCEPTION(scope, nullptr); + params.hashIdentifier = toHashIdentifier(state, params.hash); + RETURN_IF_EXCEPTION(scope, nullptr); + result = std::make_unique<CryptoAlgorithmRsaHashedImportParams>(params); + break; + } + case CryptoAlgorithmIdentifier::AES_CTR: + case CryptoAlgorithmIdentifier::AES_CBC: + case CryptoAlgorithmIdentifier::AES_CMAC: + case CryptoAlgorithmIdentifier::AES_GCM: + case CryptoAlgorithmIdentifier::AES_CFB: + case CryptoAlgorithmIdentifier::AES_KW: + result = std::make_unique<CryptoAlgorithmParameters>(params); + break; + case CryptoAlgorithmIdentifier::HMAC: { + auto params = convertDictionary<CryptoAlgorithmHmacKeyParams>(state, value); + RETURN_IF_EXCEPTION(scope, nullptr); + params.hashIdentifier = toHashIdentifier(state, params.hash); + RETURN_IF_EXCEPTION(scope, nullptr); + result = std::make_unique<CryptoAlgorithmHmacKeyParams>(params); + break; + } + default: + throwNotSupportedError(state, scope); + return nullptr; + } + break; + case Operations::WrapKey: + case Operations::UnwrapKey: + switch (*identifier) { + case CryptoAlgorithmIdentifier::AES_KW: + result = std::make_unique<CryptoAlgorithmParameters>(params); + break; + default: + throwNotSupportedError(state, scope); + return nullptr; + } + break; + default: + ASSERT_NOT_REACHED(); + return nullptr; + } + + result->identifier = *identifier; + return result; + } + + throwTypeError(&state, scope, ASCIILiteral("Invalid AlgorithmIdentifier")); + return nullptr; +} + +static CryptoKeyUsageBitmap toCryptoKeyUsageBitmap(CryptoKeyUsage usage) +{ + switch (usage) { + case CryptoKeyUsage::Encrypt: + return CryptoKeyUsageEncrypt; + case CryptoKeyUsage::Decrypt: + return CryptoKeyUsageDecrypt; + case CryptoKeyUsage::Sign: + return CryptoKeyUsageSign; + case CryptoKeyUsage::Verify: + return CryptoKeyUsageVerify; + case CryptoKeyUsage::DeriveKey: + return CryptoKeyUsageDeriveKey; + case CryptoKeyUsage::DeriveBits: + return CryptoKeyUsageDeriveBits; + case CryptoKeyUsage::WrapKey: + return CryptoKeyUsageWrapKey; + case CryptoKeyUsage::UnwrapKey: + return CryptoKeyUsageUnwrapKey; + } + + ASSERT_NOT_REACHED(); + return 0; +} + +static CryptoKeyUsageBitmap cryptoKeyUsageBitmapFromJSValue(ExecState& state, JSValue value) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + CryptoKeyUsageBitmap result = 0; + auto usages = convert<IDLSequence<IDLEnumeration<CryptoKeyUsage>>>(state, value); + RETURN_IF_EXCEPTION(scope, 0); + // Maybe we shouldn't silently bypass duplicated usages? + for (auto usage : usages) + result |= toCryptoKeyUsageBitmap(usage); + + return result; +} + +// Maybe we want more specific error messages? +static void rejectWithException(Ref<DeferredPromise>&& passedPromise, ExceptionCode ec) +{ + switch (ec) { + case NOT_SUPPORTED_ERR: + passedPromise->reject(ec, ASCIILiteral("The algorithm is not supported")); + return; + case SYNTAX_ERR: + passedPromise->reject(ec, ASCIILiteral("A required parameter was missing or out-of-range")); + return; + case INVALID_STATE_ERR: + passedPromise->reject(ec, ASCIILiteral("The requested operation is not valid for the current state of the provided key")); + return; + case INVALID_ACCESS_ERR: + passedPromise->reject(ec, ASCIILiteral("The requested operation is not valid for the provided key")); + return; + case UnknownError: + passedPromise->reject(ec, ASCIILiteral("The operation failed for an unknown transient reason (e.g. out of memory)")); + return; + case DataError: + passedPromise->reject(ec, ASCIILiteral("Data provided to an operation does not meet requirements")); + return; + case OperationError: + passedPromise->reject(ec, ASCIILiteral("The operation failed for an operation-specific reason")); + return; + } + ASSERT_NOT_REACHED(); +} + +static KeyData toKeyData(ExecState& state, SubtleCrypto::KeyFormat format, JSValue value) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + KeyData result; + switch (format) { + case SubtleCrypto::KeyFormat::Spki: + case SubtleCrypto::KeyFormat::Pkcs8: + case SubtleCrypto::KeyFormat::Raw: { + BufferSource bufferSource = convert<IDLBufferSource>(state, value); + RETURN_IF_EXCEPTION(scope, result); + Vector<uint8_t> vector; + vector.append(bufferSource.data(), bufferSource.length()); + result = WTFMove(vector); + return result; + } + case SubtleCrypto::KeyFormat::Jwk: { + result = convertDictionary<JsonWebKey>(state, value); + RETURN_IF_EXCEPTION(scope, result); + CryptoKeyUsageBitmap usages = 0; + if (WTF::get<JsonWebKey>(result).key_ops) { + // Maybe we shouldn't silently bypass duplicated usages? + for (auto usage : WTF::get<JsonWebKey>(result).key_ops.value()) + usages |= toCryptoKeyUsageBitmap(usage); + } + WTF::get<JsonWebKey>(result).usages = usages; + return result; + } + } + ASSERT_NOT_REACHED(); + return result; +} + +static RefPtr<CryptoKey> toCryptoKey(ExecState& state, JSValue value) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + RefPtr<CryptoKey> result = JSCryptoKey::toWrapped(vm, value); + if (!result) { + throwTypeError(&state, scope, ASCIILiteral("Invalid CryptoKey")); + return nullptr; + } + return result; +} + +static Vector<uint8_t> toVector(ExecState& state, JSValue value) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + BufferSource data = convert<IDLBufferSource>(state, value); + RETURN_IF_EXCEPTION(scope, { }); + Vector<uint8_t> dataVector; + dataVector.append(data.data(), data.length()); + + return dataVector; +} + +static void supportExportKeyThrow(ExecState& state, ThrowScope& scope, CryptoAlgorithmIdentifier identifier) +{ + switch (identifier) { + case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5: + case CryptoAlgorithmIdentifier::RSA_PSS: + case CryptoAlgorithmIdentifier::RSA_OAEP: + case CryptoAlgorithmIdentifier::AES_CTR: + case CryptoAlgorithmIdentifier::AES_CBC: + case CryptoAlgorithmIdentifier::AES_CMAC: + case CryptoAlgorithmIdentifier::AES_GCM: + case CryptoAlgorithmIdentifier::AES_CFB: + case CryptoAlgorithmIdentifier::AES_KW: + case CryptoAlgorithmIdentifier::HMAC: + return; + default: + throwNotSupportedError(state, scope); + } +} + +static void jsSubtleCryptoFunctionEncryptPromise(ExecState& state, Ref<DeferredPromise>&& promise) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(state.argumentCount() < 3)) { + promise->reject<IDLAny>(createNotEnoughArgumentsError(&state)); + return; + } + + auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::Encrypt); + RETURN_IF_EXCEPTION(scope, void()); + + auto key = toCryptoKey(state, state.uncheckedArgument(1)); + RETURN_IF_EXCEPTION(scope, void()); + + auto data = toVector(state, state.uncheckedArgument(2)); + RETURN_IF_EXCEPTION(scope, void()); + + if (params->identifier != key->algorithmIdentifier()) { + promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier")); + return; + } + + if (!key->allows(CryptoKeyUsageEncrypt)) { + promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't support encryption")); + return; + } + + auto algorithm = CryptoAlgorithmRegistry::singleton().create(key->algorithmIdentifier()); + if (UNLIKELY(!algorithm)) { + throwNotSupportedError(state, scope); + return; + } + + auto callback = [capturedPromise = promise.copyRef()](const Vector<uint8_t>& cipherText) mutable { + fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), cipherText.data(), cipherText.size()); + return; + }; + auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable { + rejectWithException(WTFMove(capturedPromise), ec); + }; + + auto subtle = jsDynamicDowncast<JSSubtleCrypto*>(vm, state.thisValue()); + ASSERT(subtle); + algorithm->encrypt(WTFMove(params), key.releaseNonNull(), WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue()); +} + +static void jsSubtleCryptoFunctionDecryptPromise(ExecState& state, Ref<DeferredPromise>&& promise) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(state.argumentCount() < 3)) { + promise->reject<IDLAny>(createNotEnoughArgumentsError(&state)); + return; + } + + auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::Decrypt); + RETURN_IF_EXCEPTION(scope, void()); + + auto key = toCryptoKey(state, state.uncheckedArgument(1)); + RETURN_IF_EXCEPTION(scope, void()); + + auto data = toVector(state, state.uncheckedArgument(2)); + RETURN_IF_EXCEPTION(scope, void()); + + if (params->identifier != key->algorithmIdentifier()) { + promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier")); + return; + } + + if (!key->allows(CryptoKeyUsageDecrypt)) { + promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't support decryption")); + return; + } + + auto algorithm = CryptoAlgorithmRegistry::singleton().create(key->algorithmIdentifier()); + if (UNLIKELY(!algorithm)) { + throwNotSupportedError(state, scope); + return; + } + + auto callback = [capturedPromise = promise.copyRef()](const Vector<uint8_t>& plainText) mutable { + fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), plainText.data(), plainText.size()); + return; + }; + auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable { + rejectWithException(WTFMove(capturedPromise), ec); + }; + + auto subtle = jsDynamicDowncast<JSSubtleCrypto*>(vm, state.thisValue()); + ASSERT(subtle); + algorithm->decrypt(WTFMove(params), key.releaseNonNull(), WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue()); +} + +static void jsSubtleCryptoFunctionSignPromise(ExecState& state, Ref<DeferredPromise>&& promise) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(state.argumentCount() < 3)) { + promise->reject<IDLAny>(createNotEnoughArgumentsError(&state)); + return; + } + + auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::Sign); + RETURN_IF_EXCEPTION(scope, void()); + + auto key = toCryptoKey(state, state.uncheckedArgument(1)); + RETURN_IF_EXCEPTION(scope, void()); + + auto data = toVector(state, state.uncheckedArgument(2)); + RETURN_IF_EXCEPTION(scope, void()); + + if (params->identifier != key->algorithmIdentifier()) { + promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier")); + return; + } + + if (!key->allows(CryptoKeyUsageSign)) { + promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't support signing")); + return; + } + + auto algorithm = CryptoAlgorithmRegistry::singleton().create(key->algorithmIdentifier()); + if (UNLIKELY(!algorithm)) { + throwNotSupportedError(state, scope); + return; + } + + auto callback = [capturedPromise = promise.copyRef()](const Vector<uint8_t>& signature) mutable { + fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), signature.data(), signature.size()); + return; + }; + auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable { + rejectWithException(WTFMove(capturedPromise), ec); + }; + + JSSubtleCrypto* subtle = jsDynamicDowncast<JSSubtleCrypto*>(vm, state.thisValue()); + ASSERT(subtle); + algorithm->sign(key.releaseNonNull(), WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue()); +} + +static void jsSubtleCryptoFunctionVerifyPromise(ExecState& state, Ref<DeferredPromise>&& promise) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(state.argumentCount() < 4)) { + promise->reject<IDLAny>(createNotEnoughArgumentsError(&state)); + return; + } + + auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::Verify); + RETURN_IF_EXCEPTION(scope, void()); + + auto key = toCryptoKey(state, state.uncheckedArgument(1)); + RETURN_IF_EXCEPTION(scope, void()); + + auto signature = toVector(state, state.uncheckedArgument(2)); + RETURN_IF_EXCEPTION(scope, void()); + + auto data = toVector(state, state.uncheckedArgument(3)); + RETURN_IF_EXCEPTION(scope, void()); + + if (params->identifier != key->algorithmIdentifier()) { + promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't match AlgorithmIdentifier")); + return; + } + + if (!key->allows(CryptoKeyUsageVerify)) { + promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("CryptoKey doesn't support verification")); + return; + } + + auto algorithm = CryptoAlgorithmRegistry::singleton().create(key->algorithmIdentifier()); + if (UNLIKELY(!algorithm)) { + throwNotSupportedError(state, scope); + return; + } + + auto callback = [capturedPromise = promise.copyRef()](bool result) mutable { + capturedPromise->resolve<IDLBoolean>(result); + return; + }; + auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable { + rejectWithException(WTFMove(capturedPromise), ec); + }; + + auto subtle = jsDynamicDowncast<JSSubtleCrypto*>(vm, state.thisValue()); + ASSERT(subtle); + algorithm->verify(key.releaseNonNull(), WTFMove(signature), WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue()); +} + +static void jsSubtleCryptoFunctionDigestPromise(ExecState& state, Ref<DeferredPromise>&& promise) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(state.argumentCount() < 2)) { + promise->reject<IDLAny>(createNotEnoughArgumentsError(&state)); + return; + } + + auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::Digest); + RETURN_IF_EXCEPTION(scope, void()); + + auto data = toVector(state, state.uncheckedArgument(1)); + RETURN_IF_EXCEPTION(scope, void()); + + auto algorithm = CryptoAlgorithmRegistry::singleton().create(params->identifier); + if (UNLIKELY(!algorithm)) { + throwNotSupportedError(state, scope); + return; + } + + auto callback = [capturedPromise = promise.copyRef()](const Vector<uint8_t>& digest) mutable { + fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), digest.data(), digest.size()); + return; + }; + auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable { + rejectWithException(WTFMove(capturedPromise), ec); + }; + + auto subtle = jsDynamicDowncast<JSSubtleCrypto*>(vm, state.thisValue()); + ASSERT(subtle); + algorithm->digest(WTFMove(data), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue()); +} + +static void jsSubtleCryptoFunctionDeriveKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(state.argumentCount() < 5)) { + promise->reject<IDLAny>(createNotEnoughArgumentsError(&state)); + return; + } + + auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::DeriveKey); + RETURN_IF_EXCEPTION(scope, void()); + + // We should always return a NOT_SUPPORTED_ERR since we currently don't support any algorithms that has deriveKey operation. + ASSERT_NOT_REACHED(); +} + +static void jsSubtleCryptoFunctionDeriveBitsPromise(ExecState& state, Ref<DeferredPromise>&& promise) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(state.argumentCount() < 3)) { + promise->reject<IDLAny>(createNotEnoughArgumentsError(&state)); + return; + } + + auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::DeriveBits); + RETURN_IF_EXCEPTION(scope, void()); + + // We should always return a NOT_SUPPORTED_ERR since we currently don't support any algorithms that has deriveBits operation. + ASSERT_NOT_REACHED(); +} + +static void jsSubtleCryptoFunctionGenerateKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(state.argumentCount() < 3)) { + promise->reject<IDLAny>(createNotEnoughArgumentsError(&state)); + return; + } + + auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(0), Operations::GenerateKey); + RETURN_IF_EXCEPTION(scope, void()); + + auto extractable = state.uncheckedArgument(1).toBoolean(&state); + RETURN_IF_EXCEPTION(scope, void()); + + auto keyUsages = cryptoKeyUsageBitmapFromJSValue(state, state.uncheckedArgument(2)); + RETURN_IF_EXCEPTION(scope, void()); + + auto algorithm = CryptoAlgorithmRegistry::singleton().create(params->identifier); + if (UNLIKELY(!algorithm)) { + throwNotSupportedError(state, scope); + return; + } + + auto callback = [capturedPromise = promise.copyRef()](KeyOrKeyPair&& keyOrKeyPair) mutable { + WTF::switchOn(keyOrKeyPair, + [&capturedPromise] (RefPtr<CryptoKey>& key) { + if ((key->type() == CryptoKeyType::Private || key->type() == CryptoKeyType::Secret) && !key->usagesBitmap()) { + rejectWithException(WTFMove(capturedPromise), SYNTAX_ERR); + return; + } + capturedPromise->resolve<IDLInterface<CryptoKey>>(*key); + }, + [&capturedPromise] (CryptoKeyPair& keyPair) { + if (!keyPair.privateKey->usagesBitmap()) { + rejectWithException(WTFMove(capturedPromise), SYNTAX_ERR); + return; + } + capturedPromise->resolve<IDLDictionary<CryptoKeyPair>>(keyPair); + } + ); + }; + auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable { + rejectWithException(WTFMove(capturedPromise), ec); + }; + + // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously + // regardless what kind of keys it produces: https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-generateKey + // That's simply not efficient for AES and HMAC keys. Therefore, we perform it as an async task conditionally. + algorithm->generateKey(*params, extractable, keyUsages, WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state)); +} + +static void jsSubtleCryptoFunctionImportKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(state.argumentCount() < 5)) { + promise->reject<IDLAny>(createNotEnoughArgumentsError(&state)); + return; + } + + auto format = convertEnumeration<SubtleCrypto::KeyFormat>(state, state.uncheckedArgument(0)); + RETURN_IF_EXCEPTION(scope, void()); + + auto keyData = toKeyData(state, format, state.uncheckedArgument(1)); + RETURN_IF_EXCEPTION(scope, void()); + + auto params = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(2), Operations::ImportKey); + RETURN_IF_EXCEPTION(scope, void()); + + auto extractable = state.uncheckedArgument(3).toBoolean(&state); + RETURN_IF_EXCEPTION(scope, void()); + + auto keyUsages = cryptoKeyUsageBitmapFromJSValue(state, state.uncheckedArgument(4)); + RETURN_IF_EXCEPTION(scope, void()); + + auto algorithm = CryptoAlgorithmRegistry::singleton().create(params->identifier); + if (UNLIKELY(!algorithm)) { + throwNotSupportedError(state, scope); + return; + } + + auto callback = [capturedPromise = promise.copyRef()](CryptoKey& key) mutable { + if ((key.type() == CryptoKeyType::Private || key.type() == CryptoKeyType::Secret) && !key.usagesBitmap()) { + rejectWithException(WTFMove(capturedPromise), SYNTAX_ERR); + return; + } + capturedPromise->resolve<IDLInterface<CryptoKey>>(key); + }; + auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable { + rejectWithException(WTFMove(capturedPromise), ec); + }; + + // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously: + // https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-importKey + // It is not beneficial for less time consuming operations. Therefore, we perform it synchronously. + algorithm->importKey(format, WTFMove(keyData), WTFMove(params), extractable, keyUsages, WTFMove(callback), WTFMove(exceptionCallback)); +} + +static void jsSubtleCryptoFunctionExportKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(state.argumentCount() < 2)) { + promise->reject<IDLAny>(createNotEnoughArgumentsError(&state)); + return; + } + + auto format = convertEnumeration<SubtleCrypto::KeyFormat>(state, state.uncheckedArgument(0)); + RETURN_IF_EXCEPTION(scope, void()); + + auto key = toCryptoKey(state, state.uncheckedArgument(1)); + RETURN_IF_EXCEPTION(scope, void()); + + supportExportKeyThrow(state, scope, key->algorithmIdentifier()); + RETURN_IF_EXCEPTION(scope, void()); + + if (!key->extractable()) { + promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("The CryptoKey is nonextractable")); + return; + } + + auto algorithm = CryptoAlgorithmRegistry::singleton().create(key->algorithmIdentifier()); + if (UNLIKELY(!algorithm)) { + throwNotSupportedError(state, scope); + return; + } + + auto callback = [capturedPromise = promise.copyRef()](SubtleCrypto::KeyFormat format, KeyData&& key) mutable { + switch (format) { + case SubtleCrypto::KeyFormat::Spki: + case SubtleCrypto::KeyFormat::Pkcs8: + case SubtleCrypto::KeyFormat::Raw: { + Vector<uint8_t>& rawKey = WTF::get<Vector<uint8_t>>(key); + fulfillPromiseWithArrayBuffer(WTFMove(capturedPromise), rawKey.data(), rawKey.size()); + return; + } + case SubtleCrypto::KeyFormat::Jwk: + capturedPromise->resolve<IDLDictionary<JsonWebKey>>(WTFMove(WTF::get<JsonWebKey>(key))); + return; + } + ASSERT_NOT_REACHED(); + }; + auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable { + rejectWithException(WTFMove(capturedPromise), ec); + }; + + // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously: + // https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-exportKey + // It is not beneficial for less time consuming operations. Therefore, we perform it synchronously. + algorithm->exportKey(format, key.releaseNonNull(), WTFMove(callback), WTFMove(exceptionCallback)); +} + +static void jsSubtleCryptoFunctionWrapKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(state.argumentCount() < 4)) { + promise->reject<IDLAny>(createNotEnoughArgumentsError(&state)); + return; + } + + auto format = convertEnumeration<SubtleCrypto::KeyFormat>(state, state.uncheckedArgument(0)); + RETURN_IF_EXCEPTION(scope, void()); + + auto key = toCryptoKey(state, state.uncheckedArgument(1)); + RETURN_IF_EXCEPTION(scope, void()); + + auto wrappingKey = toCryptoKey(state, state.uncheckedArgument(2)); + RETURN_IF_EXCEPTION(scope, void()); + + auto catchScope = DECLARE_CATCH_SCOPE(vm); + bool isEncryption = false; + auto wrapParams = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(3), Operations::WrapKey); + if (catchScope.exception()) { + catchScope.clearException(); + wrapParams = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(3), Operations::Encrypt); + RETURN_IF_EXCEPTION(scope, void()); + isEncryption = true; + } + + if (wrapParams->identifier != wrappingKey->algorithmIdentifier()) { + promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("Wrapping CryptoKey doesn't match AlgorithmIdentifier")); + return; + } + + if (!wrappingKey->allows(CryptoKeyUsageWrapKey)) { + promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("Wrapping CryptoKey doesn't support wrapKey operation")); + return; + } + + supportExportKeyThrow(state, scope, key->algorithmIdentifier()); + RETURN_IF_EXCEPTION(scope, void()); + + if (!key->extractable()) { + promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("The CryptoKey is nonextractable")); + return; + } + + auto exportAlgorithm = CryptoAlgorithmRegistry::singleton().create(key->algorithmIdentifier()); + if (UNLIKELY(!exportAlgorithm)) { + throwNotSupportedError(state, scope); + return; + } + + auto wrapAlgorithm = CryptoAlgorithmRegistry::singleton().create(wrappingKey->algorithmIdentifier()); + if (UNLIKELY(!wrapAlgorithm)) { + throwNotSupportedError(state, scope); + return; + } + + auto context = scriptExecutionContextFromExecState(&state); + + auto subtle = jsDynamicDowncast<JSSubtleCrypto*>(vm, state.thisValue()); + ASSERT(subtle); + auto& workQueue = subtle->wrapped().workQueue(); + + auto callback = [promise = promise.copyRef(), wrapAlgorithm, wrappingKey = WTFMove(wrappingKey), wrapParams = WTFMove(wrapParams), isEncryption, context, &workQueue](SubtleCrypto::KeyFormat format, KeyData&& key) mutable { + Vector<uint8_t> bytes; + switch (format) { + case SubtleCrypto::KeyFormat::Spki: + case SubtleCrypto::KeyFormat::Pkcs8: + case SubtleCrypto::KeyFormat::Raw: + bytes = WTF::get<Vector<uint8_t>>(key); + break; + case SubtleCrypto::KeyFormat::Jwk: { + auto jwk = toJS<IDLDictionary<JsonWebKey>>(*(promise->globalObject()->globalExec()), *(promise->globalObject()), WTFMove(WTF::get<JsonWebKey>(key))); + String jwkString = JSONStringify(promise->globalObject()->globalExec(), jwk, 0); + CString jwkUtf8String = jwkString.utf8(StrictConversion); + bytes.append(jwkUtf8String.data(), jwkUtf8String.length()); + } + } + + auto callback = [promise = promise.copyRef()](const Vector<uint8_t>& wrappedKey) mutable { + fulfillPromiseWithArrayBuffer(WTFMove(promise), wrappedKey.data(), wrappedKey.size()); + return; + }; + auto exceptionCallback = [promise = WTFMove(promise)](ExceptionCode ec) mutable { + rejectWithException(WTFMove(promise), ec); + }; + + if (!isEncryption) { + // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously: + // https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-wrapKey + // It is not beneficial for less time consuming operations. Therefore, we perform it synchronously. + wrapAlgorithm->wrapKey(wrappingKey.releaseNonNull(), WTFMove(bytes), WTFMove(callback), WTFMove(exceptionCallback)); + return; + } + // The following operation should be performed asynchronously. + wrapAlgorithm->encrypt(WTFMove(wrapParams), wrappingKey.releaseNonNull(), WTFMove(bytes), WTFMove(callback), WTFMove(exceptionCallback), *context, workQueue); + }; + auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable { + rejectWithException(WTFMove(capturedPromise), ec); + }; + + // The following operation should be performed synchronously. + exportAlgorithm->exportKey(format, key.releaseNonNull(), WTFMove(callback), WTFMove(exceptionCallback)); +} + +static void jsSubtleCryptoFunctionUnwrapKeyPromise(ExecState& state, Ref<DeferredPromise>&& promise) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(state.argumentCount() < 7)) { + promise->reject<IDLAny>(createNotEnoughArgumentsError(&state)); + return; + } + + auto format = convertEnumeration<SubtleCrypto::KeyFormat>(state, state.uncheckedArgument(0)); + RETURN_IF_EXCEPTION(scope, void()); + + auto wrappedKey = toVector(state, state.uncheckedArgument(1)); + RETURN_IF_EXCEPTION(scope, void()); + + auto unwrappingKey = toCryptoKey(state, state.uncheckedArgument(2)); + RETURN_IF_EXCEPTION(scope, void()); + + auto catchScope = DECLARE_CATCH_SCOPE(vm); + bool isDecryption = false; + auto unwrapParams = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(3), Operations::UnwrapKey); + if (catchScope.exception()) { + catchScope.clearException(); + unwrapParams = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(3), Operations::Decrypt); + RETURN_IF_EXCEPTION(scope, void()); + isDecryption = true; + } + + auto unwrappedKeyAlgorithm = normalizeCryptoAlgorithmParameters(state, state.uncheckedArgument(4), Operations::ImportKey); + RETURN_IF_EXCEPTION(scope, void()); + + auto extractable = state.uncheckedArgument(5).toBoolean(&state); + RETURN_IF_EXCEPTION(scope, void()); + + auto keyUsages = cryptoKeyUsageBitmapFromJSValue(state, state.uncheckedArgument(6)); + RETURN_IF_EXCEPTION(scope, void()); + + if (unwrapParams->identifier != unwrappingKey->algorithmIdentifier()) { + promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("Unwrapping CryptoKey doesn't match unwrap AlgorithmIdentifier")); + return; + } + + if (!unwrappingKey->allows(CryptoKeyUsageUnwrapKey)) { + promise->reject(INVALID_ACCESS_ERR, ASCIILiteral("Unwrapping CryptoKey doesn't support unwrapKey operation")); + return; + } + + auto importAlgorithm = CryptoAlgorithmRegistry::singleton().create(unwrappedKeyAlgorithm->identifier); + if (UNLIKELY(!importAlgorithm)) { + throwNotSupportedError(state, scope); + return; + } + + auto unwrapAlgorithm = CryptoAlgorithmRegistry::singleton().create(unwrappingKey->algorithmIdentifier()); + if (UNLIKELY(!unwrapAlgorithm)) { + throwNotSupportedError(state, scope); + return; + } + + auto callback = [promise = promise.copyRef(), format, importAlgorithm, unwrappedKeyAlgorithm = WTFMove(unwrappedKeyAlgorithm), extractable, keyUsages](const Vector<uint8_t>& bytes) mutable { + ExecState& state = *(promise->globalObject()->globalExec()); + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + KeyData keyData; + switch (format) { + case SubtleCrypto::KeyFormat::Spki: + case SubtleCrypto::KeyFormat::Pkcs8: + case SubtleCrypto::KeyFormat::Raw: + keyData = bytes; + break; + case SubtleCrypto::KeyFormat::Jwk: { + String jwkString(reinterpret_cast_ptr<const char*>(bytes.data()), bytes.size()); + JSC::JSLockHolder locker(vm); + auto jwk = JSONParse(&state, jwkString); + if (!jwk) { + promise->reject(DataError, ASCIILiteral("WrappedKey cannot be converted to a JSON object")); + return; + } + keyData = toKeyData(state, format, jwk); + RETURN_IF_EXCEPTION(scope, void()); + } + } + + auto callback = [promise = promise.copyRef()](CryptoKey& key) mutable { + if ((key.type() == CryptoKeyType::Private || key.type() == CryptoKeyType::Secret) && !key.usagesBitmap()) { + rejectWithException(WTFMove(promise), SYNTAX_ERR); + return; + } + promise->resolve<IDLInterface<CryptoKey>>(key); + }; + auto exceptionCallback = [promise = WTFMove(promise)](ExceptionCode ec) mutable { + rejectWithException(WTFMove(promise), ec); + }; + + // The following operation should be performed synchronously. + importAlgorithm->importKey(format, WTFMove(keyData), WTFMove(unwrappedKeyAlgorithm), extractable, keyUsages, WTFMove(callback), WTFMove(exceptionCallback)); + }; + auto exceptionCallback = [capturedPromise = WTFMove(promise)](ExceptionCode ec) mutable { + rejectWithException(WTFMove(capturedPromise), ec); + }; + + if (!isDecryption) { + // The 11 December 2014 version of the specification suggests we should perform the following task asynchronously: + // https://www.w3.org/TR/WebCryptoAPI/#SubtleCrypto-method-unwrapKey + // It is not beneficial for less time consuming operations. Therefore, we perform it synchronously. + unwrapAlgorithm->unwrapKey(unwrappingKey.releaseNonNull(), WTFMove(wrappedKey), WTFMove(callback), WTFMove(exceptionCallback)); + return; + } + auto subtle = jsDynamicDowncast<JSSubtleCrypto*>(vm, state.thisValue()); + ASSERT(subtle); + // The following operation should be performed asynchronously. + unwrapAlgorithm->decrypt(WTFMove(unwrapParams), unwrappingKey.releaseNonNull(), WTFMove(wrappedKey), WTFMove(callback), WTFMove(exceptionCallback), *scriptExecutionContextFromExecState(&state), subtle->wrapped().workQueue()); +} + +JSValue JSSubtleCrypto::encrypt(ExecState& state) +{ + return callPromiseFunction<jsSubtleCryptoFunctionEncryptPromise, PromiseExecutionScope::WindowOrWorker>(state); +} + +JSValue JSSubtleCrypto::decrypt(ExecState& state) +{ + return callPromiseFunction<jsSubtleCryptoFunctionDecryptPromise, PromiseExecutionScope::WindowOrWorker>(state); +} + +JSValue JSSubtleCrypto::sign(ExecState& state) +{ + return callPromiseFunction<jsSubtleCryptoFunctionSignPromise, PromiseExecutionScope::WindowOrWorker>(state); +} + +JSValue JSSubtleCrypto::verify(ExecState& state) +{ + return callPromiseFunction<jsSubtleCryptoFunctionVerifyPromise, PromiseExecutionScope::WindowOrWorker>(state); +} + +JSValue JSSubtleCrypto::digest(ExecState& state) +{ + return callPromiseFunction<jsSubtleCryptoFunctionDigestPromise, PromiseExecutionScope::WindowOrWorker>(state); +} + +JSValue JSSubtleCrypto::deriveKey(ExecState& state) +{ + return callPromiseFunction<jsSubtleCryptoFunctionDeriveKeyPromise, PromiseExecutionScope::WindowOrWorker>(state); +} + +JSValue JSSubtleCrypto::deriveBits(ExecState& state) +{ + return callPromiseFunction<jsSubtleCryptoFunctionDeriveBitsPromise, PromiseExecutionScope::WindowOrWorker>(state); +} + +JSValue JSSubtleCrypto::generateKey(ExecState& state) +{ + return callPromiseFunction<jsSubtleCryptoFunctionGenerateKeyPromise, PromiseExecutionScope::WindowOrWorker>(state); +} + +JSValue JSSubtleCrypto::importKey(ExecState& state) +{ + return callPromiseFunction<jsSubtleCryptoFunctionImportKeyPromise, PromiseExecutionScope::WindowOrWorker>(state); +} + +JSValue JSSubtleCrypto::exportKey(ExecState& state) +{ + return callPromiseFunction<jsSubtleCryptoFunctionExportKeyPromise, PromiseExecutionScope::WindowOrWorker>(state); +} + +JSValue JSSubtleCrypto::wrapKey(ExecState& state) +{ + return callPromiseFunction<jsSubtleCryptoFunctionWrapKeyPromise, PromiseExecutionScope::WindowOrWorker>(state); +} + +JSValue JSSubtleCrypto::unwrapKey(ExecState& state) +{ + return callPromiseFunction<jsSubtleCryptoFunctionUnwrapKeyPromise, PromiseExecutionScope::WindowOrWorker>(state); +} + +} // namespace WebCore + +#endif diff --git a/Source/WebCore/bindings/js/JSTextCustom.cpp b/Source/WebCore/bindings/js/JSTextCustom.cpp index 4b6e52965..8343e5043 100644 --- a/Source/WebCore/bindings/js/JSTextCustom.cpp +++ b/Source/WebCore/bindings/js/JSTextCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,34 +10,38 @@ * 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. ``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 - * 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. + * 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 "JSText.h" -#include "Text.h" +#include "JSCDATASection.h" + +namespace WebCore { using namespace JSC; -namespace WebCore { +JSValue toJSNewlyCreated(ExecState*, JSDOMGlobalObject* globalObject, Ref<Text>&& text) +{ + if (is<CDATASection>(text.get())) + return createWrapper<CDATASection>(globalObject, WTFMove(text)); + return createWrapper<Text>(globalObject, WTFMove(text)); +} -JSValue toJSNewlyCreated(ExecState* exec, JSDOMGlobalObject* globalObject, Text* text) +JSValue toJS(ExecState* state, JSDOMGlobalObject* globalObject, Text& text) { - if (!text) - return jsNull(); - - return CREATE_DOM_WRAPPER(exec, globalObject, Text, text); + return wrap(state, globalObject, text); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSTextTrackCueCustom.cpp b/Source/WebCore/bindings/js/JSTextTrackCueCustom.cpp index 1605ab3e3..a297e8df2 100644 --- a/Source/WebCore/bindings/js/JSTextTrackCueCustom.cpp +++ b/Source/WebCore/bindings/js/JSTextTrackCueCustom.cpp @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -28,7 +28,10 @@ #if ENABLE(VIDEO_TRACK) #include "JSTextTrackCue.h" + +#include "JSDataCue.h" #include "JSTrackCustom.h" +#include "JSVTTCue.h" #include "TextTrack.h" using namespace JSC; @@ -37,18 +40,14 @@ namespace WebCore { bool JSTextTrackCueOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor) { - JSTextTrackCue* jsTextTrackCue = jsCast<JSTextTrackCue*>(handle.get().asCell()); - TextTrackCue& textTrackCue = jsTextTrackCue->impl(); + JSTextTrackCue* jsTextTrackCue = jsCast<JSTextTrackCue*>(handle.slot()->asCell()); + TextTrackCue& textTrackCue = jsTextTrackCue->wrapped(); // If the cue is firing event listeners, its wrapper is reachable because // the wrapper is responsible for marking those event listeners. if (textTrackCue.isFiringEventListeners()) return true; - // If the cue has no event listeners and has no custom properties, it is not reachable. - if (!textTrackCue.hasEventListeners() && !jsTextTrackCue->hasCustomProperties()) - return false; - // If the cue is not associated with a track, it is not reachable. if (!textTrackCue.track()) return false; @@ -56,20 +55,29 @@ bool JSTextTrackCueOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> h return visitor.containsOpaqueRoot(root(textTrackCue.track())); } -void JSTextTrackCue::visitChildren(JSCell* cell, SlotVisitor& visitor) +JSValue toJSNewlyCreated(ExecState*, JSDOMGlobalObject* globalObject, Ref<TextTrackCue>&& cue) +{ + switch (cue->cueType()) { + case TextTrackCue::Data: + return createWrapper<DataCue>(globalObject, WTFMove(cue)); + case TextTrackCue::WebVTT: + case TextTrackCue::Generic: + return createWrapper<VTTCue>(globalObject, WTFMove(cue)); + default: + ASSERT_NOT_REACHED(); + return jsNull(); + } +} + +JSValue toJS(ExecState* state, JSDOMGlobalObject* globalObject, TextTrackCue& cue) +{ + return wrap(state, globalObject, cue); +} + +void JSTextTrackCue::visitAdditionalChildren(SlotVisitor& visitor) { - JSTextTrackCue* jsTextTrackCue = jsCast<JSTextTrackCue*>(cell); - ASSERT_GC_OBJECT_INHERITS(jsTextTrackCue, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(jsTextTrackCue->structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(jsTextTrackCue, visitor); - - // Mark the cue's track root if it has one. - TextTrackCue& textTrackCue = jsTextTrackCue->impl(); - if (TextTrack* textTrack = textTrackCue.track()) + if (TextTrack* textTrack = wrapped().track()) visitor.addOpaqueRoot(root(textTrack)); - - textTrackCue.visitJSEventListeners(visitor); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSTextTrackCustom.cpp b/Source/WebCore/bindings/js/JSTextTrackCustom.cpp index 078f6f256..793b6eadf 100644 --- a/Source/WebCore/bindings/js/JSTextTrackCustom.cpp +++ b/Source/WebCore/bindings/js/JSTextTrackCustom.cpp @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,7 +26,9 @@ #include "config.h" #if ENABLE(VIDEO_TRACK) + #include "JSTextTrack.h" + #include "JSTextTrackCueList.h" #include "JSTrackCustom.h" @@ -34,45 +36,23 @@ using namespace JSC; namespace WebCore { -void JSTextTrack::visitChildren(JSCell* cell, SlotVisitor& visitor) +void JSTextTrack::visitAdditionalChildren(SlotVisitor& visitor) { - JSTextTrack* jsTextTrack = jsCast<JSTextTrack*>(cell); - ASSERT_GC_OBJECT_INHERITS(jsTextTrack, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(jsTextTrack->structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(jsTextTrack, visitor); - - TextTrack& textTrack = jsTextTrack->impl(); - visitor.addOpaqueRoot(root(&textTrack)); - - textTrack.visitJSEventListeners(visitor); + visitor.addOpaqueRoot(root(&wrapped())); } -void JSTextTrack::setKind(ExecState* exec, JSValue value) +void JSTextTrack::setLanguage(ExecState& state, JSValue value) { - UNUSED_PARAM(exec); #if ENABLE(MEDIA_SOURCE) - const String& nativeValue(value.isEmpty() ? String() : value.toString(exec)->value(exec)); - if (exec->hadException()) - return; - impl().setKind(nativeValue); -#else - UNUSED_PARAM(value); - return; -#endif -} + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); -void JSTextTrack::setLanguage(ExecState* exec, JSValue value) -{ - UNUSED_PARAM(exec); -#if ENABLE(MEDIA_SOURCE) - const String& nativeValue(value.isEmpty() ? String() : value.toString(exec)->value(exec)); - if (exec->hadException()) - return; - impl().setLanguage(nativeValue); + auto string = value.toWTFString(&state); + RETURN_IF_EXCEPTION(scope, void()); + wrapped().setLanguage(string); #else + UNUSED_PARAM(state); UNUSED_PARAM(value); - return; #endif } diff --git a/Source/WebCore/bindings/js/JSTextTrackListCustom.cpp b/Source/WebCore/bindings/js/JSTextTrackListCustom.cpp index 8be5ef40c..3f46f4331 100644 --- a/Source/WebCore/bindings/js/JSTextTrackListCustom.cpp +++ b/Source/WebCore/bindings/js/JSTextTrackListCustom.cpp @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,6 +26,7 @@ #include "config.h" #if ENABLE(VIDEO_TRACK) + #include "JSTextTrackList.h" #include "Element.h" @@ -35,17 +36,9 @@ using namespace JSC; namespace WebCore { -void JSTextTrackList::visitChildren(JSCell* cell, SlotVisitor& visitor) +void JSTextTrackList::visitAdditionalChildren(JSC::SlotVisitor& visitor) { - JSTextTrackList* jsTextTrackList = jsCast<JSTextTrackList*>(cell); - ASSERT_GC_OBJECT_INHERITS(jsTextTrackList, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(jsTextTrackList->structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(jsTextTrackList, visitor); - - TextTrackList& textTrackList = jsTextTrackList->impl(); - visitor.addOpaqueRoot(root(textTrackList.element())); - textTrackList.visitJSEventListeners(visitor); + visitor.addOpaqueRoot(root(wrapped().element())); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSTouchCustom.cpp b/Source/WebCore/bindings/js/JSTouchCustom.cpp deleted file mode 100644 index d9434c0f2..000000000 --- a/Source/WebCore/bindings/js/JSTouchCustom.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2010, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#if !PLATFORM(IOS) -#if ENABLE(TOUCH_EVENTS) - -#include "JSTouch.h" - -#include "Touch.h" - -using namespace JSC; - -namespace WebCore { - -JSValue toJSNewlyCreated(ExecState* exec, JSDOMGlobalObject* globalObject, Touch* touch) -{ - if (!touch) - return jsNull(); - - return CREATE_DOM_WRAPPER(exec, globalObject, Touch, touch); -} - -} // namespace WebCore - -#endif // ENABLE(TOUCH_EVENTS) -#endif // !PLATFORM(IOS) diff --git a/Source/WebCore/bindings/js/JSTouchListCustom.cpp b/Source/WebCore/bindings/js/JSTouchListCustom.cpp deleted file mode 100644 index 11318c005..000000000 --- a/Source/WebCore/bindings/js/JSTouchListCustom.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2010, The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#if !PLATFORM(IOS) -#if ENABLE(TOUCH_EVENTS) - -#include "JSTouchList.h" - -#include "TouchList.h" - -using namespace JSC; - -namespace WebCore { - -JSValue toJSNewlyCreated(ExecState* exec, JSDOMGlobalObject* globalObject, TouchList* touchList) -{ - if (!touchList) - return jsNull(); - - return CREATE_DOM_WRAPPER(exec, globalObject, TouchList, touchList); -} - -} // namespace WebCore - -#endif // ENABLE(TOUCH_EVENTS) -#endif // !PLATFORM(IOS) diff --git a/Source/WebCore/bindings/js/JSTrackCustom.cpp b/Source/WebCore/bindings/js/JSTrackCustom.cpp index 0ad233618..57bb6b2c5 100644 --- a/Source/WebCore/bindings/js/JSTrackCustom.cpp +++ b/Source/WebCore/bindings/js/JSTrackCustom.cpp @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -37,49 +37,22 @@ using namespace JSC; namespace WebCore { -TrackBase* toTrack(JSValue value) +JSC::JSValue toJS(JSC::ExecState* state, JSDOMGlobalObject* globalObject, TrackBase& track) { - if (!value.isObject()) - return 0; - - JSObject* object = asObject(value); - if (object->inherits(JSTextTrack::info())) - return &jsCast<JSTextTrack*>(object)->impl(); - - // FIXME: Fill in additional tests and casts here for VideoTrack and AudioTrack when - // they have been added to WebCore. - - return 0; -} - -JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, TrackBase* track) -{ - if (!track) - return jsNull(); - - JSObject* wrapper = getCachedWrapper(currentWorld(exec), track); - if (wrapper) - return wrapper; - - switch (track->type()) { + switch (track.type()) { case TrackBase::BaseTrack: // This should never happen. ASSERT_NOT_REACHED(); break; - - case TrackBase::AudioTrack: - return CREATE_DOM_WRAPPER(exec, globalObject, AudioTrack, track); - break; + case TrackBase::AudioTrack: + return wrap(state, globalObject, downcast<AudioTrack>(track)); case TrackBase::VideoTrack: - return CREATE_DOM_WRAPPER(exec, globalObject, VideoTrack, track); - break; - + return wrap(state, globalObject, downcast<VideoTrack>(track)); case TrackBase::TextTrack: - return CREATE_DOM_WRAPPER(exec, globalObject, TextTrack, track); - break; + return wrap(state, globalObject, downcast<TextTrack>(track)); } - + return jsNull(); } diff --git a/Source/WebCore/bindings/js/JSTrackCustom.h b/Source/WebCore/bindings/js/JSTrackCustom.h index 6e24a0915..30dd99066 100644 --- a/Source/WebCore/bindings/js/JSTrackCustom.h +++ b/Source/WebCore/bindings/js/JSTrackCustom.h @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,8 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSTrackCustom_h -#define JSTrackCustom_h +#pragma once #if ENABLE(VIDEO_TRACK) @@ -35,8 +34,7 @@ namespace WebCore { -TrackBase* toTrack(JSC::JSValue); -JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, TrackBase*); +JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, TrackBase&); inline void* root(TrackBase* track) { @@ -45,7 +43,6 @@ inline void* root(TrackBase* track) return track; } -} +} // namespace WebCore -#endif -#endif +#endif // ENABLE(VIDEO_TRACK) diff --git a/Source/WebCore/bindings/js/JSTreeWalkerCustom.cpp b/Source/WebCore/bindings/js/JSTreeWalkerCustom.cpp index 9f01659f9..2be08a991 100644 --- a/Source/WebCore/bindings/js/JSTreeWalkerCustom.cpp +++ b/Source/WebCore/bindings/js/JSTreeWalkerCustom.cpp @@ -20,24 +20,14 @@ #include "config.h" #include "JSTreeWalker.h" -#include "JSNode.h" #include "Node.h" -#include "NodeFilter.h" -#include "TreeWalker.h" - -using namespace JSC; +#include <heap/SlotVisitorInlines.h> namespace WebCore { -void JSTreeWalker::visitChildren(JSCell* cell, SlotVisitor& visitor) +void JSTreeWalker::visitAdditionalChildren(JSC::SlotVisitor& visitor) { - JSTreeWalker* thisObject = jsCast<JSTreeWalker*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(thisObject, visitor); - - if (NodeFilter* filter = thisObject->m_impl->filter()) + if (NodeFilter* filter = wrapped().filter()) visitor.addOpaqueRoot(filter); } diff --git a/Source/WebCore/bindings/js/JSUserMessageHandlersNamespaceCustom.cpp b/Source/WebCore/bindings/js/JSUserMessageHandlersNamespaceCustom.cpp new file mode 100644 index 000000000..1dd42d4fd --- /dev/null +++ b/Source/WebCore/bindings/js/JSUserMessageHandlersNamespaceCustom.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014 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 "JSUserMessageHandlersNamespace.h" + +#if ENABLE(USER_MESSAGE_HANDLERS) + +#include "JSDOMConvertInterface.h" +#include "JSDOMConvertStrings.h" +#include "JSUserMessageHandler.h" +#include <runtime/JSCInlines.h> + +using namespace JSC; + +namespace WebCore { + +bool JSUserMessageHandlersNamespace::getOwnPropertySlotDelegate(ExecState* exec, PropertyName propertyName, PropertySlot& slot) +{ + if (auto* handler = wrapped().handler(propertyNameToAtomicString(propertyName), globalObject()->world())) { + slot.setValue(this, ReadOnly | DontDelete | DontEnum, toJS<IDLInterface<UserMessageHandler>>(*exec, *globalObject(), *handler)); + return true; + } + return false; +} + +} + +#endif // ENABLE(USER_MESSAGE_HANDLERS) diff --git a/Source/WebCore/bindings/js/JSVideoTrackCustom.cpp b/Source/WebCore/bindings/js/JSVideoTrackCustom.cpp index a82e7b8bc..f79a3341f 100644 --- a/Source/WebCore/bindings/js/JSVideoTrackCustom.cpp +++ b/Source/WebCore/bindings/js/JSVideoTrackCustom.cpp @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -35,43 +35,38 @@ using namespace JSC; namespace WebCore { -void JSVideoTrack::visitChildren(JSCell* cell, SlotVisitor& visitor) +void JSVideoTrack::visitAdditionalChildren(SlotVisitor& visitor) { - JSVideoTrack* jsVideoTrack = jsCast<JSVideoTrack*>(cell); - ASSERT_GC_OBJECT_INHERITS(jsVideoTrack, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(jsVideoTrack->structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(jsVideoTrack, visitor); - - VideoTrack& videoTrack = jsVideoTrack->impl(); - visitor.addOpaqueRoot(root(&videoTrack)); + visitor.addOpaqueRoot(root(&wrapped())); } -void JSVideoTrack::setKind(ExecState* exec, JSValue value) +void JSVideoTrack::setKind(ExecState& state, JSValue value) { - UNUSED_PARAM(exec); #if ENABLE(MEDIA_SOURCE) - const String& nativeValue(value.isEmpty() ? String() : value.toString(exec)->value(exec)); - if (exec->hadException()) - return; - impl().setKind(nativeValue); + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto string = value.toWTFString(&state); + RETURN_IF_EXCEPTION(scope, void()); + wrapped().setKind(string); #else + UNUSED_PARAM(state); UNUSED_PARAM(value); - return; #endif } -void JSVideoTrack::setLanguage(ExecState* exec, JSValue value) +void JSVideoTrack::setLanguage(ExecState& state, JSValue value) { - UNUSED_PARAM(exec); #if ENABLE(MEDIA_SOURCE) - const String& nativeValue(value.isEmpty() ? String() : value.toString(exec)->value(exec)); - if (exec->hadException()) - return; - impl().setLanguage(nativeValue); + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto string = value.toWTFString(&state); + RETURN_IF_EXCEPTION(scope, void()); + wrapped().setLanguage(string); #else + UNUSED_PARAM(state); UNUSED_PARAM(value); - return; #endif } diff --git a/Source/WebCore/bindings/js/JSVideoTrackListCustom.cpp b/Source/WebCore/bindings/js/JSVideoTrackListCustom.cpp index 0a669d3e3..a2a36184a 100644 --- a/Source/WebCore/bindings/js/JSVideoTrackListCustom.cpp +++ b/Source/WebCore/bindings/js/JSVideoTrackListCustom.cpp @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,26 +26,18 @@ #include "config.h" #if ENABLE(VIDEO_TRACK) + #include "JSVideoTrackList.h" -#include "Element.h" #include "JSNodeCustom.h" using namespace JSC; namespace WebCore { -void JSVideoTrackList::visitChildren(JSCell* cell, SlotVisitor& visitor) +void JSVideoTrackList::visitAdditionalChildren(SlotVisitor& visitor) { - JSVideoTrackList* jsVideoTrackList = jsCast<JSVideoTrackList*>(cell); - ASSERT_GC_OBJECT_INHERITS(jsVideoTrackList, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(jsVideoTrackList->structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(jsVideoTrackList, visitor); - - VideoTrackList& videoTrackList = jsVideoTrackList->impl(); - visitor.addOpaqueRoot(root(videoTrackList.element())); - videoTrackList.visitJSEventListeners(visitor); + visitor.addOpaqueRoot(root(wrapped().element())); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSCDATASectionCustom.cpp b/Source/WebCore/bindings/js/JSWebGL2RenderingContextCustom.cpp index de655c129..9cefb0ea3 100644 --- a/Source/WebCore/bindings/js/JSCDATASectionCustom.cpp +++ b/Source/WebCore/bindings/js/JSWebGL2RenderingContextCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved. + * Copyright (C) 2015-2017 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -20,24 +20,25 @@ * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" -#include "JSCDATASection.h" -#include "CDATASection.h" +#if ENABLE(WEBGL) && ENABLE(WEBGL2) + +#include "JSWebGL2RenderingContext.h" +#include <heap/HeapInlines.h> using namespace JSC; namespace WebCore { -JSValue toJSNewlyCreated(ExecState* exec, JSDOMGlobalObject* globalObject, CDATASection* section) +void JSWebGL2RenderingContext::visitAdditionalChildren(SlotVisitor& visitor) { - if (!section) - return jsNull(); - - return CREATE_DOM_WRAPPER(exec, globalObject, CDATASection, section); + visitor.addOpaqueRoot(&wrapped()); } } // namespace WebCore + +#endif // ENABLE(WEBGL) diff --git a/Source/WebCore/bindings/js/JSWebGLRenderingContextBaseCustom.cpp b/Source/WebCore/bindings/js/JSWebGLRenderingContextBaseCustom.cpp new file mode 100644 index 000000000..66d7ebd04 --- /dev/null +++ b/Source/WebCore/bindings/js/JSWebGLRenderingContextBaseCustom.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2015-2017 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. ``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 + * 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" + +#if ENABLE(WEBGL) + +#include "EXTBlendMinMax.h" +#include "EXTFragDepth.h" +#include "EXTShaderTextureLOD.h" +#include "EXTTextureFilterAnisotropic.h" +#include "EXTsRGB.h" +#include "ExceptionCode.h" +#include "JSANGLEInstancedArrays.h" +#include "JSEXTBlendMinMax.h" +#include "JSEXTFragDepth.h" +#include "JSEXTShaderTextureLOD.h" +#include "JSEXTTextureFilterAnisotropic.h" +#include "JSEXTsRGB.h" +#include "JSHTMLCanvasElement.h" +#include "JSHTMLImageElement.h" +#include "JSImageData.h" +#include "JSOESElementIndexUint.h" +#include "JSOESStandardDerivatives.h" +#include "JSOESTextureFloat.h" +#include "JSOESTextureFloatLinear.h" +#include "JSOESTextureHalfFloat.h" +#include "JSOESTextureHalfFloatLinear.h" +#include "JSOESVertexArrayObject.h" +#include "JSWebGLBuffer.h" +#include "JSWebGLCompressedTextureATC.h" +#include "JSWebGLCompressedTexturePVRTC.h" +#include "JSWebGLCompressedTextureS3TC.h" +#include "JSWebGLDebugRendererInfo.h" +#include "JSWebGLDebugShaders.h" +#include "JSWebGLDepthTexture.h" +#include "JSWebGLDrawBuffers.h" +#include "JSWebGLFramebuffer.h" +#include "JSWebGLLoseContext.h" +#include "JSWebGLProgram.h" +#include "JSWebGLRenderbuffer.h" +#include "JSWebGLRenderingContext.h" +#include "JSWebGLShader.h" +#include "JSWebGLTexture.h" +#include "JSWebGLUniformLocation.h" +#include "JSWebGLVertexArrayObject.h" +#include "JSWebGLVertexArrayObjectOES.h" +#include "JSWebKitCSSMatrix.h" +#include "OESElementIndexUint.h" +#include "OESStandardDerivatives.h" +#include "OESTextureFloat.h" +#include "OESTextureFloatLinear.h" +#include "OESTextureHalfFloat.h" +#include "OESTextureHalfFloatLinear.h" +#include "OESVertexArrayObject.h" +#include "WebGLBuffer.h" +#include "WebGLCompressedTextureATC.h" +#include "WebGLCompressedTexturePVRTC.h" +#include "WebGLCompressedTextureS3TC.h" +#include "WebGLDebugRendererInfo.h" +#include "WebGLDebugShaders.h" +#include "WebGLDepthTexture.h" +#include "WebGLDrawBuffers.h" +#include "WebGLExtension.h" +#include "WebGLFramebuffer.h" +#include "WebGLLoseContext.h" +#include "WebGLProgram.h" +#include "WebGLRenderingContextBase.h" +#include "WebGLVertexArrayObject.h" +#include "WebGLVertexArrayObjectOES.h" +#include <runtime/Error.h> +#include <runtime/JSObjectInlines.h> +#include <runtime/JSTypedArrays.h> +#include <runtime/TypedArrayInlines.h> +#include <runtime/TypedArrays.h> +#include <wtf/FastMalloc.h> + +#if ENABLE(VIDEO) +#include "JSHTMLVideoElement.h" +#endif + +#if ENABLE(WEBGL2) +#include "JSWebGL2RenderingContext.h" +#endif + +using namespace JSC; + +namespace WebCore { + +JSValue toJSNewlyCreated(ExecState*, JSDOMGlobalObject* globalObject, Ref<WebGLRenderingContextBase>&& object) +{ +#if ENABLE(WEBGL2) + if (is<WebGL2RenderingContext>(object)) + return createWrapper<WebGL2RenderingContext>(globalObject, WTFMove(object)); +#endif + return createWrapper<WebGLRenderingContext>(globalObject, WTFMove(object)); +} + +JSValue toJS(ExecState* state, JSDOMGlobalObject* globalObject, WebGLRenderingContextBase& object) +{ + return wrap(state, globalObject, object); +} + +static JSValue toJS(ExecState& state, JSDOMGlobalObject& globalObject, WebGLExtension* extension) +{ + if (!extension) + return jsNull(); + switch (extension->getName()) { + case WebGLExtension::WebGLLoseContextName: + return toJS(&state, &globalObject, static_cast<WebGLLoseContext*>(extension)); + case WebGLExtension::EXTShaderTextureLODName: + return toJS(&state, &globalObject, static_cast<EXTShaderTextureLOD*>(extension)); + case WebGLExtension::EXTTextureFilterAnisotropicName: + return toJS(&state, &globalObject, static_cast<EXTTextureFilterAnisotropic*>(extension)); + case WebGLExtension::EXTsRGBName: + return toJS(&state, &globalObject, static_cast<EXTsRGB*>(extension)); + case WebGLExtension::EXTFragDepthName: + return toJS(&state, &globalObject, static_cast<EXTFragDepth*>(extension)); + case WebGLExtension::EXTBlendMinMaxName: + return toJS(&state, &globalObject, static_cast<EXTBlendMinMax*>(extension)); + case WebGLExtension::OESStandardDerivativesName: + return toJS(&state, &globalObject, static_cast<OESStandardDerivatives*>(extension)); + case WebGLExtension::OESTextureFloatName: + return toJS(&state, &globalObject, static_cast<OESTextureFloat*>(extension)); + case WebGLExtension::OESTextureFloatLinearName: + return toJS(&state, &globalObject, static_cast<OESTextureFloatLinear*>(extension)); + case WebGLExtension::OESTextureHalfFloatName: + return toJS(&state, &globalObject, static_cast<OESTextureHalfFloat*>(extension)); + case WebGLExtension::OESTextureHalfFloatLinearName: + return toJS(&state, &globalObject, static_cast<OESTextureHalfFloatLinear*>(extension)); + case WebGLExtension::OESVertexArrayObjectName: + return toJS(&state, &globalObject, static_cast<OESVertexArrayObject*>(extension)); + case WebGLExtension::OESElementIndexUintName: + return toJS(&state, &globalObject, static_cast<OESElementIndexUint*>(extension)); + case WebGLExtension::WebGLDebugRendererInfoName: + return toJS(&state, &globalObject, static_cast<WebGLDebugRendererInfo*>(extension)); + case WebGLExtension::WebGLDebugShadersName: + return toJS(&state, &globalObject, static_cast<WebGLDebugShaders*>(extension)); + case WebGLExtension::WebGLCompressedTextureATCName: + return toJS(&state, &globalObject, static_cast<WebGLCompressedTextureATC*>(extension)); + case WebGLExtension::WebGLCompressedTexturePVRTCName: + return toJS(&state, &globalObject, static_cast<WebGLCompressedTexturePVRTC*>(extension)); + case WebGLExtension::WebGLCompressedTextureS3TCName: + return toJS(&state, &globalObject, static_cast<WebGLCompressedTextureS3TC*>(extension)); + case WebGLExtension::WebGLDepthTextureName: + return toJS(&state, &globalObject, static_cast<WebGLDepthTexture*>(extension)); + case WebGLExtension::WebGLDrawBuffersName: + return toJS(&state, &globalObject, static_cast<WebGLDrawBuffers*>(extension)); + case WebGLExtension::ANGLEInstancedArraysName: + return toJS(&state, &globalObject, static_cast<ANGLEInstancedArrays*>(extension)); + } + ASSERT_NOT_REACHED(); + return jsNull(); +} + +bool JSWebGLRenderingContextBaseOwner::isReachableFromOpaqueRoots(Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor) +{ + JSWebGLRenderingContextBase* jsWebGLRenderingContext = jsCast<JSWebGLRenderingContextBase*>(handle.slot()->asCell()); + void* root = WebCore::root(jsWebGLRenderingContext->wrapped().canvas()); + return visitor.containsOpaqueRoot(root); +} + +void JSWebGLRenderingContextBase::visitAdditionalChildren(SlotVisitor& visitor) +{ + visitor.addOpaqueRoot(&wrapped()); + visitor.addOpaqueRoot(root(wrapped().canvas())); +} + +JSValue JSWebGLRenderingContextBase::getExtension(ExecState& state) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (state.argumentCount() < 1) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + + auto name = state.uncheckedArgument(0).toWTFString(&state); + RETURN_IF_EXCEPTION(scope, { }); + return toJS(state, *globalObject(), wrapped().getExtension(name)); +} + +} // namespace WebCore + +#endif // ENABLE(WEBGL) diff --git a/Source/WebCore/bindings/js/JSWebGLRenderingContextCustom.cpp b/Source/WebCore/bindings/js/JSWebGLRenderingContextCustom.cpp index 9e390fc23..65abcdd1f 100644 --- a/Source/WebCore/bindings/js/JSWebGLRenderingContextCustom.cpp +++ b/Source/WebCore/bindings/js/JSWebGLRenderingContextCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,727 +26,20 @@ #include "config.h" #if ENABLE(WEBGL) - #include "JSWebGLRenderingContext.h" - -#include "ANGLEInstancedArrays.h" -#include "EXTDrawBuffers.h" -#include "EXTTextureFilterAnisotropic.h" -#include "ExceptionCode.h" -#include "HTMLCanvasElement.h" -#include "HTMLImageElement.h" -#include "JSANGLEInstancedArrays.h" -#include "JSEXTDrawBuffers.h" -#include "JSEXTTextureFilterAnisotropic.h" -#include "JSHTMLCanvasElement.h" -#include "JSHTMLImageElement.h" -#include "JSImageData.h" -#include "JSOESElementIndexUint.h" -#include "JSOESStandardDerivatives.h" -#include "JSOESTextureFloat.h" -#include "JSOESTextureFloatLinear.h" -#include "JSOESTextureHalfFloat.h" -#include "JSOESTextureHalfFloatLinear.h" -#include "JSOESVertexArrayObject.h" -#include "JSWebGLBuffer.h" -#include "JSWebGLCompressedTextureATC.h" -#include "JSWebGLCompressedTexturePVRTC.h" -#include "JSWebGLCompressedTextureS3TC.h" -#include "JSWebGLDebugRendererInfo.h" -#include "JSWebGLDebugShaders.h" -#include "JSWebGLDepthTexture.h" -#include "JSWebGLFramebuffer.h" -#include "JSWebGLLoseContext.h" -#include "JSWebGLProgram.h" -#include "JSWebGLRenderbuffer.h" -#include "JSWebGLShader.h" -#include "JSWebGLTexture.h" -#include "JSWebGLUniformLocation.h" -#include "JSWebGLVertexArrayObjectOES.h" -#include "JSWebKitCSSMatrix.h" -#include "NotImplemented.h" -#include "OESElementIndexUint.h" -#include "OESStandardDerivatives.h" -#include "OESTextureFloat.h" -#include "OESTextureFloatLinear.h" -#include "OESTextureHalfFloat.h" -#include "OESTextureHalfFloatLinear.h" -#include "OESVertexArrayObject.h" -#include "WebGLBuffer.h" -#include "WebGLCompressedTextureATC.h" -#include "WebGLCompressedTexturePVRTC.h" -#include "WebGLCompressedTextureS3TC.h" -#include "WebGLDebugRendererInfo.h" -#include "WebGLDebugShaders.h" -#include "WebGLDepthTexture.h" -#include "WebGLExtension.h" -#include "WebGLFramebuffer.h" -#include "WebGLGetInfo.h" -#include "WebGLLoseContext.h" -#include "WebGLProgram.h" -#include "WebGLRenderingContext.h" -#include "WebGLVertexArrayObjectOES.h" -#include <runtime/Error.h> -#include <runtime/JSTypedArrays.h> -#include <runtime/TypedArrayInlines.h> -#include <runtime/TypedArrays.h> -#include <wtf/FastMalloc.h> - -#if ENABLE(VIDEO) -#include "HTMLVideoElement.h" -#include "JSHTMLVideoElement.h" -#endif +#include "DOMWrapperWorld.h" +#include <JavaScriptCore/JSCellInlines.h> +#include <JavaScriptCore/StructureInlines.h> +#include <heap/HeapInlines.h> +#include <heap/SlotVisitorInlines.h> using namespace JSC; namespace WebCore { -static JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, const WebGLGetInfo& info) -{ - switch (info.getType()) { - case WebGLGetInfo::kTypeBool: - return jsBoolean(info.getBool()); - case WebGLGetInfo::kTypeBoolArray: { - MarkedArgumentBuffer list; - const Vector<bool>& value = info.getBoolArray(); - for (size_t ii = 0; ii < value.size(); ++ii) - list.append(jsBoolean(value[ii])); - return constructArray(exec, 0, globalObject, list); - } - case WebGLGetInfo::kTypeFloat: - return jsNumber(info.getFloat()); - case WebGLGetInfo::kTypeInt: - return jsNumber(info.getInt()); - case WebGLGetInfo::kTypeNull: - return jsNull(); - case WebGLGetInfo::kTypeString: - return jsStringWithCache(exec, info.getString()); - case WebGLGetInfo::kTypeUnsignedInt: - return jsNumber(info.getUnsignedInt()); - case WebGLGetInfo::kTypeWebGLBuffer: - return toJS(exec, globalObject, info.getWebGLBuffer()); - case WebGLGetInfo::kTypeWebGLFloatArray: - return toJS(exec, globalObject, info.getWebGLFloatArray()); - case WebGLGetInfo::kTypeWebGLFramebuffer: - return toJS(exec, globalObject, info.getWebGLFramebuffer()); - case WebGLGetInfo::kTypeWebGLIntArray: - return toJS(exec, globalObject, info.getWebGLIntArray()); - // FIXME: implement WebGLObjectArray - // case WebGLGetInfo::kTypeWebGLObjectArray: - case WebGLGetInfo::kTypeWebGLProgram: - return toJS(exec, globalObject, info.getWebGLProgram()); - case WebGLGetInfo::kTypeWebGLRenderbuffer: - return toJS(exec, globalObject, info.getWebGLRenderbuffer()); - case WebGLGetInfo::kTypeWebGLTexture: - return toJS(exec, globalObject, info.getWebGLTexture()); - case WebGLGetInfo::kTypeWebGLUnsignedByteArray: - return toJS(exec, globalObject, info.getWebGLUnsignedByteArray()); - case WebGLGetInfo::kTypeWebGLUnsignedIntArray: - return toJS(exec, globalObject, info.getWebGLUnsignedIntArray()); - case WebGLGetInfo::kTypeWebGLVertexArrayObjectOES: - return toJS(exec, globalObject, info.getWebGLVertexArrayObjectOES()); - default: - notImplemented(); - return jsUndefined(); - } -} - -enum ObjectType { - kBuffer, kRenderbuffer, kTexture, kVertexAttrib -}; - -static JSValue getObjectParameter(JSWebGLRenderingContext* obj, ExecState* exec, ObjectType objectType) -{ - if (exec->argumentCount() != 2) - return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); - - ExceptionCode ec = 0; - WebGLRenderingContext& context = obj->impl(); - unsigned target = exec->uncheckedArgument(0).toInt32(exec); - if (exec->hadException()) - return jsUndefined(); - unsigned pname = exec->uncheckedArgument(1).toInt32(exec); - if (exec->hadException()) - return jsUndefined(); - WebGLGetInfo info; - switch (objectType) { - case kBuffer: - info = context.getBufferParameter(target, pname, ec); - break; - case kRenderbuffer: - info = context.getRenderbufferParameter(target, pname, ec); - break; - case kTexture: - info = context.getTexParameter(target, pname, ec); - break; - case kVertexAttrib: - // target => index - info = context.getVertexAttrib(target, pname, ec); - break; - default: - notImplemented(); - break; - } - if (ec) { - setDOMException(exec, ec); - return jsUndefined(); - } - return toJS(exec, obj->globalObject(), info); -} - -enum WhichProgramCall { - kProgramParameter, kUniform -}; - -static JSValue toJS(ExecState* exec, JSDOMGlobalObject* globalObject, WebGLExtension* extension) -{ - if (!extension) - return jsNull(); - switch (extension->getName()) { - case WebGLExtension::WebGLLoseContextName: - return toJS(exec, globalObject, static_cast<WebGLLoseContext*>(extension)); - case WebGLExtension::EXTDrawBuffersName: - return toJS(exec, globalObject, static_cast<EXTDrawBuffers*>(extension)); - case WebGLExtension::EXTTextureFilterAnisotropicName: - return toJS(exec, globalObject, static_cast<EXTTextureFilterAnisotropic*>(extension)); - case WebGLExtension::OESStandardDerivativesName: - return toJS(exec, globalObject, static_cast<OESStandardDerivatives*>(extension)); - case WebGLExtension::OESTextureFloatName: - return toJS(exec, globalObject, static_cast<OESTextureFloat*>(extension)); - case WebGLExtension::OESTextureFloatLinearName: - return toJS(exec, globalObject, static_cast<OESTextureFloatLinear*>(extension)); - case WebGLExtension::OESTextureHalfFloatName: - return toJS(exec, globalObject, static_cast<OESTextureHalfFloat*>(extension)); - case WebGLExtension::OESTextureHalfFloatLinearName: - return toJS(exec, globalObject, static_cast<OESTextureHalfFloatLinear*>(extension)); - case WebGLExtension::OESVertexArrayObjectName: - return toJS(exec, globalObject, static_cast<OESVertexArrayObject*>(extension)); - case WebGLExtension::OESElementIndexUintName: - return toJS(exec, globalObject, static_cast<OESElementIndexUint*>(extension)); - case WebGLExtension::WebGLDebugRendererInfoName: - return toJS(exec, globalObject, static_cast<WebGLDebugRendererInfo*>(extension)); - case WebGLExtension::WebGLDebugShadersName: - return toJS(exec, globalObject, static_cast<WebGLDebugShaders*>(extension)); - case WebGLExtension::WebGLCompressedTextureATCName: - return toJS(exec, globalObject, static_cast<WebGLCompressedTextureATC*>(extension)); - case WebGLExtension::WebGLCompressedTexturePVRTCName: - return toJS(exec, globalObject, static_cast<WebGLCompressedTexturePVRTC*>(extension)); - case WebGLExtension::WebGLCompressedTextureS3TCName: - return toJS(exec, globalObject, static_cast<WebGLCompressedTextureS3TC*>(extension)); - case WebGLExtension::WebGLDepthTextureName: - return toJS(exec, globalObject, static_cast<WebGLDepthTexture*>(extension)); - case WebGLExtension::ANGLEInstancedArraysName: - return toJS(exec, globalObject, static_cast<ANGLEInstancedArrays*>(extension)); - } - ASSERT_NOT_REACHED(); - return jsNull(); -} - -void JSWebGLRenderingContext::visitChildren(JSCell* cell, SlotVisitor& visitor) -{ - JSWebGLRenderingContext* thisObject = jsCast<JSWebGLRenderingContext*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(thisObject, visitor); - visitor.addOpaqueRoot(&thisObject->impl()); -} - -JSValue JSWebGLRenderingContext::getAttachedShaders(ExecState* exec) -{ - if (exec->argumentCount() < 1) - return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); - ExceptionCode ec = 0; - WebGLRenderingContext& context = impl(); - WebGLProgram* program = toWebGLProgram(exec->uncheckedArgument(0)); - if (!program && !exec->uncheckedArgument(0).isUndefinedOrNull()) - return throwTypeError(exec); - Vector<RefPtr<WebGLShader>> shaders; - bool succeed = context.getAttachedShaders(program, shaders, ec); - if (ec) { - setDOMException(exec, ec); - return jsNull(); - } - if (!succeed) - return jsNull(); - MarkedArgumentBuffer list; - for (size_t ii = 0; ii < shaders.size(); ++ii) - list.append(toJS(exec, globalObject(), shaders[ii].get())); - return constructArray(exec, 0, globalObject(), list); -} - -JSValue JSWebGLRenderingContext::getExtension(ExecState* exec) -{ - if (exec->argumentCount() < 1) - return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); - - WebGLRenderingContext& context = impl(); - const String name = exec->uncheckedArgument(0).toString(exec)->value(exec); - if (exec->hadException()) - return jsUndefined(); - WebGLExtension* extension = context.getExtension(name); - return toJS(exec, globalObject(), extension); -} - -JSValue JSWebGLRenderingContext::getBufferParameter(ExecState* exec) -{ - return getObjectParameter(this, exec, kBuffer); -} - -JSValue JSWebGLRenderingContext::getFramebufferAttachmentParameter(ExecState* exec) -{ - if (exec->argumentCount() != 3) - return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); - - ExceptionCode ec = 0; - WebGLRenderingContext& context = impl(); - unsigned target = exec->uncheckedArgument(0).toInt32(exec); - if (exec->hadException()) - return jsUndefined(); - unsigned attachment = exec->uncheckedArgument(1).toInt32(exec); - if (exec->hadException()) - return jsUndefined(); - unsigned pname = exec->uncheckedArgument(2).toInt32(exec); - if (exec->hadException()) - return jsUndefined(); - WebGLGetInfo info = context.getFramebufferAttachmentParameter(target, attachment, pname, ec); - if (ec) { - setDOMException(exec, ec); - return jsUndefined(); - } - return toJS(exec, globalObject(), info); -} - -JSValue JSWebGLRenderingContext::getParameter(ExecState* exec) -{ - if (exec->argumentCount() != 1) - return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); - - ExceptionCode ec = 0; - WebGLRenderingContext& context = impl(); - unsigned pname = exec->uncheckedArgument(0).toInt32(exec); - if (exec->hadException()) - return jsUndefined(); - WebGLGetInfo info = context.getParameter(pname, ec); - if (ec) { - setDOMException(exec, ec); - return jsUndefined(); - } - return toJS(exec, globalObject(), info); -} - -JSValue JSWebGLRenderingContext::getProgramParameter(ExecState* exec) -{ - if (exec->argumentCount() != 2) - return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); - - ExceptionCode ec = 0; - WebGLRenderingContext& context = impl(); - WebGLProgram* program = toWebGLProgram(exec->uncheckedArgument(0)); - if (!program && !exec->uncheckedArgument(0).isUndefinedOrNull()) - return throwTypeError(exec); - unsigned pname = exec->uncheckedArgument(1).toInt32(exec); - if (exec->hadException()) - return jsUndefined(); - WebGLGetInfo info = context.getProgramParameter(program, pname, ec); - if (ec) { - setDOMException(exec, ec); - return jsUndefined(); - } - return toJS(exec, globalObject(), info); -} - -JSValue JSWebGLRenderingContext::getRenderbufferParameter(ExecState* exec) -{ - return getObjectParameter(this, exec, kRenderbuffer); -} - -JSValue JSWebGLRenderingContext::getShaderParameter(ExecState* exec) -{ - if (exec->argumentCount() != 2) - return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); - - ExceptionCode ec = 0; - WebGLRenderingContext& context = impl(); - if (!exec->uncheckedArgument(0).isUndefinedOrNull() && !exec->uncheckedArgument(0).inherits(JSWebGLShader::info())) - return throwTypeError(exec); - WebGLShader* shader = toWebGLShader(exec->uncheckedArgument(0)); - unsigned pname = exec->uncheckedArgument(1).toInt32(exec); - if (exec->hadException()) - return jsUndefined(); - WebGLGetInfo info = context.getShaderParameter(shader, pname, ec); - if (ec) { - setDOMException(exec, ec); - return jsUndefined(); - } - return toJS(exec, globalObject(), info); -} - -JSValue JSWebGLRenderingContext::getSupportedExtensions(ExecState* exec) -{ - WebGLRenderingContext& context = impl(); - if (context.isContextLost()) - return jsNull(); - Vector<String> value = context.getSupportedExtensions(); - MarkedArgumentBuffer list; - for (size_t ii = 0; ii < value.size(); ++ii) - list.append(jsStringWithCache(exec, value[ii])); - return constructArray(exec, 0, globalObject(), list); -} - -JSValue JSWebGLRenderingContext::getTexParameter(ExecState* exec) -{ - return getObjectParameter(this, exec, kTexture); -} - -JSValue JSWebGLRenderingContext::getUniform(ExecState* exec) -{ - if (exec->argumentCount() != 2) - return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); - - ExceptionCode ec = 0; - WebGLRenderingContext& context = impl(); - WebGLProgram* program = toWebGLProgram(exec->uncheckedArgument(0)); - if (!program && !exec->uncheckedArgument(0).isUndefinedOrNull()) - return throwTypeError(exec); - WebGLUniformLocation* location = toWebGLUniformLocation(exec->uncheckedArgument(1)); - if (!location && !exec->uncheckedArgument(1).isUndefinedOrNull()) - return throwTypeError(exec); - WebGLGetInfo info = context.getUniform(program, location, ec); - if (ec) { - setDOMException(exec, ec); - return jsUndefined(); - } - return toJS(exec, globalObject(), info); -} - -JSValue JSWebGLRenderingContext::getVertexAttrib(ExecState* exec) -{ - return getObjectParameter(this, exec, kVertexAttrib); -} - -template<typename T, size_t inlineCapacity> -bool toVector(JSC::ExecState* exec, JSC::JSValue value, Vector<T, inlineCapacity>& vector) -{ - if (!value.isObject()) - return false; - - JSC::JSObject* object = asObject(value); - int32_t length = object->get(exec, exec->vm().propertyNames->length).toInt32(exec); - - if (!vector.tryReserveCapacity(length)) - return false; - vector.resize(length); - - for (int32_t i = 0; i < length; ++i) { - JSC::JSValue v = object->get(exec, i); - if (exec->hadException()) - return false; - vector[i] = static_cast<T>(v.toNumber(exec)); - } - - return true; -} - -enum DataFunctionToCall { - f_uniform1v, f_uniform2v, f_uniform3v, f_uniform4v, - f_vertexAttrib1v, f_vertexAttrib2v, f_vertexAttrib3v, f_vertexAttrib4v -}; - -enum DataFunctionMatrixToCall { - f_uniformMatrix2fv, f_uniformMatrix3fv, f_uniformMatrix4fv -}; - -static bool functionForUniform(DataFunctionToCall f) -{ - switch (f) { - case f_uniform1v: - case f_uniform2v: - case f_uniform3v: - case f_uniform4v: - return true; - break; - default: break; - } - return false; -} - -static JSC::JSValue dataFunctionf(DataFunctionToCall f, JSC::ExecState* exec, WebGLRenderingContext& context) -{ - if (exec->argumentCount() != 2) - return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); - - WebGLUniformLocation* location = 0; - long index = -1; - - if (functionForUniform(f)) { - location = toWebGLUniformLocation(exec->uncheckedArgument(0)); - if (!location && !exec->uncheckedArgument(0).isUndefinedOrNull()) - return throwTypeError(exec); - } else - index = exec->uncheckedArgument(0).toInt32(exec); - - if (exec->hadException()) - return jsUndefined(); - - RefPtr<Float32Array> webGLArray = toFloat32Array(exec->uncheckedArgument(1)); - if (exec->hadException()) - return jsUndefined(); - - ExceptionCode ec = 0; - if (webGLArray) { - switch (f) { - case f_uniform1v: - context.uniform1fv(location, webGLArray.get(), ec); - break; - case f_uniform2v: - context.uniform2fv(location, webGLArray.get(), ec); - break; - case f_uniform3v: - context.uniform3fv(location, webGLArray.get(), ec); - break; - case f_uniform4v: - context.uniform4fv(location, webGLArray.get(), ec); - break; - case f_vertexAttrib1v: - context.vertexAttrib1fv(index, webGLArray.get()); - break; - case f_vertexAttrib2v: - context.vertexAttrib2fv(index, webGLArray.get()); - break; - case f_vertexAttrib3v: - context.vertexAttrib3fv(index, webGLArray.get()); - break; - case f_vertexAttrib4v: - context.vertexAttrib4fv(index, webGLArray.get()); - break; - } - - setDOMException(exec, ec); - return jsUndefined(); - } - - Vector<float, 64> array; - if (!toVector(exec, exec->uncheckedArgument(1), array)) - return throwTypeError(exec); - - switch (f) { - case f_uniform1v: - context.uniform1fv(location, array.data(), array.size(), ec); - break; - case f_uniform2v: - context.uniform2fv(location, array.data(), array.size(), ec); - break; - case f_uniform3v: - context.uniform3fv(location, array.data(), array.size(), ec); - break; - case f_uniform4v: - context.uniform4fv(location, array.data(), array.size(), ec); - break; - case f_vertexAttrib1v: - context.vertexAttrib1fv(index, array.data(), array.size()); - break; - case f_vertexAttrib2v: - context.vertexAttrib2fv(index, array.data(), array.size()); - break; - case f_vertexAttrib3v: - context.vertexAttrib3fv(index, array.data(), array.size()); - break; - case f_vertexAttrib4v: - context.vertexAttrib4fv(index, array.data(), array.size()); - break; - } - - setDOMException(exec, ec); - return jsUndefined(); -} - -static JSC::JSValue dataFunctioni(DataFunctionToCall f, JSC::ExecState* exec, WebGLRenderingContext& context) -{ - if (exec->argumentCount() != 2) - return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); - - WebGLUniformLocation* location = toWebGLUniformLocation(exec->uncheckedArgument(0)); - if (!location && !exec->uncheckedArgument(0).isUndefinedOrNull()) - return throwTypeError(exec); - - RefPtr<Int32Array> webGLArray = toInt32Array(exec->uncheckedArgument(1)); - - ExceptionCode ec = 0; - if (webGLArray) { - switch (f) { - case f_uniform1v: - context.uniform1iv(location, webGLArray.get(), ec); - break; - case f_uniform2v: - context.uniform2iv(location, webGLArray.get(), ec); - break; - case f_uniform3v: - context.uniform3iv(location, webGLArray.get(), ec); - break; - case f_uniform4v: - context.uniform4iv(location, webGLArray.get(), ec); - break; - default: - break; - } - - setDOMException(exec, ec); - return jsUndefined(); - } - - - Vector<int, 64> array; - if (!toVector(exec, exec->uncheckedArgument(1), array)) - return throwTypeError(exec); - - switch (f) { - case f_uniform1v: - context.uniform1iv(location, array.data(), array.size(), ec); - break; - case f_uniform2v: - context.uniform2iv(location, array.data(), array.size(), ec); - break; - case f_uniform3v: - context.uniform3iv(location, array.data(), array.size(), ec); - break; - case f_uniform4v: - context.uniform4iv(location, array.data(), array.size(), ec); - break; - default: - break; - } - - setDOMException(exec, ec); - return jsUndefined(); -} - -static JSC::JSValue dataFunctionMatrix(DataFunctionMatrixToCall f, JSC::ExecState* exec, WebGLRenderingContext& context) -{ - if (exec->argumentCount() != 3) - return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); - - WebGLUniformLocation* location = toWebGLUniformLocation(exec->uncheckedArgument(0)); - if (!location && !exec->uncheckedArgument(0).isUndefinedOrNull()) - return throwTypeError(exec); - - bool transpose = exec->uncheckedArgument(1).toBoolean(exec); - if (exec->hadException()) - return jsUndefined(); - - RefPtr<Float32Array> webGLArray = toFloat32Array(exec->uncheckedArgument(2)); - - ExceptionCode ec = 0; - if (webGLArray) { - switch (f) { - case f_uniformMatrix2fv: - context.uniformMatrix2fv(location, transpose, webGLArray.get(), ec); - break; - case f_uniformMatrix3fv: - context.uniformMatrix3fv(location, transpose, webGLArray.get(), ec); - break; - case f_uniformMatrix4fv: - context.uniformMatrix4fv(location, transpose, webGLArray.get(), ec); - break; - } - - setDOMException(exec, ec); - return jsUndefined(); - } - - Vector<float, 64> array; - if (!toVector(exec, exec->uncheckedArgument(2), array)) - return throwTypeError(exec); - - switch (f) { - case f_uniformMatrix2fv: - context.uniformMatrix2fv(location, transpose, array.data(), array.size(), ec); - break; - case f_uniformMatrix3fv: - context.uniformMatrix3fv(location, transpose, array.data(), array.size(), ec); - break; - case f_uniformMatrix4fv: - context.uniformMatrix4fv(location, transpose, array.data(), array.size(), ec); - break; - } - - setDOMException(exec, ec); - return jsUndefined(); -} - -JSC::JSValue JSWebGLRenderingContext::uniform1fv(JSC::ExecState* exec) -{ - return dataFunctionf(f_uniform1v, exec, impl()); -} - -JSC::JSValue JSWebGLRenderingContext::uniform1iv(JSC::ExecState* exec) -{ - return dataFunctioni(f_uniform1v, exec, impl()); -} - -JSC::JSValue JSWebGLRenderingContext::uniform2fv(JSC::ExecState* exec) -{ - return dataFunctionf(f_uniform2v, exec, impl()); -} - -JSC::JSValue JSWebGLRenderingContext::uniform2iv(JSC::ExecState* exec) -{ - return dataFunctioni(f_uniform2v, exec, impl()); -} - -JSC::JSValue JSWebGLRenderingContext::uniform3fv(JSC::ExecState* exec) -{ - return dataFunctionf(f_uniform3v, exec, impl()); -} - -JSC::JSValue JSWebGLRenderingContext::uniform3iv(JSC::ExecState* exec) -{ - return dataFunctioni(f_uniform3v, exec, impl()); -} - -JSC::JSValue JSWebGLRenderingContext::uniform4fv(JSC::ExecState* exec) -{ - return dataFunctionf(f_uniform4v, exec, impl()); -} - -JSC::JSValue JSWebGLRenderingContext::uniform4iv(JSC::ExecState* exec) -{ - return dataFunctioni(f_uniform4v, exec, impl()); -} - -JSC::JSValue JSWebGLRenderingContext::uniformMatrix2fv(JSC::ExecState* exec) -{ - return dataFunctionMatrix(f_uniformMatrix2fv, exec, impl()); -} - -JSC::JSValue JSWebGLRenderingContext::uniformMatrix3fv(JSC::ExecState* exec) -{ - return dataFunctionMatrix(f_uniformMatrix3fv, exec, impl()); -} - -JSC::JSValue JSWebGLRenderingContext::uniformMatrix4fv(JSC::ExecState* exec) -{ - return dataFunctionMatrix(f_uniformMatrix4fv, exec, impl()); -} - -JSC::JSValue JSWebGLRenderingContext::vertexAttrib1fv(JSC::ExecState* exec) -{ - return dataFunctionf(f_vertexAttrib1v, exec, impl()); -} - -JSC::JSValue JSWebGLRenderingContext::vertexAttrib2fv(JSC::ExecState* exec) -{ - return dataFunctionf(f_vertexAttrib2v, exec, impl()); -} - -JSC::JSValue JSWebGLRenderingContext::vertexAttrib3fv(JSC::ExecState* exec) -{ - return dataFunctionf(f_vertexAttrib3v, exec, impl()); -} - -JSC::JSValue JSWebGLRenderingContext::vertexAttrib4fv(JSC::ExecState* exec) +void JSWebGLRenderingContext::visitAdditionalChildren(SlotVisitor& visitor) { - return dataFunctionf(f_vertexAttrib4v, exec, impl()); + visitor.addOpaqueRoot(&wrapped()); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSWebKitPointCustom.cpp b/Source/WebCore/bindings/js/JSWebKitPointCustom.cpp deleted file mode 100644 index 7ef129103..000000000 --- a/Source/WebCore/bindings/js/JSWebKitPointCustom.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2009, 2010 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 COMPUTER, INC. ``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 COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "JSWebKitPoint.h" - -#include "WebKitPoint.h" - -using namespace JSC; - -namespace WebCore { - -EncodedJSValue JSC_HOST_CALL JSWebKitPointConstructor::constructJSWebKitPoint(ExecState* exec) -{ - JSWebKitPointConstructor* jsConstructor = jsCast<JSWebKitPointConstructor*>(exec->callee()); - - float x = 0; - float y = 0; - if (exec->argumentCount() >= 2) { - x = static_cast<float>(exec->argument(0).toNumber(exec)); - y = static_cast<float>(exec->argument(1).toNumber(exec)); - if (std::isnan(x)) - x = 0; - if (std::isnan(y)) - y = 0; - } - return JSValue::encode(asObject(toJS(exec, jsConstructor->globalObject(), WebKitPoint::create(x, y)))); -} - -} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSWebKitSubtleCryptoCustom.cpp b/Source/WebCore/bindings/js/JSWebKitSubtleCryptoCustom.cpp new file mode 100644 index 000000000..638b37e4a --- /dev/null +++ b/Source/WebCore/bindings/js/JSWebKitSubtleCryptoCustom.cpp @@ -0,0 +1,705 @@ +/* + * Copyright (C) 2013, 2016 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 "JSWebKitSubtleCrypto.h" + +#if ENABLE(SUBTLE_CRYPTO) + +#include "CryptoAlgorithm.h" +#include "CryptoAlgorithmParametersDeprecated.h" +#include "CryptoAlgorithmRegistry.h" +#include "CryptoKeyData.h" +#include "CryptoKeySerializationRaw.h" +#include "Document.h" +#include "ExceptionCode.h" +#include "JSCryptoAlgorithmDictionary.h" +#include "JSCryptoKey.h" +#include "JSCryptoKeyPair.h" +#include "JSCryptoKeySerializationJWK.h" +#include "JSCryptoOperationData.h" +#include "JSDOMPromise.h" +#include "ScriptState.h" +#include <runtime/Error.h> + +using namespace JSC; + +namespace WebCore { + +enum class CryptoKeyFormat { + // An unformatted sequence of bytes. Intended for secret keys. + Raw, + + // The DER encoding of the PrivateKeyInfo structure from RFC 5208. + PKCS8, + + // The DER encoding of the SubjectPublicKeyInfo structure from RFC 5280. + SPKI, + + // The key is represented as JSON according to the JSON Web Key format. + JWK +}; + +static RefPtr<CryptoAlgorithm> createAlgorithmFromJSValue(ExecState& state, ThrowScope& scope, JSValue value) +{ + auto algorithmIdentifier = JSCryptoAlgorithmDictionary::parseAlgorithmIdentifier(state, scope, value); + RETURN_IF_EXCEPTION(scope, { }); + + auto result = CryptoAlgorithmRegistry::singleton().create(algorithmIdentifier); + if (!result) + throwNotSupportedError(state, scope); + + return result; +} + +static CryptoKeyFormat cryptoKeyFormatFromJSValue(ExecState& state, ThrowScope& scope, JSValue value) +{ + auto keyFormatString = value.toWTFString(&state); + RETURN_IF_EXCEPTION(scope, { }); + + if (keyFormatString == "raw") + return CryptoKeyFormat::Raw; + if (keyFormatString == "pkcs8") + return CryptoKeyFormat::PKCS8; + if (keyFormatString == "spki") + return CryptoKeyFormat::SPKI; + if (keyFormatString == "jwk") + return CryptoKeyFormat::JWK; + + throwTypeError(&state, scope, ASCIILiteral("Unknown key format")); + return { }; +} + +static CryptoKeyUsageBitmap cryptoKeyUsagesFromJSValue(ExecState& state, ThrowScope& scope, JSValue value) +{ + if (!isJSArray(value)) { + throwTypeError(&state, scope); + return { }; + } + + CryptoKeyUsageBitmap result = 0; + JSArray* array = asArray(value); + for (unsigned i = 0; i < array->length(); ++i) { + auto usageString = array->getIndex(&state, i).toWTFString(&state); + RETURN_IF_EXCEPTION(scope, { }); + if (usageString == "encrypt") + result |= CryptoKeyUsageEncrypt; + else if (usageString == "decrypt") + result |= CryptoKeyUsageDecrypt; + else if (usageString == "sign") + result |= CryptoKeyUsageSign; + else if (usageString == "verify") + result |= CryptoKeyUsageVerify; + else if (usageString == "deriveKey") + result |= CryptoKeyUsageDeriveKey; + else if (usageString == "deriveBits") + result |= CryptoKeyUsageDeriveBits; + else if (usageString == "wrapKey") + result |= CryptoKeyUsageWrapKey; + else if (usageString == "unwrapKey") + result |= CryptoKeyUsageUnwrapKey; + } + return result; +} + +JSValue JSWebKitSubtleCrypto::encrypt(ExecState& state) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (state.argumentCount() < 3) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + + auto algorithm = createAlgorithmFromJSValue(state, scope, state.uncheckedArgument(0)); + RETURN_IF_EXCEPTION(scope, { }); + + auto parameters = JSCryptoAlgorithmDictionary::createParametersForEncrypt(state, scope, algorithm->identifier(), state.uncheckedArgument(0)); + RETURN_IF_EXCEPTION(scope, { }); + + RefPtr<CryptoKey> key = JSCryptoKey::toWrapped(vm, state.uncheckedArgument(1)); + if (!key) + return throwTypeError(&state, scope); + + if (!key->allows(CryptoKeyUsageEncrypt)) { + wrapped().document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'encrypt'")); + throwNotSupportedError(state, scope); + return jsUndefined(); + } + + auto data = cryptoOperationDataFromJSValue(state, scope, state.uncheckedArgument(2)); + RETURN_IF_EXCEPTION(scope, { }); + + RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow()); + auto promise = wrapper->promise(); + auto successCallback = [wrapper](const Vector<uint8_t>& result) mutable { + fulfillPromiseWithArrayBuffer(wrapper.releaseNonNull(), result.data(), result.size()); + }; + auto failureCallback = [wrapper]() mutable { + wrapper->reject(); // FIXME: This should reject with an Exception. + }; + + auto result = algorithm->encrypt(*parameters, *key, data, WTFMove(successCallback), WTFMove(failureCallback)); + if (result.hasException()) { + propagateException(state, scope, result.releaseException()); + return { }; + } + + return promise; +} + +JSValue JSWebKitSubtleCrypto::decrypt(ExecState& state) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (state.argumentCount() < 3) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + + auto algorithm = createAlgorithmFromJSValue(state, scope, state.uncheckedArgument(0)); + RETURN_IF_EXCEPTION(scope, { }); + + auto parameters = JSCryptoAlgorithmDictionary::createParametersForDecrypt(state, scope, algorithm->identifier(), state.uncheckedArgument(0)); + RETURN_IF_EXCEPTION(scope, { }); + + RefPtr<CryptoKey> key = JSCryptoKey::toWrapped(vm, state.uncheckedArgument(1)); + if (!key) + return throwTypeError(&state, scope); + + if (!key->allows(CryptoKeyUsageDecrypt)) { + wrapped().document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'decrypt'")); + throwNotSupportedError(state, scope); + return jsUndefined(); + } + + auto data = cryptoOperationDataFromJSValue(state, scope, state.uncheckedArgument(2)); + RETURN_IF_EXCEPTION(scope, { }); + + RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow()); + auto promise = wrapper->promise(); + auto successCallback = [wrapper](const Vector<uint8_t>& result) mutable { + fulfillPromiseWithArrayBuffer(wrapper.releaseNonNull(), result.data(), result.size()); + }; + auto failureCallback = [wrapper]() mutable { + wrapper->reject(); // FIXME: This should reject with an Exception. + }; + + auto result = algorithm->decrypt(*parameters, *key, data, WTFMove(successCallback), WTFMove(failureCallback)); + if (result.hasException()) { + propagateException(state, scope, result.releaseException()); + return { }; + } + + return promise; +} + +JSValue JSWebKitSubtleCrypto::sign(ExecState& state) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (state.argumentCount() < 3) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + + auto algorithm = createAlgorithmFromJSValue(state, scope, state.uncheckedArgument(0)); + RETURN_IF_EXCEPTION(scope, { }); + + auto parameters = JSCryptoAlgorithmDictionary::createParametersForSign(state, scope, algorithm->identifier(), state.uncheckedArgument(0)); + RETURN_IF_EXCEPTION(scope, { }); + + RefPtr<CryptoKey> key = JSCryptoKey::toWrapped(vm, state.uncheckedArgument(1)); + if (!key) + return throwTypeError(&state, scope); + + if (!key->allows(CryptoKeyUsageSign)) { + wrapped().document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'sign'")); + throwNotSupportedError(state, scope); + return jsUndefined(); + } + + auto data = cryptoOperationDataFromJSValue(state, scope, state.uncheckedArgument(2)); + RETURN_IF_EXCEPTION(scope, { }); + + RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow()); + auto promise = wrapper->promise(); + auto successCallback = [wrapper](const Vector<uint8_t>& result) mutable { + fulfillPromiseWithArrayBuffer(wrapper.releaseNonNull(), result.data(), result.size()); + }; + auto failureCallback = [wrapper]() mutable { + wrapper->reject(); // FIXME: This should reject with an Exception. + }; + + auto result = algorithm->sign(*parameters, *key, data, WTFMove(successCallback), WTFMove(failureCallback)); + if (result.hasException()) { + propagateException(state, scope, result.releaseException()); + return { }; + } + + return promise; +} + +JSValue JSWebKitSubtleCrypto::verify(ExecState& state) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (state.argumentCount() < 4) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + + auto algorithm = createAlgorithmFromJSValue(state, scope, state.uncheckedArgument(0)); + RETURN_IF_EXCEPTION(scope, { }); + + auto parameters = JSCryptoAlgorithmDictionary::createParametersForVerify(state, scope, algorithm->identifier(), state.uncheckedArgument(0)); + RETURN_IF_EXCEPTION(scope, { }); + + RefPtr<CryptoKey> key = JSCryptoKey::toWrapped(vm, state.uncheckedArgument(1)); + if (!key) + return throwTypeError(&state, scope); + + if (!key->allows(CryptoKeyUsageVerify)) { + wrapped().document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'verify'")); + throwNotSupportedError(state, scope); + return jsUndefined(); + } + + auto signature = cryptoOperationDataFromJSValue(state, scope, state.uncheckedArgument(2)); + RETURN_IF_EXCEPTION(scope, { }); + + auto data = cryptoOperationDataFromJSValue(state, scope, state.uncheckedArgument(3)); + RETURN_IF_EXCEPTION(scope, { }); + + RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow()); + auto promise = wrapper->promise(); + auto successCallback = [wrapper](bool result) mutable { + wrapper->resolve<IDLBoolean>(result); + }; + auto failureCallback = [wrapper]() mutable { + wrapper->reject(); // FIXME: This should reject with an Exception. + }; + + auto result = algorithm->verify(*parameters, *key, signature, data, WTFMove(successCallback), WTFMove(failureCallback)); + if (result.hasException()) { + propagateException(state, scope, result.releaseException()); + return { }; + } + + return promise; +} + +JSValue JSWebKitSubtleCrypto::digest(ExecState& state) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (state.argumentCount() < 2) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + + auto algorithm = createAlgorithmFromJSValue(state, scope, state.uncheckedArgument(0)); + RETURN_IF_EXCEPTION(scope, { }); + + auto parameters = JSCryptoAlgorithmDictionary::createParametersForDigest(state, scope, algorithm->identifier(), state.uncheckedArgument(0)); + RETURN_IF_EXCEPTION(scope, { }); + + auto data = cryptoOperationDataFromJSValue(state, scope, state.uncheckedArgument(1)); + RETURN_IF_EXCEPTION(scope, { }); + + RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow()); + auto promise = wrapper->promise(); + auto successCallback = [wrapper](const Vector<uint8_t>& result) mutable { + fulfillPromiseWithArrayBuffer(wrapper.releaseNonNull(), result.data(), result.size()); + }; + auto failureCallback = [wrapper]() mutable { + wrapper->reject(); // FIXME: This should reject with an Exception. + }; + + auto result = algorithm->digest(*parameters, data, WTFMove(successCallback), WTFMove(failureCallback)); + if (result.hasException()) { + propagateException(state, scope, result.releaseException()); + return { }; + } + + return promise; +} + +JSValue JSWebKitSubtleCrypto::generateKey(ExecState& state) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (state.argumentCount() < 1) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + + auto algorithm = createAlgorithmFromJSValue(state, scope, state.uncheckedArgument(0)); + RETURN_IF_EXCEPTION(scope, { }); + + auto parameters = JSCryptoAlgorithmDictionary::createParametersForGenerateKey(state, scope, algorithm->identifier(), state.uncheckedArgument(0)); + RETURN_IF_EXCEPTION(scope, { }); + + bool extractable = state.argument(1).toBoolean(&state); + RETURN_IF_EXCEPTION(scope, { }); + + CryptoKeyUsageBitmap keyUsages = 0; + if (state.argumentCount() >= 3) { + keyUsages = cryptoKeyUsagesFromJSValue(state, scope, state.uncheckedArgument(2)); + RETURN_IF_EXCEPTION(scope, { }); + } + + RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow()); + auto promise = wrapper->promise(); + auto successCallback = [wrapper](KeyOrKeyPair&& keyOrKeyPair) mutable { + WTF::switchOn(keyOrKeyPair, + [&wrapper] (RefPtr<CryptoKey>& key) { + wrapper->resolve<IDLInterface<CryptoKey>>(*key); + }, + [&wrapper] (CryptoKeyPair& keyPair) { + wrapper->resolve<IDLDictionary<CryptoKeyPair>>(keyPair); + } + ); + }; + auto failureCallback = [wrapper]() mutable { + wrapper->reject(); // FIXME: This should reject with an Exception. + }; + + auto result = algorithm->generateKey(*parameters, extractable, keyUsages, WTFMove(successCallback), WTFMove(failureCallback), *scriptExecutionContextFromExecState(&state)); + if (result.hasException()) { + propagateException(state, scope, result.releaseException()); + return { }; + } + + return promise; +} + +static void importKey(ExecState& state, CryptoKeyFormat keyFormat, CryptoOperationData data, RefPtr<CryptoAlgorithm> algorithm, RefPtr<CryptoAlgorithmParametersDeprecated> parameters, bool extractable, CryptoKeyUsageBitmap keyUsages, CryptoAlgorithm::KeyCallback callback, CryptoAlgorithm::VoidCallback failureCallback) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + std::unique_ptr<CryptoKeySerialization> keySerialization; + switch (keyFormat) { + case CryptoKeyFormat::Raw: + keySerialization = CryptoKeySerializationRaw::create(data); + break; + case CryptoKeyFormat::JWK: { + String jwkString = String::fromUTF8(data.first, data.second); + if (jwkString.isNull()) { + throwTypeError(&state, scope, ASCIILiteral("JWK JSON serialization is not valid UTF-8")); + return; + } + keySerialization = std::make_unique<JSCryptoKeySerializationJWK>(&state, jwkString); + RETURN_IF_EXCEPTION(scope, void()); + break; + } + default: + throwTypeError(&state, scope, ASCIILiteral("Unsupported key format for import")); + return; + } + + ASSERT(keySerialization); + + std::optional<CryptoAlgorithmPair> reconciledResult = keySerialization->reconcileAlgorithm(algorithm.get(), parameters.get()); + if (!reconciledResult) { + if (!scope.exception()) + throwTypeError(&state, scope, ASCIILiteral("Algorithm specified in key is not compatible with one passed to importKey as argument")); + return; + } + RETURN_IF_EXCEPTION(scope, void()); + + algorithm = reconciledResult->algorithm; + parameters = reconciledResult->parameters; + if (!algorithm) { + throwTypeError(&state, scope, ASCIILiteral("Neither key nor function argument has crypto algorithm specified")); + return; + } + ASSERT(parameters); + + keySerialization->reconcileExtractable(extractable); + RETURN_IF_EXCEPTION(scope, void()); + + keySerialization->reconcileUsages(keyUsages); + RETURN_IF_EXCEPTION(scope, void()); + + auto keyData = keySerialization->keyData(); + RETURN_IF_EXCEPTION(scope, void()); + + propagateException(state, scope, algorithm->importKey(*parameters, *keyData, extractable, keyUsages, WTFMove(callback), WTFMove(failureCallback))); +} + +JSValue JSWebKitSubtleCrypto::importKey(ExecState& state) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (state.argumentCount() < 3) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + + auto keyFormat = cryptoKeyFormatFromJSValue(state, scope, state.uncheckedArgument(0)); + RETURN_IF_EXCEPTION(scope, { }); + + auto data = cryptoOperationDataFromJSValue(state, scope, state.uncheckedArgument(1)); + RETURN_IF_EXCEPTION(scope, { }); + + RefPtr<CryptoAlgorithm> algorithm; + RefPtr<CryptoAlgorithmParametersDeprecated> parameters; + if (!state.uncheckedArgument(2).isNull()) { + algorithm = createAlgorithmFromJSValue(state, scope, state.uncheckedArgument(2)); + RETURN_IF_EXCEPTION(scope, { }); + + parameters = JSCryptoAlgorithmDictionary::createParametersForImportKey(state, scope, algorithm->identifier(), state.uncheckedArgument(2)); + RETURN_IF_EXCEPTION(scope, { }); + } + + bool extractable = state.argument(3).toBoolean(&state); + RETURN_IF_EXCEPTION(scope, JSValue()); + + CryptoKeyUsageBitmap keyUsages = 0; + if (state.argumentCount() >= 5) { + keyUsages = cryptoKeyUsagesFromJSValue(state, scope, state.uncheckedArgument(4)); + RETURN_IF_EXCEPTION(scope, { }); + } + + RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow()); + auto promise = wrapper->promise(); + auto successCallback = [wrapper](CryptoKey& result) mutable { + wrapper->resolve<IDLInterface<CryptoKey>>(result); + }; + auto failureCallback = [wrapper]() mutable { + wrapper->reject(); // FIXME: This should reject with an Exception. + }; + + WebCore::importKey(state, keyFormat, data, WTFMove(algorithm), WTFMove(parameters), extractable, keyUsages, WTFMove(successCallback), WTFMove(failureCallback)); + RETURN_IF_EXCEPTION(scope, JSValue()); + + return promise; +} + +static void exportKey(ExecState& state, CryptoKeyFormat keyFormat, const CryptoKey& key, CryptoAlgorithm::VectorCallback callback, CryptoAlgorithm::VoidCallback failureCallback) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (!key.extractable()) { + throwTypeError(&state, scope, ASCIILiteral("Key is not extractable")); + return; + } + + switch (keyFormat) { + case CryptoKeyFormat::Raw: { + Vector<uint8_t> result; + if (CryptoKeySerializationRaw::serialize(key, result)) + callback(result); + else + failureCallback(); + break; + } + case CryptoKeyFormat::JWK: { + String result = JSCryptoKeySerializationJWK::serialize(&state, key); + RETURN_IF_EXCEPTION(scope, void()); + CString utf8String = result.utf8(StrictConversion); + Vector<uint8_t> resultBuffer; + resultBuffer.append(utf8String.data(), utf8String.length()); + callback(resultBuffer); + break; + } + default: + throwTypeError(&state, scope, ASCIILiteral("Unsupported key format for export")); + break; + } +} + +JSValue JSWebKitSubtleCrypto::exportKey(ExecState& state) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (state.argumentCount() < 2) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + + auto keyFormat = cryptoKeyFormatFromJSValue(state, scope, state.uncheckedArgument(0)); + RETURN_IF_EXCEPTION(scope, { }); + + RefPtr<CryptoKey> key = JSCryptoKey::toWrapped(vm, state.uncheckedArgument(1)); + if (!key) + return throwTypeError(&state, scope); + + RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow()); + auto promise = wrapper->promise(); + auto successCallback = [wrapper](const Vector<uint8_t>& result) mutable { + fulfillPromiseWithArrayBuffer(wrapper.releaseNonNull(), result.data(), result.size()); + }; + auto failureCallback = [wrapper]() mutable { + wrapper->reject(); // FIXME: This should reject with an Exception. + }; + + WebCore::exportKey(state, keyFormat, *key, WTFMove(successCallback), WTFMove(failureCallback)); + RETURN_IF_EXCEPTION(scope, JSValue()); + + return promise; +} + +JSValue JSWebKitSubtleCrypto::wrapKey(ExecState& state) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (state.argumentCount() < 4) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + + auto keyFormat = cryptoKeyFormatFromJSValue(state, scope, state.uncheckedArgument(0)); + RETURN_IF_EXCEPTION(scope, { }); + + RefPtr<CryptoKey> key = JSCryptoKey::toWrapped(vm, state.uncheckedArgument(1)); + if (!key) + return throwTypeError(&state, scope); + + RefPtr<CryptoKey> wrappingKey = JSCryptoKey::toWrapped(vm, state.uncheckedArgument(2)); + if (!key) + return throwTypeError(&state, scope); + + if (!wrappingKey->allows(CryptoKeyUsageWrapKey)) { + wrapped().document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'wrapKey'")); + throwNotSupportedError(state, scope); + return jsUndefined(); + } + + auto algorithm = createAlgorithmFromJSValue(state, scope, state.uncheckedArgument(3)); + RETURN_IF_EXCEPTION(scope, { }); + + auto parameters = JSCryptoAlgorithmDictionary::createParametersForEncrypt(state, scope, algorithm->identifier(), state.uncheckedArgument(3)); + RETURN_IF_EXCEPTION(scope, { }); + + RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow()); + auto promise = wrapper->promise(); + + auto exportSuccessCallback = [keyFormat, algorithm, parameters, wrappingKey, wrapper](const Vector<uint8_t>& exportedKeyData) mutable { + auto encryptSuccessCallback = [wrapper](const Vector<uint8_t>& encryptedData) mutable { + fulfillPromiseWithArrayBuffer(wrapper.releaseNonNull(), encryptedData.data(), encryptedData.size()); + }; + auto encryptFailureCallback = [wrapper]() mutable { + wrapper->reject(); // FIXME: This should reject with an Exception. + }; + auto result = algorithm->encryptForWrapKey(*parameters, *wrappingKey, std::make_pair(exportedKeyData.data(), exportedKeyData.size()), WTFMove(encryptSuccessCallback), WTFMove(encryptFailureCallback)); + if (result.hasException()) { + // FIXME: Report failure details to console, and possibly to calling script once there is a standardized way to pass errors to WebCrypto promise reject functions. + wrapper->reject(); // FIXME: This should reject with an Exception. + } + }; + + auto exportFailureCallback = [wrapper]() mutable { + wrapper->reject(); // FIXME: This should reject with an Exception. + }; + + WebCore::exportKey(state, keyFormat, *key, WTFMove(exportSuccessCallback), WTFMove(exportFailureCallback)); + + return promise; +} + +JSValue JSWebKitSubtleCrypto::unwrapKey(ExecState& state) +{ + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (state.argumentCount() < 5) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + + auto keyFormat = cryptoKeyFormatFromJSValue(state, scope, state.uncheckedArgument(0)); + RETURN_IF_EXCEPTION(scope, { }); + + auto wrappedKeyData = cryptoOperationDataFromJSValue(state, scope, state.uncheckedArgument(1)); + RETURN_IF_EXCEPTION(scope, { }); + + RefPtr<CryptoKey> unwrappingKey = JSCryptoKey::toWrapped(vm, state.uncheckedArgument(2)); + if (!unwrappingKey) + return throwTypeError(&state, scope); + + if (!unwrappingKey->allows(CryptoKeyUsageUnwrapKey)) { + wrapped().document()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, ASCIILiteral("Key usages do not include 'unwrapKey'")); + throwNotSupportedError(state, scope); + return jsUndefined(); + } + + auto unwrapAlgorithm = createAlgorithmFromJSValue(state, scope, state.uncheckedArgument(3)); + RETURN_IF_EXCEPTION(scope, { }); + + auto unwrapAlgorithmParameters = JSCryptoAlgorithmDictionary::createParametersForDecrypt(state, scope, unwrapAlgorithm->identifier(), state.uncheckedArgument(3)); + RETURN_IF_EXCEPTION(scope, { }); + + RefPtr<CryptoAlgorithm> unwrappedKeyAlgorithm; + RefPtr<CryptoAlgorithmParametersDeprecated> unwrappedKeyAlgorithmParameters; + if (!state.uncheckedArgument(4).isNull()) { + unwrappedKeyAlgorithm = createAlgorithmFromJSValue(state, scope, state.uncheckedArgument(4)); + RETURN_IF_EXCEPTION(scope, { }); + + unwrappedKeyAlgorithmParameters = JSCryptoAlgorithmDictionary::createParametersForImportKey(state, scope, unwrappedKeyAlgorithm->identifier(), state.uncheckedArgument(4)); + RETURN_IF_EXCEPTION(scope, { }); + } + + bool extractable = state.argument(5).toBoolean(&state); + RETURN_IF_EXCEPTION(scope, { }); + + CryptoKeyUsageBitmap keyUsages = 0; + if (state.argumentCount() >= 7) { + keyUsages = cryptoKeyUsagesFromJSValue(state, scope, state.uncheckedArgument(6)); + RETURN_IF_EXCEPTION(scope, { }); + } + + RefPtr<DeferredPromise> wrapper = createDeferredPromise(state, domWindow()); + auto promise = wrapper->promise(); + Strong<JSDOMGlobalObject> domGlobalObject(state.vm(), globalObject()); + + auto decryptSuccessCallback = [domGlobalObject, keyFormat, unwrappedKeyAlgorithm, unwrappedKeyAlgorithmParameters, extractable, keyUsages, wrapper](const Vector<uint8_t>& result) mutable { + auto importSuccessCallback = [wrapper](CryptoKey& key) mutable { + wrapper->resolve<IDLInterface<CryptoKey>>(key); + }; + auto importFailureCallback = [wrapper]() mutable { + wrapper->reject(); // FIXME: This should reject with an Exception. + }; + + VM& vm = domGlobalObject->vm(); + auto scope = DECLARE_CATCH_SCOPE(vm); + + ExecState& state = *domGlobalObject->globalExec(); + WebCore::importKey(state, keyFormat, std::make_pair(result.data(), result.size()), unwrappedKeyAlgorithm, unwrappedKeyAlgorithmParameters, extractable, keyUsages, WTFMove(importSuccessCallback), WTFMove(importFailureCallback)); + if (UNLIKELY(scope.exception())) { + // FIXME: Report exception details to console, and possibly to calling script once there is a standardized way to pass errors to WebCrypto promise reject functions. + scope.clearException(); + wrapper->reject(); // FIXME: This should reject with an Exception. + } + }; + + auto decryptFailureCallback = [wrapper]() mutable { + wrapper->reject(); // FIXME: This should reject with an Exception. + }; + + auto result = unwrapAlgorithm->decryptForUnwrapKey(*unwrapAlgorithmParameters, *unwrappingKey, wrappedKeyData, WTFMove(decryptSuccessCallback), WTFMove(decryptFailureCallback)); + if (result.hasException()) { + propagateException(state, scope, result.releaseException()); + return { }; + } + + return promise; +} + +} // namespace WebCore + +#endif diff --git a/Source/WebCore/bindings/js/JSWorkerCustom.cpp b/Source/WebCore/bindings/js/JSWorkerCustom.cpp index caa5318f1..84e07fe05 100644 --- a/Source/WebCore/bindings/js/JSWorkerCustom.cpp +++ b/Source/WebCore/bindings/js/JSWorkerCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved. + * Copyright (C) 2008-2009, 2016 Apple Inc. All Rights Reserved. * Copyright (C) 2011 Google Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,48 +25,41 @@ */ #include "config.h" - #include "JSWorker.h" #include "Document.h" +#include "JSDOMConstructorBase.h" +#include "JSDOMConvertStrings.h" +#include "JSDOMExceptionHandling.h" #include "JSDOMGlobalObject.h" -#include "JSMessagePortCustom.h" -#include "Worker.h" #include "JSDOMWindowCustom.h" +#include "Worker.h" #include <runtime/Error.h> using namespace JSC; namespace WebCore { -JSC::JSValue JSWorker::postMessage(JSC::ExecState* exec) +EncodedJSValue JSC_HOST_CALL constructJSWorker(ExecState& state) { - return handlePostMessage(exec, &impl()); -} + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); -EncodedJSValue JSC_HOST_CALL JSWorkerConstructor::constructJSWorker(ExecState* exec) -{ - JSWorkerConstructor* jsConstructor = jsCast<JSWorkerConstructor*>(exec->callee()); + ASSERT(jsCast<JSDOMConstructorBase*>(state.jsCallee())); + ASSERT(jsCast<JSDOMConstructorBase*>(state.jsCallee())->globalObject()); + auto& globalObject = *jsCast<JSDOMConstructorBase*>(state.jsCallee())->globalObject(); - if (!exec->argumentCount()) - return throwVMError(exec, createNotEnoughArgumentsError(exec)); + if (!state.argumentCount()) + return throwVMError(&state, scope, createNotEnoughArgumentsError(&state)); - String scriptURL = exec->argument(0).toString(exec)->value(exec); - if (exec->hadException()) - return JSValue::encode(JSValue()); + auto scriptURL = convert<IDLDOMString>(state, state.uncheckedArgument(0)); + RETURN_IF_EXCEPTION(scope, encodedJSValue()); - // See section 4.8.2 step 14 of WebWorkers for why this is the lexicalGlobalObject. - DOMWindow& window = asJSDOMWindow(exec->lexicalGlobalObject())->impl(); + // See section 4.8.2 step 14 of WebWorkers for why this is the lexicalGlobalObject. + auto& window = asJSDOMWindow(state.lexicalGlobalObject())->wrapped(); - ExceptionCode ec = 0; ASSERT(window.document()); - RefPtr<Worker> worker = Worker::create(*window.document(), scriptURL, ec); - if (ec) { - setDOMException(exec, ec); - return JSValue::encode(JSValue()); - } - - return JSValue::encode(asObject(toJS(exec, jsConstructor->globalObject(), worker.release()))); + return JSValue::encode(toJSNewlyCreated<IDLInterface<Worker>>(state, globalObject, scope, Worker::create(*window.document(), scriptURL, globalObject.runtimeFlags()))); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.cpp b/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.cpp index bc42aba4c..f1e6d8ed4 100644 --- a/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.cpp +++ b/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009, 2016 Apple Inc. All rights reserved. * Copyright (C) 2009 Google Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without @@ -11,10 +11,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,58 +26,70 @@ */ #include "config.h" - #include "JSWorkerGlobalScopeBase.h" #include "DOMWrapperWorld.h" #include "JSDOMGlobalObjectTask.h" #include "JSDedicatedWorkerGlobalScope.h" +#include "JSDynamicDowncast.h" #include "JSWorkerGlobalScope.h" +#include "Language.h" #include "WorkerGlobalScope.h" +#include "WorkerThread.h" +#include <runtime/JSCInlines.h> +#include <runtime/JSCJSValueInlines.h> #include <runtime/Microtask.h> -#if ENABLE(SHARED_WORKERS) -#include "JSSharedWorkerGlobalScope.h" -#endif - using namespace JSC; namespace WebCore { -const ClassInfo JSWorkerGlobalScopeBase::s_info = { "WorkerGlobalScope", &JSDOMGlobalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSWorkerGlobalScopeBase) }; +const ClassInfo JSWorkerGlobalScopeBase::s_info = { "WorkerGlobalScope", &JSDOMGlobalObject::s_info, 0, CREATE_METHOD_TABLE(JSWorkerGlobalScopeBase) }; -const GlobalObjectMethodTable JSWorkerGlobalScopeBase::s_globalObjectMethodTable = { &allowsAccessFrom, &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript, &javaScriptExperimentsEnabled, &queueTaskToEventLoop, &shouldInterruptScriptBeforeTimeout }; +const GlobalObjectMethodTable JSWorkerGlobalScopeBase::s_globalObjectMethodTable = { + &supportsRichSourceInfo, + &shouldInterruptScript, + &javaScriptRuntimeFlags, + &queueTaskToEventLoop, + &shouldInterruptScriptBeforeTimeout, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + &defaultLanguage +}; -JSWorkerGlobalScopeBase::JSWorkerGlobalScopeBase(JSC::VM& vm, JSC::Structure* structure, PassRefPtr<WorkerGlobalScope> impl) - : JSDOMGlobalObject(vm, structure, &normalWorld(vm), &s_globalObjectMethodTable) - , m_impl(impl) +JSWorkerGlobalScopeBase::JSWorkerGlobalScopeBase(JSC::VM& vm, JSC::Structure* structure, RefPtr<WorkerGlobalScope>&& impl) + : JSDOMGlobalObject(vm, structure, normalWorld(vm), &s_globalObjectMethodTable) + , m_wrapped(WTFMove(impl)) { } -void JSWorkerGlobalScopeBase::finishCreation(VM& vm) +void JSWorkerGlobalScopeBase::finishCreation(VM& vm, JSProxy* proxy) { - Base::finishCreation(vm); - ASSERT(inherits(info())); -} + m_proxy.set(vm, this, proxy); -void JSWorkerGlobalScopeBase::destroy(JSCell* cell) -{ - static_cast<JSWorkerGlobalScopeBase*>(cell)->JSWorkerGlobalScopeBase::~JSWorkerGlobalScopeBase(); + Base::finishCreation(vm, m_proxy.get()); + ASSERT(inherits(vm, info())); } -ScriptExecutionContext* JSWorkerGlobalScopeBase::scriptExecutionContext() const +void JSWorkerGlobalScopeBase::visitChildren(JSCell* cell, SlotVisitor& visitor) { - return m_impl.get(); + JSWorkerGlobalScopeBase* thisObject = jsCast<JSWorkerGlobalScopeBase*>(cell); + ASSERT_GC_OBJECT_INHERITS(thisObject, info()); + Base::visitChildren(thisObject, visitor); + visitor.append(thisObject->m_proxy); } -bool JSWorkerGlobalScopeBase::allowsAccessFrom(const JSGlobalObject* object, ExecState* exec) +void JSWorkerGlobalScopeBase::destroy(JSCell* cell) { - return JSGlobalObject::allowsAccessFrom(object, exec); + static_cast<JSWorkerGlobalScopeBase*>(cell)->JSWorkerGlobalScopeBase::~JSWorkerGlobalScopeBase(); } -bool JSWorkerGlobalScopeBase::supportsProfiling(const JSGlobalObject* object) +ScriptExecutionContext* JSWorkerGlobalScopeBase::scriptExecutionContext() const { - return JSGlobalObject::supportsProfiling(object); + return m_wrapped.get(); } bool JSWorkerGlobalScopeBase::supportsRichSourceInfo(const JSGlobalObject* object) @@ -95,64 +107,49 @@ bool JSWorkerGlobalScopeBase::shouldInterruptScriptBeforeTimeout(const JSGlobalO return JSGlobalObject::shouldInterruptScriptBeforeTimeout(object); } -bool JSWorkerGlobalScopeBase::javaScriptExperimentsEnabled(const JSGlobalObject* object) +RuntimeFlags JSWorkerGlobalScopeBase::javaScriptRuntimeFlags(const JSGlobalObject* object) { - return JSGlobalObject::javaScriptExperimentsEnabled(object); + const JSWorkerGlobalScopeBase *thisObject = jsCast<const JSWorkerGlobalScopeBase*>(object); + return thisObject->m_wrapped->thread().runtimeFlags(); } -void JSWorkerGlobalScopeBase::queueTaskToEventLoop(const JSGlobalObject* object, PassRefPtr<Microtask> task) +void JSWorkerGlobalScopeBase::queueTaskToEventLoop(const JSGlobalObject* object, Ref<JSC::Microtask>&& task) { const JSWorkerGlobalScopeBase* thisObject = static_cast<const JSWorkerGlobalScopeBase*>(object); - thisObject->scriptExecutionContext()->postTask(JSGlobalObjectTask::create((JSDOMGlobalObject*)thisObject, task)); + thisObject->scriptExecutionContext()->postTask(JSGlobalObjectTask((JSDOMGlobalObject*)thisObject, WTFMove(task))); } -JSValue toJS(ExecState* exec, JSDOMGlobalObject*, WorkerGlobalScope* workerGlobalScope) +JSValue toJS(ExecState* exec, JSDOMGlobalObject*, WorkerGlobalScope& workerGlobalScope) { return toJS(exec, workerGlobalScope); } -JSValue toJS(ExecState*, WorkerGlobalScope* workerGlobalScope) +JSValue toJS(ExecState*, WorkerGlobalScope& workerGlobalScope) { - if (!workerGlobalScope) - return jsNull(); - WorkerScriptController* script = workerGlobalScope->script(); + WorkerScriptController* script = workerGlobalScope.script(); if (!script) return jsNull(); JSWorkerGlobalScope* contextWrapper = script->workerGlobalScopeWrapper(); ASSERT(contextWrapper); - return contextWrapper; + return contextWrapper->proxy(); } -JSDedicatedWorkerGlobalScope* toJSDedicatedWorkerGlobalScope(JSValue value) +JSDedicatedWorkerGlobalScope* toJSDedicatedWorkerGlobalScope(VM& vm, JSValue value) { if (!value.isObject()) return 0; - const ClassInfo* classInfo = asObject(value)->classInfo(); + const ClassInfo* classInfo = asObject(value)->classInfo(vm); if (classInfo == JSDedicatedWorkerGlobalScope::info()) return jsCast<JSDedicatedWorkerGlobalScope*>(asObject(value)); + if (classInfo == JSProxy::info()) + return jsDynamicDowncast<JSDedicatedWorkerGlobalScope*>(vm, jsCast<JSProxy*>(asObject(value))->target()); return 0; } -#if ENABLE(SHARED_WORKERS) -JSSharedWorkerGlobalScope* toJSSharedWorkerGlobalScope(JSValue value) -{ - if (!value.isObject()) - return 0; - const ClassInfo* classInfo = asObject(value)->classInfo(); - if (classInfo == JSSharedWorkerGlobalScope::info()) - return jsCast<JSSharedWorkerGlobalScope*>(asObject(value)); - return 0; -} -#endif -JSWorkerGlobalScope* toJSWorkerGlobalScope(JSValue value) +JSWorkerGlobalScope* toJSWorkerGlobalScope(VM& vm, JSValue value) { - JSWorkerGlobalScope* context = toJSDedicatedWorkerGlobalScope(value); -#if ENABLE(SHARED_WORKERS) - if (!context) - context = toJSSharedWorkerGlobalScope(value); -#endif - return context; + return toJSDedicatedWorkerGlobalScope(vm, value); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.h b/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.h index e2e93e14e..b0b36f9be 100644 --- a/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.h +++ b/Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.h @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -24,15 +24,14 @@ * */ -#ifndef JSWorkerGlobalScopeBase_h -#define JSWorkerGlobalScopeBase_h +#pragma once #include "JSDOMGlobalObject.h" +#include "JSDOMWrapper.h" namespace WebCore { class JSDedicatedWorkerGlobalScope; - class JSSharedWorkerGlobalScope; class JSWorkerGlobalScope; class WorkerGlobalScope; @@ -43,7 +42,8 @@ namespace WebCore { DECLARE_INFO; - WorkerGlobalScope& impl() const { return *m_impl; } + WorkerGlobalScope& wrapped() const { return *m_wrapped; } + JSC::JSProxy* proxy() const { ASSERT(m_proxy); return m_proxy.get(); } ScriptExecutionContext* scriptExecutionContext() const; static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) @@ -53,34 +53,31 @@ namespace WebCore { static const JSC::GlobalObjectMethodTable s_globalObjectMethodTable; - static bool allowsAccessFrom(const JSC::JSGlobalObject*, JSC::ExecState*); - static bool supportsProfiling(const JSC::JSGlobalObject*); static bool supportsRichSourceInfo(const JSC::JSGlobalObject*); static bool shouldInterruptScript(const JSC::JSGlobalObject*); static bool shouldInterruptScriptBeforeTimeout(const JSC::JSGlobalObject*); - static bool javaScriptExperimentsEnabled(const JSC::JSGlobalObject*); - static void queueTaskToEventLoop(const JSC::JSGlobalObject*, PassRefPtr<JSC::Microtask>); + static JSC::RuntimeFlags javaScriptRuntimeFlags(const JSC::JSGlobalObject*); + static void queueTaskToEventLoop(const JSC::JSGlobalObject*, Ref<JSC::Microtask>&&); protected: - JSWorkerGlobalScopeBase(JSC::VM&, JSC::Structure*, PassRefPtr<WorkerGlobalScope>); - void finishCreation(JSC::VM&); + JSWorkerGlobalScopeBase(JSC::VM&, JSC::Structure*, RefPtr<WorkerGlobalScope>&&); + void finishCreation(JSC::VM&, JSC::JSProxy*); + + static void visitChildren(JSC::JSCell*, JSC::SlotVisitor&); private: - RefPtr<WorkerGlobalScope> m_impl; + RefPtr<WorkerGlobalScope> m_wrapped; + JSC::WriteBarrier<JSC::JSProxy> m_proxy; }; // Returns a JSWorkerGlobalScope or jsNull() // Always ignores the execState and passed globalObject, WorkerGlobalScope is itself a globalObject and will always use its own prototype chain. - JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, WorkerGlobalScope*); - JSC::JSValue toJS(JSC::ExecState*, WorkerGlobalScope*); - - JSDedicatedWorkerGlobalScope* toJSDedicatedWorkerGlobalScope(JSC::JSValue); - JSWorkerGlobalScope* toJSWorkerGlobalScope(JSC::JSValue); + JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, WorkerGlobalScope&); + inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, WorkerGlobalScope* scope) { return scope ? toJS(exec, globalObject, *scope) : JSC::jsNull(); } + JSC::JSValue toJS(JSC::ExecState*, WorkerGlobalScope&); + inline JSC::JSValue toJS(JSC::ExecState* exec, WorkerGlobalScope* scope) { return scope ? toJS(exec, *scope) : JSC::jsNull(); } -#if ENABLE(SHARED_WORKERS) - JSSharedWorkerGlobalScope* toJSSharedWorkerGlobalScope(JSC::JSValue); -#endif + JSDedicatedWorkerGlobalScope* toJSDedicatedWorkerGlobalScope(JSC::VM&, JSC::JSValue); + JSWorkerGlobalScope* toJSWorkerGlobalScope(JSC::VM&, JSC::JSValue); } // namespace WebCore - -#endif // JSWorkerGlobalScopeBase_h diff --git a/Source/WebCore/bindings/js/JSWorkerGlobalScopeCustom.cpp b/Source/WebCore/bindings/js/JSWorkerGlobalScopeCustom.cpp index d12d98e84..6663dfb7b 100644 --- a/Source/WebCore/bindings/js/JSWorkerGlobalScopeCustom.cpp +++ b/Source/WebCore/bindings/js/JSWorkerGlobalScopeCustom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2011 Apple Inc. All Rights Reserved. + * Copyright (C) 2008-2009, 2011, 2016 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,95 +24,61 @@ */ #include "config.h" - #include "JSWorkerGlobalScope.h" -#include "ExceptionCode.h" -#include "JSDOMBinding.h" -#include "JSDOMGlobalObject.h" -#include "JSEventListener.h" -#include "JSEventSource.h" -#include "JSMessageChannel.h" -#include "JSMessagePort.h" -#include "JSWorkerLocation.h" -#include "JSWorkerNavigator.h" -#include "JSXMLHttpRequest.h" +#include "JSDOMConvert.h" #include "ScheduledAction.h" #include "WorkerGlobalScope.h" -#include "WorkerLocation.h" -#include "WorkerNavigator.h" -#include <interpreter/Interpreter.h> - -#if ENABLE(WEB_SOCKETS) -#include "JSWebSocket.h" -#endif using namespace JSC; namespace WebCore { -void JSWorkerGlobalScope::visitChildren(JSCell* cell, SlotVisitor& visitor) +void JSWorkerGlobalScope::visitAdditionalChildren(SlotVisitor& visitor) { - JSWorkerGlobalScope* thisObject = jsCast<JSWorkerGlobalScope*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(thisObject, visitor); - - if (WorkerLocation* location = thisObject->impl().optionalLocation()) + if (auto* location = wrapped().optionalLocation()) visitor.addOpaqueRoot(location); - if (WorkerNavigator* navigator = thisObject->impl().optionalNavigator()) + if (auto* navigator = wrapped().optionalNavigator()) visitor.addOpaqueRoot(navigator); - - thisObject->impl().visitJSEventListeners(visitor); -} - -bool JSWorkerGlobalScope::getOwnPropertySlotDelegate(ExecState* exec, PropertyName propertyName, PropertySlot& slot) -{ - // Look for overrides before looking at any of our own properties. - if (JSGlobalObject::getOwnPropertySlot(this, exec, propertyName, slot)) - return true; - return false; + ScriptExecutionContext& context = wrapped(); + visitor.addOpaqueRoot(&context); + + // Normally JSEventTargetCustom.cpp's JSEventTarget::visitAdditionalChildren() would call this. But + // even though WorkerGlobalScope is an EventTarget, JSWorkerGlobalScope does not subclass + // JSEventTarget, so we need to do this here. + wrapped().visitJSEventListeners(visitor); } -JSValue JSWorkerGlobalScope::importScripts(ExecState* exec) +JSValue JSWorkerGlobalScope::setTimeout(ExecState& state) { - if (!exec->argumentCount()) - return jsUndefined(); - - Vector<String> urls; - for (unsigned i = 0; i < exec->argumentCount(); i++) { - urls.append(exec->uncheckedArgument(i).toString(exec)->value(exec)); - if (exec->hadException()) - return jsUndefined(); - } - ExceptionCode ec = 0; + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); - impl().importScripts(urls, ec); - setDOMException(exec, ec); - return jsUndefined(); -} + if (UNLIKELY(state.argumentCount() < 1)) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); -JSValue JSWorkerGlobalScope::setTimeout(ExecState* exec) -{ - OwnPtr<ScheduledAction> action = ScheduledAction::create(exec, currentWorld(exec), impl().contentSecurityPolicy()); - if (exec->hadException()) - return jsUndefined(); + std::unique_ptr<ScheduledAction> action = ScheduledAction::create(&state, globalObject()->world(), wrapped().contentSecurityPolicy()); + RETURN_IF_EXCEPTION(scope, JSValue()); if (!action) return jsNumber(0); - int delay = exec->argument(1).toInt32(exec); - return jsNumber(impl().setTimeout(action.release(), delay)); + int delay = state.argument(1).toInt32(&state); + return jsNumber(wrapped().setTimeout(WTFMove(action), delay)); } -JSValue JSWorkerGlobalScope::setInterval(ExecState* exec) +JSValue JSWorkerGlobalScope::setInterval(ExecState& state) { - OwnPtr<ScheduledAction> action = ScheduledAction::create(exec, currentWorld(exec), impl().contentSecurityPolicy()); - if (exec->hadException()) - return jsUndefined(); + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + if (UNLIKELY(state.argumentCount() < 1)) + return throwException(&state, scope, createNotEnoughArgumentsError(&state)); + + std::unique_ptr<ScheduledAction> action = ScheduledAction::create(&state, globalObject()->world(), wrapped().contentSecurityPolicy()); + RETURN_IF_EXCEPTION(scope, JSValue()); if (!action) return jsNumber(0); - int delay = exec->argument(1).toInt32(exec); - return jsNumber(impl().setInterval(action.release(), delay)); + int delay = state.argument(1).toInt32(&state); + return jsNumber(wrapped().setInterval(WTFMove(action), delay)); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSXMLDocumentCustom.cpp b/Source/WebCore/bindings/js/JSXMLDocumentCustom.cpp new file mode 100644 index 000000000..9c82c500b --- /dev/null +++ b/Source/WebCore/bindings/js/JSXMLDocumentCustom.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2016 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 "JSXMLDocument.h" + +#include "JSDOMWindow.h" +#include "JSDocumentCustom.h" +#include "JSSVGDocument.h" +#include "NodeTraversal.h" + +namespace WebCore { + +using namespace JSC; + +JSValue toJSNewlyCreated(ExecState* state, JSDOMGlobalObject* globalObject, Ref<XMLDocument>&& document) +{ + reportMemoryForDocumentIfFrameless(*state, document.get()); + + return createWrapper<XMLDocument>(globalObject, WTFMove(document)); +} + +JSValue toJS(ExecState* state, JSDOMGlobalObject* globalObject, XMLDocument& document) +{ + if (auto* wrapper = cachedDocumentWrapper(*state, *globalObject, document)) + return wrapper; + return toJSNewlyCreated(state, globalObject, Ref<XMLDocument>(document)); +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp b/Source/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp index 7ea887833..7d584d74c 100644 --- a/Source/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp +++ b/Source/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp @@ -10,7 +10,7 @@ * 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -39,13 +39,13 @@ #include "HTMLDocument.h" #include "InspectorInstrumentation.h" #include "JSBlob.h" +#include "JSDOMConvert.h" #include "JSDOMFormData.h" #include "JSDOMWindowCustom.h" #include "JSDocument.h" #include "JSEvent.h" #include "JSEventListener.h" #include "XMLHttpRequest.h" -#include <interpreter/StackVisitor.h> #include <runtime/ArrayBuffer.h> #include <runtime/Error.h> #include <runtime/JSArrayBuffer.h> @@ -56,184 +56,81 @@ using namespace JSC; namespace WebCore { -void JSXMLHttpRequest::visitChildren(JSCell* cell, SlotVisitor& visitor) +void JSXMLHttpRequest::visitAdditionalChildren(SlotVisitor& visitor) { - JSXMLHttpRequest* thisObject = jsCast<JSXMLHttpRequest*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(thisObject, visitor); - - if (XMLHttpRequestUpload* upload = thisObject->m_impl->optionalUpload()) + if (XMLHttpRequestUpload* upload = wrapped().optionalUpload()) visitor.addOpaqueRoot(upload); - if (Document* responseDocument = thisObject->m_impl->optionalResponseXML()) + if (Document* responseDocument = wrapped().optionalResponseXML()) visitor.addOpaqueRoot(responseDocument); - - if (ArrayBuffer* responseArrayBuffer = thisObject->m_impl->optionalResponseArrayBuffer()) - visitor.addOpaqueRoot(responseArrayBuffer); - - if (Blob* responseBlob = thisObject->m_impl->optionalResponseBlob()) - visitor.addOpaqueRoot(responseBlob); - - if (thisObject->m_response) - visitor.append(&thisObject->m_response); - - thisObject->m_impl->visitJSEventListeners(visitor); } -// Custom functions -JSValue JSXMLHttpRequest::open(ExecState* exec) +JSValue JSXMLHttpRequest::responseText(ExecState& state) const { - if (exec->argumentCount() < 2) - return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); - - const URL& url = impl().scriptExecutionContext()->completeURL(exec->uncheckedArgument(1).toString(exec)->value(exec)); - String method = exec->uncheckedArgument(0).toString(exec)->value(exec); - - ExceptionCode ec = 0; - if (exec->argumentCount() >= 3) { - bool async = exec->uncheckedArgument(2).toBoolean(exec); - if (!exec->argument(3).isUndefined()) { - String user = valueToStringWithNullCheck(exec, exec->uncheckedArgument(3)); - - if (!exec->argument(4).isUndefined()) { - String password = valueToStringWithNullCheck(exec, exec->uncheckedArgument(4)); - impl().open(method, url, async, user, password, ec); - } else - impl().open(method, url, async, user, ec); - } else - impl().open(method, url, async, ec); - } else - impl().open(method, url, ec); - - setDOMException(exec, ec); - return jsUndefined(); -} - -class SendFunctor { -public: - SendFunctor() - : m_hasSkippedFirstFrame(false) - , m_line(0) - , m_column(0) - { - } + auto result = wrapped().responseText(); - unsigned line() const { return m_line; } - unsigned column() const { return m_column; } - String url() const { return m_url; } - - StackVisitor::Status operator()(StackVisitor& visitor) - { - if (!m_hasSkippedFirstFrame) { - m_hasSkippedFirstFrame = true; - return StackVisitor::Continue; - } - - unsigned line = 0; - unsigned column = 0; - visitor->computeLineAndColumn(line, column); - m_line = line; - m_column = column; - m_url = visitor->sourceURL(); - return StackVisitor::Done; + if (UNLIKELY(result.hasException())) { + auto& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + propagateException(state, scope, result.releaseException()); + return { }; } -private: - bool m_hasSkippedFirstFrame; - unsigned m_line; - unsigned m_column; - String m_url; -}; + auto resultValue = result.releaseReturnValue(); + if (resultValue.isNull()) + return jsNull(); -JSValue JSXMLHttpRequest::send(ExecState* exec) -{ - InspectorInstrumentation::willSendXMLHttpRequest(impl().scriptExecutionContext(), impl().url()); - - ExceptionCode ec = 0; - JSValue val = exec->argument(0); - if (val.isUndefinedOrNull()) - impl().send(ec); - else if (val.inherits(JSDocument::info())) - impl().send(toDocument(val), ec); - else if (val.inherits(JSBlob::info())) - impl().send(toBlob(val), ec); - else if (val.inherits(JSDOMFormData::info())) - impl().send(toDOMFormData(val), ec); - else if (val.inherits(JSArrayBuffer::info())) - impl().send(toArrayBuffer(val), ec); - else if (val.inherits(JSArrayBufferView::info())) { - RefPtr<ArrayBufferView> view = toArrayBufferView(val); - impl().send(view.get(), ec); - } else - impl().send(val.toString(exec)->value(exec), ec); - - SendFunctor functor; - exec->iterate(functor); - impl().setLastSendLineAndColumnNumber(functor.line(), functor.column()); - impl().setLastSendURL(functor.url()); - setDOMException(exec, ec); - return jsUndefined(); + // See JavaScriptCore for explanation: Should be used for any string that is already owned by another + // object, to let the engine know that collecting the JSString wrapper is unlikely to save memory. + return jsOwnedString(&state, resultValue); } -JSValue JSXMLHttpRequest::responseText(ExecState* exec) const +JSValue JSXMLHttpRequest::retrieveResponse(ExecState& state) { - ExceptionCode ec = 0; - String text = impl().responseText(ec); - if (ec) { - setDOMException(exec, ec); + auto type = wrapped().responseType(); + + switch (type) { + case XMLHttpRequest::ResponseType::EmptyString: + case XMLHttpRequest::ResponseType::Text: + return responseText(state); + default: + break; + } + + if (!wrapped().doneWithoutErrors()) + return jsNull(); + + JSValue value; + switch (type) { + case XMLHttpRequest::ResponseType::EmptyString: + case XMLHttpRequest::ResponseType::Text: + ASSERT_NOT_REACHED(); return jsUndefined(); + + case XMLHttpRequest::ResponseType::Json: + value = JSONParse(&state, wrapped().responseTextIgnoringResponseType()); + if (!value) + value = jsNull(); + break; + + case XMLHttpRequest::ResponseType::Document: { + auto document = wrapped().responseXML(); + ASSERT(!document.hasException()); + value = toJS<IDLInterface<Document>>(state, *globalObject(), document.releaseReturnValue()); + break; } - return jsOwnedStringOrNull(exec, text); -} -JSValue JSXMLHttpRequest::response(ExecState* exec) const -{ - switch (impl().responseTypeCode()) { - case XMLHttpRequest::ResponseTypeDefault: - case XMLHttpRequest::ResponseTypeText: - return responseText(exec); - - case XMLHttpRequest::ResponseTypeJSON: - { - // FIXME: Use CachedAttribute for other types as well. - if (m_response && impl().responseCacheIsValid()) - return m_response.get(); - - if (!impl().doneWithoutErrors()) - return jsNull(); - - JSValue value = JSONParse(exec, impl().responseTextIgnoringResponseType()); - if (!value) - value = jsNull(); - JSXMLHttpRequest* jsRequest = const_cast<JSXMLHttpRequest*>(this); - jsRequest->m_response.set(exec->vm(), jsRequest, value); - - impl().didCacheResponseJSON(); - - return value; - } - - case XMLHttpRequest::ResponseTypeDocument: - { - ExceptionCode ec = 0; - Document* document = impl().responseXML(ec); - if (ec) { - setDOMException(exec, ec); - return jsUndefined(); - } - return toJS(exec, globalObject(), document); - } - - case XMLHttpRequest::ResponseTypeBlob: - return toJS(exec, globalObject(), impl().responseBlob()); - - case XMLHttpRequest::ResponseTypeArrayBuffer: - return toJS(exec, globalObject(), impl().responseArrayBuffer()); + case XMLHttpRequest::ResponseType::Blob: + value = toJSNewlyCreated<IDLInterface<Blob>>(state, *globalObject(), wrapped().createResponseBlob()); + break; + + case XMLHttpRequest::ResponseType::Arraybuffer: + value = toJS<IDLInterface<ArrayBuffer>>(state, *globalObject(), wrapped().createResponseArrayBuffer()); + break; } - return jsUndefined(); + wrapped().didCacheResponse(); + return value; } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSXPathNSResolverCustom.cpp b/Source/WebCore/bindings/js/JSXPathNSResolverCustom.cpp new file mode 100644 index 000000000..8c1761ccb --- /dev/null +++ b/Source/WebCore/bindings/js/JSXPathNSResolverCustom.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 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 "JSXPathNSResolver.h" + +#include "JSCustomXPathNSResolver.h" +#include "JSDOMExceptionHandling.h" + +using namespace JSC; + +namespace WebCore { + +RefPtr<XPathNSResolver> JSXPathNSResolver::toWrapped(VM& vm, ExecState& state, JSValue value) +{ + if (value.inherits(vm, JSXPathNSResolver::info())) + return &jsCast<JSXPathNSResolver*>(asObject(value))->wrapped(); + + auto result = JSCustomXPathNSResolver::create(state, value); + if (UNLIKELY(result.hasException())) { + auto scope = DECLARE_THROW_SCOPE(vm); + propagateException(state, scope, result.releaseException()); + return nullptr; + } + return result.releaseReturnValue(); +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSXPathResultCustom.cpp b/Source/WebCore/bindings/js/JSXPathResultCustom.cpp index 35ba89231..d4fbbef6f 100644 --- a/Source/WebCore/bindings/js/JSXPathResultCustom.cpp +++ b/Source/WebCore/bindings/js/JSXPathResultCustom.cpp @@ -26,30 +26,18 @@ #include "config.h" #include "JSXPathResult.h" -#include "JSDOMBinding.h" #include "JSNodeCustom.h" -#include "XPathResult.h" #include "XPathValue.h" -using namespace JSC; - namespace WebCore { -void JSXPathResult::visitChildren(JSCell* cell, SlotVisitor& visitor) +void JSXPathResult::visitAdditionalChildren(JSC::SlotVisitor& visitor) { - JSXPathResult* thisObject = jsCast<JSXPathResult*>(cell); - ASSERT_GC_OBJECT_INHERITS(thisObject, info()); - COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag); - ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); - Base::visitChildren(thisObject, visitor); - - const XPath::Value& xpathValue = thisObject->impl().value(); - if (xpathValue.isNodeSet()) { - const XPath::NodeSet& nodesToMark = xpathValue.toNodeSet(); - for (size_t i = 0; i < nodesToMark.size(); ++i) { - Node* node = nodesToMark[i]; - visitor.addOpaqueRoot(root(node)); - } + auto& value = wrapped().value(); + if (value.isNodeSet()) { + // FIXME: This looks like it might race, but I'm not sure. + for (auto& node : value.toNodeSet()) + visitor.addOpaqueRoot(root(node.get())); } } diff --git a/Source/WebCore/bindings/js/JSXSLTProcessorCustom.cpp b/Source/WebCore/bindings/js/JSXSLTProcessorCustom.cpp deleted file mode 100644 index 1086de270..000000000 --- a/Source/WebCore/bindings/js/JSXSLTProcessorCustom.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2008 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE 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 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" - -#if ENABLE(XSLT) - -#include "JSXSLTProcessor.h" - -#include "Document.h" -#include "DocumentFragment.h" -#include "JSDocument.h" -#include "JSDocumentFragment.h" -#include "JSNode.h" -#include "Node.h" -#include "XSLTProcessor.h" -#include "JSDOMBinding.h" -#include <wtf/text/WTFString.h> - -using namespace JSC; - -namespace WebCore { - -JSValue JSXSLTProcessor::setParameter(ExecState* exec) -{ - if (exec->argument(1).isUndefinedOrNull() || exec->argument(2).isUndefinedOrNull()) - return jsUndefined(); // Throw exception? - String namespaceURI = exec->uncheckedArgument(0).toString(exec)->value(exec); - String localName = exec->uncheckedArgument(1).toString(exec)->value(exec); - String value = exec->uncheckedArgument(2).toString(exec)->value(exec); - impl().setParameter(namespaceURI, localName, value); - return jsUndefined(); -} - -JSValue JSXSLTProcessor::getParameter(ExecState* exec) -{ - if (exec->argument(1).isUndefinedOrNull()) - return jsUndefined(); - String namespaceURI = exec->uncheckedArgument(0).toString(exec)->value(exec); - String localName = exec->uncheckedArgument(1).toString(exec)->value(exec); - String value = impl().getParameter(namespaceURI, localName); - return jsStringOrUndefined(exec, value); -} - -JSValue JSXSLTProcessor::removeParameter(ExecState* exec) -{ - if (exec->argument(1).isUndefinedOrNull()) - return jsUndefined(); - String namespaceURI = exec->uncheckedArgument(0).toString(exec)->value(exec); - String localName = exec->uncheckedArgument(1).toString(exec)->value(exec); - impl().removeParameter(namespaceURI, localName); - return jsUndefined(); -} - -} // namespace WebCore - -#endif // ENABLE(XSLT) diff --git a/Source/WebCore/bindings/js/ModuleFetchFailureKind.h b/Source/WebCore/bindings/js/ModuleFetchFailureKind.h new file mode 100644 index 000000000..259ef1ed6 --- /dev/null +++ b/Source/WebCore/bindings/js/ModuleFetchFailureKind.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2017 Yusuke Suzuki <utatane.tea@gmail.com> + * + * 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. + */ + +#pragma once + +namespace WebCore { + +enum class ModuleFetchFailureKind { + WasErrored, + WasCanceled, +}; + +} // namespace WebCore + diff --git a/Source/WebCore/bindings/js/PageScriptDebugServer.cpp b/Source/WebCore/bindings/js/PageScriptDebugServer.cpp deleted file mode 100644 index e938d8900..000000000 --- a/Source/WebCore/bindings/js/PageScriptDebugServer.cpp +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright (c) 2011 Google Inc. All rights reserved. - * Copyright (C) 2013 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "PageScriptDebugServer.h" - -#include "Document.h" -#include "EventLoop.h" -#include "FrameView.h" -#include "JSDOMWindowCustom.h" -#include "MainFrame.h" -#include "Page.h" -#include "PageGroup.h" -#include "PluginView.h" -#include "ScriptController.h" -#include "Timer.h" -#include "Widget.h" -#include <runtime/JSLock.h> -#include <wtf/MainThread.h> -#include <wtf/OwnPtr.h> -#include <wtf/PassOwnPtr.h> -#include <wtf/StdLibExtras.h> - -#if PLATFORM(IOS) -#include "JSDOMWindowBase.h" -#include "WebCoreThreadInternal.h" -#endif - -using namespace JSC; -using namespace Inspector; - -namespace WebCore { - -static Page* toPage(JSGlobalObject* globalObject) -{ - ASSERT_ARG(globalObject, globalObject); - - JSDOMWindow* window = asJSDOMWindow(globalObject); - Frame* frame = window->impl().frame(); - return frame ? frame->page() : 0; -} - -PageScriptDebugServer& PageScriptDebugServer::shared() -{ - DEFINE_STATIC_LOCAL(PageScriptDebugServer, server, ()); - return server; -} - -PageScriptDebugServer::PageScriptDebugServer() - : ScriptDebugServer() - , m_pausedPage(0) -{ -} - -PageScriptDebugServer::~PageScriptDebugServer() -{ -} - -void PageScriptDebugServer::addListener(ScriptDebugListener* listener, Page* page) -{ - ASSERT_ARG(listener, listener); - ASSERT_ARG(page, page); - - OwnPtr<ListenerSet>& listeners = m_pageListenersMap.add(page, nullptr).iterator->value; - if (!listeners) - listeners = adoptPtr(new ListenerSet); - - bool wasEmpty = listeners->isEmpty(); - listeners->add(listener); - - if (wasEmpty) - didAddFirstListener(page); -} - -void PageScriptDebugServer::removeListener(ScriptDebugListener* listener, Page* page, bool skipRecompile) -{ - ASSERT_ARG(listener, listener); - ASSERT_ARG(page, page); - - PageListenersMap::iterator it = m_pageListenersMap.find(page); - if (it == m_pageListenersMap.end()) - return; - - ListenerSet* listeners = it->value.get(); - listeners->remove(listener); - - if (listeners->isEmpty()) { - m_pageListenersMap.remove(it); - didRemoveLastListener(page, skipRecompile); - } -} - -void PageScriptDebugServer::recompileAllJSFunctions() -{ - JSLockHolder lock(JSDOMWindow::commonVM()); - Debugger::recompileAllJSFunctions(JSDOMWindow::commonVM()); -} - -ScriptDebugServer::ListenerSet* PageScriptDebugServer::getListenersForGlobalObject(JSGlobalObject* globalObject) -{ - Page* page = toPage(globalObject); - if (!page) - return 0; - return m_pageListenersMap.get(page); -} - -void PageScriptDebugServer::didPause(JSC::JSGlobalObject* globalObject) -{ - ASSERT(!m_pausedPage); - - Page* page = toPage(globalObject); - ASSERT(page); - if (!page) - return; - - m_pausedPage = page; - - setJavaScriptPaused(page->group(), true); -} - -void PageScriptDebugServer::didContinue(JSC::JSGlobalObject* globalObject) -{ - // Page can be null if we are continuing because the Page closed. - Page* page = toPage(globalObject); - ASSERT(!page || page == m_pausedPage); - - m_pausedPage = 0; - - if (page) - setJavaScriptPaused(page->group(), false); -} - -void PageScriptDebugServer::didAddFirstListener(Page* page) -{ - // Set debugger before recompiling to get sourceParsed callbacks. - page->setDebugger(this); - recompileAllJSFunctions(); -} - -void PageScriptDebugServer::didRemoveLastListener(Page* page, bool skipRecompile) -{ - ASSERT(page); - - if (m_pausedPage == page) - m_doneProcessingDebuggerEvents = true; - - // Clear debugger before recompiling because we do not need sourceParsed callbacks. - page->setDebugger(nullptr); - - if (!skipRecompile) - recompileAllJSFunctions(); -} - -void PageScriptDebugServer::runEventLoopWhilePaused() -{ -#if PLATFORM(IOS) - // On iOS, running an EventLoop causes us to run a nested WebRunLoop. - // Since the WebThread is autoreleased at the end of run loop iterations - // we need to gracefully handle releasing and reacquiring the lock. - ASSERT(WebThreadIsLockedOrDisabled()); - { - if (WebThreadIsEnabled()) - JSC::JSLock::DropAllLocks dropAllLocks(WebCore::JSDOMWindowBase::commonVM(), JSC::JSLock::DropAllLocks::AlwaysDropLocks); - WebRunLoopEnableNested(); -#endif - - TimerBase::fireTimersInNestedEventLoop(); - - EventLoop loop; - while (!m_doneProcessingDebuggerEvents && !loop.ended()) - loop.cycle(); - -#if PLATFORM(IOS) - WebRunLoopDisableNested(); - } - ASSERT(WebThreadIsLockedOrDisabled()); -#endif -} - -bool PageScriptDebugServer::isContentScript(ExecState* exec) const -{ - return ¤tWorld(exec) != &mainThreadNormalWorld(); -} - -void PageScriptDebugServer::reportException(ExecState* exec, JSValue exception) const -{ - WebCore::reportException(exec, exception); -} - -void PageScriptDebugServer::setJavaScriptPaused(const PageGroup& pageGroup, bool paused) -{ - setMainThreadCallbacksPaused(paused); - - const HashSet<Page*>& pages = pageGroup.pages(); - - HashSet<Page*>::const_iterator end = pages.end(); - for (HashSet<Page*>::const_iterator it = pages.begin(); it != end; ++it) - setJavaScriptPaused(*it, paused); -} - -void PageScriptDebugServer::setJavaScriptPaused(Page* page, bool paused) -{ - ASSERT_ARG(page, page); - - page->setDefersLoading(paused); - - for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext()) - setJavaScriptPaused(frame, paused); -} - -void PageScriptDebugServer::setJavaScriptPaused(Frame* frame, bool paused) -{ - ASSERT_ARG(frame, frame); - - if (!frame->script().canExecuteScripts(NotAboutToExecuteScript)) - return; - - frame->script().setPaused(paused); - - Document* document = frame->document(); - if (paused) { - document->suspendScriptedAnimationControllerCallbacks(); - document->suspendActiveDOMObjects(ActiveDOMObject::JavaScriptDebuggerPaused); - } else { - document->resumeActiveDOMObjects(ActiveDOMObject::JavaScriptDebuggerPaused); - document->resumeScriptedAnimationControllerCallbacks(); - } - - setJavaScriptPaused(frame->view(), paused); -} - -void PageScriptDebugServer::setJavaScriptPaused(FrameView* view, bool paused) -{ - if (!view) - return; - - for (auto it = view->children().begin(), end = view->children().end(); it != end; ++it) { - Widget* widget = (*it).get(); - if (!widget->isPluginView()) - continue; - toPluginView(widget)->setJavaScriptPaused(paused); - } -} - -} // namespace WebCore diff --git a/Source/WebCore/bindings/js/PageScriptDebugServer.h b/Source/WebCore/bindings/js/PageScriptDebugServer.h deleted file mode 100644 index 75db77a1c..000000000 --- a/Source/WebCore/bindings/js/PageScriptDebugServer.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2011 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef PageScriptDebugServer_h -#define PageScriptDebugServer_h - -#include <inspector/ScriptDebugServer.h> -#include <wtf/Forward.h> - -namespace WebCore { - -class Frame; -class FrameView; -class Page; -class PageGroup; - -class PageScriptDebugServer : public Inspector::ScriptDebugServer { - WTF_MAKE_NONCOPYABLE(PageScriptDebugServer); -public: - static PageScriptDebugServer& shared(); - - void addListener(Inspector::ScriptDebugListener*, Page*); - void removeListener(Inspector::ScriptDebugListener*, Page*, bool skipRecompile); - - virtual void recompileAllJSFunctions() override; - -private: - typedef HashMap<Page*, OwnPtr<ListenerSet>> PageListenersMap; - - PageScriptDebugServer(); - virtual ~PageScriptDebugServer(); - - virtual ListenerSet* getListenersForGlobalObject(JSC::JSGlobalObject*); - virtual void didPause(JSC::JSGlobalObject*); - virtual void didContinue(JSC::JSGlobalObject*); - virtual void runEventLoopWhilePaused(); - virtual bool isContentScript(JSC::ExecState*) const override; - virtual void reportException(JSC::ExecState*, JSC::JSValue) const override; - - - void didAddFirstListener(Page*); - void didRemoveLastListener(Page*, bool skipRecompile); - - void setJavaScriptPaused(const PageGroup&, bool paused); - void setJavaScriptPaused(Page*, bool paused); - void setJavaScriptPaused(Frame*, bool paused); - void setJavaScriptPaused(FrameView*, bool paused); - - PageListenersMap m_pageListenersMap; - Page* m_pausedPage; -}; - -} // namespace WebCore - -#endif // PageScriptDebugServer_h diff --git a/Source/WebCore/bindings/js/ReadableStreamDefaultController.cpp b/Source/WebCore/bindings/js/ReadableStreamDefaultController.cpp new file mode 100644 index 000000000..080cf7013 --- /dev/null +++ b/Source/WebCore/bindings/js/ReadableStreamDefaultController.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2016 Canon Inc. + * Copyright (C) 2016 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 required to be 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. + * 3. Neither the name of Canon Inc. nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CANON 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 CANON INC. AND 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 "ReadableStreamDefaultController.h" + +#if ENABLE(READABLE_STREAM_API) + +#include "WebCoreJSClientData.h" +#include <heap/HeapInlines.h> +#include <runtime/IdentifierInlines.h> +#include <runtime/JSObjectInlines.h> + +namespace WebCore { + +static inline JSC::JSValue callFunction(JSC::ExecState& state, JSC::JSValue jsFunction, JSC::JSValue thisValue, const JSC::ArgList& arguments) +{ + JSC::CallData callData; + auto callType = JSC::getCallData(jsFunction, callData); + return call(&state, jsFunction, callType, callData, thisValue, arguments); +} + +JSC::JSValue ReadableStreamDefaultController::invoke(JSC::ExecState& state, JSC::JSObject& object, const char* propertyName, JSC::JSValue parameter) +{ + JSC::VM& vm = state.vm(); + JSC::JSLockHolder lock(vm); + auto scope = DECLARE_THROW_SCOPE(vm); + + auto function = object.get(&state, JSC::Identifier::fromString(&state, propertyName)); + RETURN_IF_EXCEPTION(scope, JSC::JSValue()); + + if (!function.isFunction()) { + if (!function.isUndefined()) + throwTypeError(&state, scope, ASCIILiteral("ReadableStream trying to call a property that is not callable")); + return JSC::jsUndefined(); + } + + JSC::MarkedArgumentBuffer arguments; + arguments.append(parameter); + + return callFunction(state, function, &object, arguments); +} + +bool ReadableStreamDefaultController::isControlledReadableStreamLocked() const +{ + auto& globalObject = this->globalObject(); + JSC::VM& vm = globalObject.vm(); + JSC::JSLockHolder lock(vm); + auto scope = DECLARE_CATCH_SCOPE(vm); + auto& state = globalExec(); + + auto& clientData = *static_cast<JSVMClientData*>(vm.clientData); + auto readableStream = m_jsController->get(&state, clientData.builtinNames().controlledReadableStreamPrivateName()); + ASSERT_UNUSED(scope, !scope.exception()); + + auto* isLocked = globalObject.builtinInternalFunctions().readableStreamInternals().m_isReadableStreamLockedFunction.get(); + ASSERT(isLocked); + + JSC::MarkedArgumentBuffer arguments; + arguments.append(readableStream); + auto result = callFunction(state, isLocked, JSC::jsUndefined(), arguments); + ASSERT(!scope.exception()); + + return result.isTrue(); +} + +} // namespace WebCore + +#endif // ENABLE(READABLE_STREAM_API) diff --git a/Source/WebCore/bindings/js/ReadableStreamDefaultController.h b/Source/WebCore/bindings/js/ReadableStreamDefaultController.h new file mode 100644 index 000000000..c3500b14a --- /dev/null +++ b/Source/WebCore/bindings/js/ReadableStreamDefaultController.h @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2016 Canon Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted, provided that the following conditions + * are required to be 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. + * 3. Neither the name of Canon Inc. nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CANON 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 CANON INC. AND 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. + */ + +#pragma once + +#if ENABLE(READABLE_STREAM_API) + +#include "JSDOMConvertBufferSource.h" +#include "JSReadableStreamDefaultController.h" +#include <runtime/JSCJSValue.h> +#include <runtime/JSCJSValueInlines.h> +#include <runtime/TypedArrays.h> + +namespace WebCore { + +class ReadableStreamSource; + +class ReadableStreamDefaultController { +public: + explicit ReadableStreamDefaultController(JSReadableStreamDefaultController* controller) : m_jsController(controller) { } + + static JSC::JSValue invoke(JSC::ExecState&, JSC::JSObject&, const char*, JSC::JSValue); + + bool enqueue(RefPtr<JSC::ArrayBuffer>&&); + + template<class ResolveResultType> + void error(const ResolveResultType&); + + void close() { invoke(*globalObject().globalExec(), jsController(), "close", JSC::jsUndefined()); } + + bool isControlledReadableStreamLocked() const; + +private: + void error(JSC::ExecState& state, JSC::JSValue value) { invoke(state, jsController(), "error", value); } + void enqueue(JSC::ExecState& state, JSC::JSValue value) { invoke(state, jsController(), "enqueue", value); } + JSReadableStreamDefaultController& jsController() const; + + JSDOMGlobalObject& globalObject() const; + JSC::ExecState& globalExec() const; + + // The owner of ReadableStreamDefaultController is responsible to keep uncollected the JSReadableStreamDefaultController. + JSReadableStreamDefaultController* m_jsController { nullptr }; +}; + +inline JSReadableStreamDefaultController& ReadableStreamDefaultController::jsController() const +{ + ASSERT(m_jsController); + return *m_jsController; +} + +inline JSDOMGlobalObject& ReadableStreamDefaultController::globalObject() const +{ + ASSERT(m_jsController); + ASSERT(m_jsController->globalObject()); + return *static_cast<JSDOMGlobalObject*>(m_jsController->globalObject()); +} + +inline JSC::ExecState& ReadableStreamDefaultController::globalExec() const +{ + ASSERT(globalObject().globalExec()); + return *globalObject().globalExec(); +} + +inline bool ReadableStreamDefaultController::enqueue(RefPtr<JSC::ArrayBuffer>&& buffer) +{ + auto& globalObject = this->globalObject(); + JSC::VM& vm = globalObject.vm(); + JSC::JSLockHolder locker(vm); + auto scope = DECLARE_THROW_SCOPE(vm); + JSC::ExecState& state = globalExec(); + + if (!buffer) { + error(state, createOutOfMemoryError(&state)); + return false; + } + auto length = buffer->byteLength(); + auto chunk = JSC::Uint8Array::create(WTFMove(buffer), 0, length); + ASSERT(chunk); + enqueue(state, toJS(&state, &globalObject, chunk.get())); + ASSERT_UNUSED(scope, !scope.exception()); + return true; +} + +template<> +inline void ReadableStreamDefaultController::error<String>(const String& errorMessage) +{ + JSC::ExecState& state = globalExec(); + JSC::JSLockHolder locker(&state); + error(state, JSC::createTypeError(&state, errorMessage)); +} + +} // namespace WebCore + +#endif // ENABLE(READABLE_STREAM_API) diff --git a/Source/WebCore/bindings/js/ScheduledAction.cpp b/Source/WebCore/bindings/js/ScheduledAction.cpp index 9173edd49..93332666b 100644 --- a/Source/WebCore/bindings/js/ScheduledAction.cpp +++ b/Source/WebCore/bindings/js/ScheduledAction.cpp @@ -29,7 +29,7 @@ #include "Document.h" #include "Frame.h" #include "FrameLoader.h" -#include "JSDOMBinding.h" +#include "JSDOMExceptionHandling.h" #include "JSDOMWindow.h" #include "JSMainThreadExecState.h" #include "JSMainThreadExecStateInstrumentation.h" @@ -39,27 +39,28 @@ #include "ScriptSourceCode.h" #include "WorkerGlobalScope.h" #include "WorkerThread.h" -#include <bindings/ScriptValue.h> #include <runtime/JSLock.h> using namespace JSC; namespace WebCore { -PassOwnPtr<ScheduledAction> ScheduledAction::create(ExecState* exec, DOMWrapperWorld& isolatedWorld, ContentSecurityPolicy* policy) +std::unique_ptr<ScheduledAction> ScheduledAction::create(ExecState* exec, DOMWrapperWorld& isolatedWorld, ContentSecurityPolicy* policy) { + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + JSValue v = exec->argument(0); CallData callData; - if (getCallData(v, callData) == CallTypeNone) { + if (getCallData(v, callData) == CallType::None) { if (policy && !policy->allowEval(exec)) return nullptr; - String string = v.toString(exec)->value(exec); - if (exec->hadException()) - return nullptr; - return adoptPtr(new ScheduledAction(string, isolatedWorld)); + String string = v.toWTFString(exec); + RETURN_IF_EXCEPTION(scope, nullptr); + return std::unique_ptr<ScheduledAction>(new ScheduledAction(string, isolatedWorld)); } - return adoptPtr(new ScheduledAction(exec, v, isolatedWorld)); + return std::unique_ptr<ScheduledAction>(new ScheduledAction(exec, v, isolatedWorld)); } ScheduledAction::ScheduledAction(ExecState* exec, JSValue function, DOMWrapperWorld& isolatedWorld) @@ -72,24 +73,22 @@ ScheduledAction::ScheduledAction(ExecState* exec, JSValue function, DOMWrapperWo m_args.append(Strong<JSC::Unknown>(exec->vm(), exec->uncheckedArgument(i))); } -void ScheduledAction::execute(ScriptExecutionContext* context) +void ScheduledAction::execute(ScriptExecutionContext& context) { - if (context->isDocument()) - execute(toDocument(context)); - else { - ASSERT_WITH_SECURITY_IMPLICATION(context->isWorkerGlobalScope()); - execute(static_cast<WorkerGlobalScope*>(context)); - } + if (is<Document>(context)) + execute(downcast<Document>(context)); + else + execute(downcast<WorkerGlobalScope>(context)); } -void ScheduledAction::executeFunctionInContext(JSGlobalObject* globalObject, JSValue thisValue, ScriptExecutionContext* context) +void ScheduledAction::executeFunctionInContext(JSGlobalObject* globalObject, JSValue thisValue, ScriptExecutionContext& context) { ASSERT(m_function); - JSLockHolder lock(context->vm()); + JSLockHolder lock(context.vm()); CallData callData; CallType callType = getCallData(m_function.get(), callData); - if (callType == CallTypeNone) + if (callType == CallType::None) return; ExecState* exec = globalObject->globalExec(); @@ -99,26 +98,27 @@ void ScheduledAction::executeFunctionInContext(JSGlobalObject* globalObject, JSV for (size_t i = 0; i < size; ++i) args.append(m_args[i].get()); - InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(context, callType, callData); + InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(&context, callType, callData); - if (context->isDocument()) - JSMainThreadExecState::call(exec, m_function.get(), callType, callData, thisValue, args); + NakedPtr<JSC::Exception> exception; + if (is<Document>(context)) + JSMainThreadExecState::profiledCall(exec, JSC::ProfilingReason::Other, m_function.get(), callType, callData, thisValue, args, exception); else - JSC::call(exec, m_function.get(), callType, callData, thisValue, args); + JSC::profiledCall(exec, JSC::ProfilingReason::Other, m_function.get(), callType, callData, thisValue, args, exception); - InspectorInstrumentation::didCallFunction(cookie); + InspectorInstrumentation::didCallFunction(cookie, &context); - if (exec->hadException()) - reportCurrentException(exec); + if (exception) + reportException(exec, exception); } -void ScheduledAction::execute(Document* document) +void ScheduledAction::execute(Document& document) { - JSDOMWindow* window = toJSDOMWindow(document->frame(), *m_isolatedWorld); + JSDOMWindow* window = toJSDOMWindow(document.frame(), *m_isolatedWorld); if (!window) return; - RefPtr<Frame> frame = window->impl().frame(); + RefPtr<Frame> frame = window->wrapped().frame(); if (!frame || !frame->script().canExecuteScripts(AboutToExecuteScript)) return; @@ -128,18 +128,18 @@ void ScheduledAction::execute(Document* document) frame->script().executeScriptInWorld(*m_isolatedWorld, m_code); } -void ScheduledAction::execute(WorkerGlobalScope* workerGlobalScope) +void ScheduledAction::execute(WorkerGlobalScope& workerGlobalScope) { // In a Worker, the execution should always happen on a worker thread. - ASSERT(workerGlobalScope->thread()->threadID() == currentThread()); + ASSERT(workerGlobalScope.thread().threadID() == currentThread()); - WorkerScriptController* scriptController = workerGlobalScope->script(); + WorkerScriptController* scriptController = workerGlobalScope.script(); if (m_function) { JSWorkerGlobalScope* contextWrapper = scriptController->workerGlobalScopeWrapper(); executeFunctionInContext(contextWrapper, contextWrapper, workerGlobalScope); } else { - ScriptSourceCode code(m_code, workerGlobalScope->url()); + ScriptSourceCode code(m_code, workerGlobalScope.url()); scriptController->evaluate(code); } } diff --git a/Source/WebCore/bindings/js/ScheduledAction.h b/Source/WebCore/bindings/js/ScheduledAction.h index 19add3fe8..dac8579ea 100644 --- a/Source/WebCore/bindings/js/ScheduledAction.h +++ b/Source/WebCore/bindings/js/ScheduledAction.h @@ -17,14 +17,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef ScheduledAction_h -#define ScheduledAction_h +#pragma once #include "JSDOMBinding.h" #include <heap/Strong.h> #include <heap/StrongInlines.h> +#include <memory> #include <runtime/JSCell.h> -#include <wtf/PassOwnPtr.h> #include <wtf/Vector.h> #include <wtf/text/WTFString.h> @@ -46,22 +45,22 @@ namespace WebCore { class ScheduledAction { WTF_MAKE_NONCOPYABLE(ScheduledAction); WTF_MAKE_FAST_ALLOCATED; public: - static PassOwnPtr<ScheduledAction> create(JSC::ExecState*, DOMWrapperWorld& isolatedWorld, ContentSecurityPolicy*); + static std::unique_ptr<ScheduledAction> create(JSC::ExecState*, DOMWrapperWorld& isolatedWorld, ContentSecurityPolicy*); - void execute(ScriptExecutionContext*); + void execute(ScriptExecutionContext&); private: ScheduledAction(JSC::ExecState*, JSC::JSValue function, DOMWrapperWorld& isolatedWorld); ScheduledAction(const String& code, DOMWrapperWorld& isolatedWorld) - : m_function(*isolatedWorld.vm()) + : m_function(isolatedWorld.vm()) , m_code(code) , m_isolatedWorld(&isolatedWorld) { } - void executeFunctionInContext(JSC::JSGlobalObject*, JSC::JSValue thisValue, ScriptExecutionContext*); - void execute(Document*); - void execute(WorkerGlobalScope*); + void executeFunctionInContext(JSC::JSGlobalObject*, JSC::JSValue thisValue, ScriptExecutionContext&); + void execute(Document&); + void execute(WorkerGlobalScope&); JSC::Strong<JSC::Unknown> m_function; Vector<JSC::Strong<JSC::Unknown>> m_args; @@ -70,5 +69,3 @@ namespace WebCore { }; } // namespace WebCore - -#endif // ScheduledAction_h diff --git a/Source/WebCore/bindings/js/ScriptCachedFrameData.cpp b/Source/WebCore/bindings/js/ScriptCachedFrameData.cpp index c4e12f942..1196db791 100644 --- a/Source/WebCore/bindings/js/ScriptCachedFrameData.cpp +++ b/Source/WebCore/bindings/js/ScriptCachedFrameData.cpp @@ -1,11 +1,11 @@ /* * Copyright (c) 2008, Google Inc. All rights reserved. * Copyright (C) 2008 Apple Inc. All Rights Reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above @@ -15,7 +15,7 @@ * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -32,14 +32,17 @@ #include "config.h" #include "ScriptCachedFrameData.h" +#include "CommonVM.h" #include "Document.h" #include "Frame.h" #include "GCController.h" #include "Page.h" +#include "PageConsoleClient.h" #include "PageGroup.h" +#include "ScriptController.h" #include <heap/StrongInlines.h> #include <runtime/JSLock.h> -#include "ScriptController.h" +#include <runtime/WeakGCMapInlines.h> using namespace JSC; @@ -47,18 +50,19 @@ namespace WebCore { ScriptCachedFrameData::ScriptCachedFrameData(Frame& frame) { - JSLockHolder lock(JSDOMWindowBase::commonVM()); + JSLockHolder lock(commonVM()); ScriptController& scriptController = frame.script(); - ScriptController::ShellMap& windowShells = scriptController.m_windowShells; + Vector<JSC::Strong<JSDOMWindowShell>> windowShells = scriptController.windowShells(); - ScriptController::ShellMap::iterator windowShellsEnd = windowShells.end(); - for (ScriptController::ShellMap::iterator iter = windowShells.begin(); iter != windowShellsEnd; ++iter) { - JSDOMWindow* window = iter->value->window(); - m_windows.add(iter->key.get(), Strong<JSDOMWindow>(window->vm(), window)); + for (size_t i = 0; i < windowShells.size(); ++i) { + JSDOMWindowShell* windowShell = windowShells[i].get(); + JSDOMWindow* window = windowShell->window(); + m_windows.add(&windowShell->world(), Strong<JSDOMWindow>(window->vm(), window)); + window->setConsoleClient(nullptr); } - scriptController.attachDebugger(0); + scriptController.attachDebugger(nullptr); } ScriptCachedFrameData::~ScriptCachedFrameData() @@ -68,29 +72,33 @@ ScriptCachedFrameData::~ScriptCachedFrameData() void ScriptCachedFrameData::restore(Frame& frame) { - JSLockHolder lock(JSDOMWindowBase::commonVM()); + JSLockHolder lock(commonVM()); + Page* page = frame.page(); ScriptController& scriptController = frame.script(); - ScriptController::ShellMap& windowShells = scriptController.m_windowShells; + Vector<JSC::Strong<JSDOMWindowShell>> windowShells = scriptController.windowShells(); - for (auto it = windowShells.begin(), end = windowShells.end(); it != end; ++it) { - DOMWrapperWorld* world = it->key.get(); - JSDOMWindowShell* windowShell = it->value.get(); + for (size_t i = 0; i < windowShells.size(); ++i) { + JSDOMWindowShell* windowShell = windowShells[i].get(); + DOMWrapperWorld* world = &windowShell->world(); if (JSDOMWindow* window = m_windows.get(world).get()) windowShell->setWindow(window->vm(), window); else { DOMWindow* domWindow = frame.document()->domWindow(); - if (&windowShell->window()->impl() == domWindow) + if (&windowShell->window()->wrapped() == domWindow) continue; windowShell->setWindow(domWindow); - if (Page* page = frame.page()) { + if (page) { scriptController.attachDebugger(windowShell, page->debugger()); windowShell->window()->setProfileGroup(page->group().identifier()); } } + + if (page) + windowShell->window()->setConsoleClient(&page->console()); } } @@ -99,9 +107,9 @@ void ScriptCachedFrameData::clear() if (m_windows.isEmpty()) return; - JSLockHolder lock(JSDOMWindowBase::commonVM()); + JSLockHolder lock(commonVM()); m_windows.clear(); - gcController().garbageCollectSoon(); + GCController::singleton().garbageCollectSoon(); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/ScriptCachedFrameData.h b/Source/WebCore/bindings/js/ScriptCachedFrameData.h index 55b98e3be..eff5e3802 100644 --- a/Source/WebCore/bindings/js/ScriptCachedFrameData.h +++ b/Source/WebCore/bindings/js/ScriptCachedFrameData.h @@ -29,8 +29,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ScriptCachedFrameData_h -#define ScriptCachedFrameData_h +#pragma once #include <heap/Strong.h> #include <wtf/HashMap.h> @@ -56,5 +55,3 @@ private: }; } // namespace WebCore - -#endif // ScriptCachedFrameData_h diff --git a/Source/WebCore/bindings/js/ScriptCallStackFactory.cpp b/Source/WebCore/bindings/js/ScriptCallStackFactory.cpp deleted file mode 100644 index 7d695a444..000000000 --- a/Source/WebCore/bindings/js/ScriptCallStackFactory.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (c) 2010 Google Inc. All rights reserved. - * Copyright (C) 2012 Research In Motion Limited. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "ScriptCallStackFactory.h" - -#include "InspectorInstrumentation.h" -#include "JSDOMBinding.h" -#include "JSMainThreadExecState.h" -#include "ScriptArguments.h" -#include "ScriptCallFrame.h" -#include "ScriptCallStack.h" -#include <bindings/ScriptValue.h> -#include <interpreter/CallFrame.h> -#include <interpreter/CallFrameInlines.h> -#include <interpreter/StackVisitor.h> -#include <runtime/ArgList.h> -#include <runtime/JSCJSValue.h> -#include <runtime/JSFunction.h> -#include <runtime/VM.h> -#include <wtf/text/WTFString.h> - -using namespace JSC; - -namespace WebCore { - -class ScriptExecutionContext; - -class CreateScriptCallStackFunctor { -public: - CreateScriptCallStackFunctor(Vector<ScriptCallFrame>& frames, size_t remainingCapacity) - : m_frames(frames) - , m_remainingCapacityForFrameCapture(remainingCapacity) - { - } - - StackVisitor::Status operator()(StackVisitor& visitor) - { - if (m_remainingCapacityForFrameCapture) { - unsigned line; - unsigned column; - visitor->computeLineAndColumn(line, column); - m_frames.append(ScriptCallFrame(visitor->functionName(), visitor->sourceURL(), line, column)); - - m_remainingCapacityForFrameCapture--; - return StackVisitor::Continue; - } - return StackVisitor::Done; - } - -private: - Vector<ScriptCallFrame>& m_frames; - size_t m_remainingCapacityForFrameCapture; -}; - -PassRefPtr<ScriptCallStack> createScriptCallStack(size_t maxStackSize, bool emptyIsAllowed) -{ - Vector<ScriptCallFrame> frames; - if (JSC::ExecState* exec = JSMainThreadExecState::currentState()) { - CallFrame* frame = exec->vm().topCallFrame; - CreateScriptCallStackFunctor functor(frames, maxStackSize); - frame->iterate(functor); - } - if (frames.isEmpty() && !emptyIsAllowed) { - // No frames found. It may happen in the case where - // a bound function is called from native code for example. - // Fallback to setting lineNumber to 0, and source and function name to "undefined". - frames.append(ScriptCallFrame("undefined", "undefined", 0, 0)); - } - return ScriptCallStack::create(frames); -} - -class CreateScriptCallStackForConsoleFunctor { -public: - CreateScriptCallStackForConsoleFunctor(bool needToSkipAFrame, size_t remainingCapacity, Vector<ScriptCallFrame>& frames) - : m_needToSkipAFrame(needToSkipAFrame) - , m_remainingCapacityForFrameCapture(remainingCapacity) - , m_frames(frames) - { - } - - StackVisitor::Status operator()(StackVisitor& visitor) - { - if (m_needToSkipAFrame) { - m_needToSkipAFrame = false; - return StackVisitor::Continue; - } - - if (m_remainingCapacityForFrameCapture) { - // This early exit is necessary to maintain our old behaviour - // but the stack trace we produce now is complete and handles all - // ways in which code may be running - if (!visitor->callee() && m_frames.size()) - return StackVisitor::Done; - - unsigned line; - unsigned column; - visitor->computeLineAndColumn(line, column); - m_frames.append(ScriptCallFrame(visitor->functionName(), visitor->sourceURL(), line, column)); - - m_remainingCapacityForFrameCapture--; - return StackVisitor::Continue; - } - return StackVisitor::Done; - } - -private: - bool m_needToSkipAFrame; - size_t m_remainingCapacityForFrameCapture; - Vector<ScriptCallFrame>& m_frames; -}; - -PassRefPtr<ScriptCallStack> createScriptCallStack(JSC::ExecState* exec, size_t maxStackSize) -{ - Vector<ScriptCallFrame> frames; - ASSERT(exec); - CallFrame* frame = exec->vm().topCallFrame; - CreateScriptCallStackForConsoleFunctor functor(true, maxStackSize, frames); - frame->iterate(functor); - if (frames.isEmpty()) { - CreateScriptCallStackForConsoleFunctor functor(false, maxStackSize, frames); - frame->iterate(functor); - } - return ScriptCallStack::create(frames); -} - -PassRefPtr<ScriptCallStack> createScriptCallStackFromException(JSC::ExecState* exec, JSC::JSValue& exception, size_t maxStackSize) -{ - Vector<ScriptCallFrame> frames; - RefCountedArray<StackFrame> stackTrace = exec->vm().exceptionStack(); - for (size_t i = 0; i < stackTrace.size() && i < maxStackSize; i++) { - if (!stackTrace[i].callee && frames.size()) - break; - - String functionName = stackTrace[i].friendlyFunctionName(exec); - unsigned line; - unsigned column; - stackTrace[i].computeLineAndColumn(line, column); - frames.append(ScriptCallFrame(functionName, stackTrace[i].sourceURL, line, column)); - } - - // FIXME: <http://webkit.org/b/115087> Web Inspector: WebCore::reportException should not evaluate JavaScript handling exceptions - // Fallback to getting at least the line and sourceURL from the exception if it has values and the exceptionStack doesn't. - if (frames.size() > 0) { - const ScriptCallFrame& firstCallFrame = frames.first(); - JSObject* exceptionObject = exception.toObject(exec); - if (exception.isObject() && firstCallFrame.sourceURL().isEmpty()) { - JSValue lineValue = exceptionObject->getDirect(exec->vm(), Identifier(exec, "line")); - int lineNumber = lineValue && lineValue.isNumber() ? int(lineValue.toNumber(exec)) : 0; - JSValue columnValue = exceptionObject->getDirect(exec->vm(), Identifier(exec, "column")); - int columnNumber = columnValue && columnValue.isNumber() ? int(columnValue.toNumber(exec)) : 0; - JSValue sourceURLValue = exceptionObject->getDirect(exec->vm(), Identifier(exec, "sourceURL")); - String exceptionSourceURL = sourceURLValue && sourceURLValue.isString() ? sourceURLValue.toString(exec)->value(exec) : ASCIILiteral("undefined"); - frames[0] = ScriptCallFrame(firstCallFrame.functionName(), exceptionSourceURL, lineNumber, columnNumber); - } - } - - return ScriptCallStack::create(frames); -} - -PassRefPtr<ScriptCallStack> createScriptCallStackForConsole(JSC::ExecState* exec) -{ - size_t maxStackSize = 1; - if (InspectorInstrumentation::hasFrontends()) { - ScriptExecutionContext* scriptExecutionContext = jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())->scriptExecutionContext(); - if (InspectorInstrumentation::consoleAgentEnabled(scriptExecutionContext)) - maxStackSize = ScriptCallStack::maxCallStackSizeToCapture; - } - return createScriptCallStack(exec, maxStackSize); -} - -PassRefPtr<ScriptArguments> createScriptArguments(JSC::ExecState* exec, unsigned skipArgumentCount) -{ - Vector<Deprecated::ScriptValue> arguments; - size_t argumentCount = exec->argumentCount(); - for (size_t i = skipArgumentCount; i < argumentCount; ++i) - arguments.append(Deprecated::ScriptValue(exec->vm(), exec->uncheckedArgument(i))); - return ScriptArguments::create(exec, arguments); -} - -} // namespace WebCore diff --git a/Source/WebCore/bindings/js/ScriptCallStackFactory.h b/Source/WebCore/bindings/js/ScriptCallStackFactory.h deleted file mode 100644 index 298bbbd40..000000000 --- a/Source/WebCore/bindings/js/ScriptCallStackFactory.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2010 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef ScriptCallStackFactory_h -#define ScriptCallStackFactory_h - -#include <wtf/Forward.h> -#include <wtf/RefCountedArray.h> - -namespace JSC { -class ExecState; -class JSValue; -struct StackFrame; -} - -namespace WebCore { - -class ScriptArguments; -class ScriptCallStack; - -PassRefPtr<ScriptCallStack> createScriptCallStack(size_t maxStackSize, bool emptyStackIsAllowed); -PassRefPtr<ScriptCallStack> createScriptCallStack(JSC::ExecState*, size_t maxStackSize); -PassRefPtr<ScriptCallStack> createScriptCallStackFromException(JSC::ExecState*, JSC::JSValue& exception, size_t maxStackSize); -PassRefPtr<ScriptCallStack> createScriptCallStackForConsole(JSC::ExecState*); -PassRefPtr<ScriptArguments> createScriptArguments(JSC::ExecState*, unsigned skipArgumentCount); - -} // namespace WebCore - -#endif // ScriptCallStackFactory_h diff --git a/Source/WebCore/bindings/js/ScriptController.cpp b/Source/WebCore/bindings/js/ScriptController.cpp index c0135ae8d..68eb91bed 100644 --- a/Source/WebCore/bindings/js/ScriptController.cpp +++ b/Source/WebCore/bindings/js/ScriptController.cpp @@ -1,7 +1,7 @@ /* * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006-2016 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,36 +22,48 @@ #include "ScriptController.h" #include "BridgeJSC.h" +#include "CachedScriptFetcher.h" +#include "CommonVM.h" #include "ContentSecurityPolicy.h" #include "DocumentLoader.h" #include "Event.h" -#include "EventNames.h" #include "Frame.h" #include "FrameLoaderClient.h" #include "GCController.h" #include "HTMLPlugInElement.h" #include "InspectorInstrumentation.h" +#include "JSDOMBindingSecurity.h" +#include "JSDOMExceptionHandling.h" #include "JSDOMWindow.h" #include "JSDocument.h" #include "JSMainThreadExecState.h" +#include "LoadableModuleScript.h" +#include "MainFrame.h" +#include "MemoryPressureHandler.h" +#include "ModuleFetchFailureKind.h" #include "NP_jsobject.h" #include "Page.h" +#include "PageConsoleClient.h" #include "PageGroup.h" -#include "PluginView.h" -#include "ScriptCallStack.h" +#include "PluginViewBase.h" #include "ScriptSourceCode.h" #include "ScriptableDocumentParser.h" #include "Settings.h" -#include "StorageNamespace.h" #include "UserGestureIndicator.h" #include "WebCoreJSClientData.h" #include "npruntime_impl.h" #include "runtime_root.h" -#include <bindings/ScriptValue.h> #include <debugger/Debugger.h> #include <heap/StrongInlines.h> +#include <inspector/ScriptCallStack.h> #include <runtime/InitializeThreading.h> +#include <runtime/JSFunction.h> +#include <runtime/JSInternalPromise.h> #include <runtime/JSLock.h> +#include <runtime/JSModuleRecord.h> +#include <runtime/JSNativeStdFunction.h> +#include <runtime/JSScriptFetcher.h> +#include <wtf/SetForScope.h> #include <wtf/Threading.h> #include <wtf/text/TextPosition.h> @@ -59,6 +71,18 @@ using namespace JSC; namespace WebCore { +static void collectGarbageAfterWindowShellDestruction() +{ + // Make sure to GC Extra Soon(tm) during memory pressure conditions + // to soften high peaks of memory usage during navigation. + if (MemoryPressureHandler::singleton().isUnderMemoryPressure()) { + // NOTE: We do the collection on next runloop to ensure that there's no pointer + // to the window object on the stack. + GCController::singleton().garbageCollectOnNextRunLoop(); + } else + GCController::singleton().garbageCollectSoon(); +} + void ScriptController::initializeThreading() { #if !PLATFORM(IOS) @@ -74,7 +98,7 @@ ScriptController::ScriptController(Frame& frame) #if ENABLE(NETSCAPE_PLUGIN_API) , m_windowScriptNPObject(0) #endif -#if PLATFORM(MAC) +#if PLATFORM(COCOA) , m_windowScriptObject(0) #endif { @@ -85,16 +109,19 @@ ScriptController::~ScriptController() disconnectPlatformScriptObjects(); if (m_cacheableBindingRootObject) { - JSLockHolder lock(JSDOMWindowBase::commonVM()); + JSLockHolder lock(commonVM()); m_cacheableBindingRootObject->invalidate(); - m_cacheableBindingRootObject = 0; + m_cacheableBindingRootObject = nullptr; } // It's likely that destroying m_windowShells will create a lot of garbage. if (!m_windowShells.isEmpty()) { - while (!m_windowShells.isEmpty()) - destroyWindowShell(*m_windowShells.begin()->key); - gcController().garbageCollectSoon(); + while (!m_windowShells.isEmpty()) { + ShellMap::iterator iter = m_windowShells.begin(); + iter->value->window()->setConsoleClient(nullptr); + destroyWindowShell(*iter->key); + } + collectGarbageAfterWindowShellDestruction(); } } @@ -105,22 +132,24 @@ void ScriptController::destroyWindowShell(DOMWrapperWorld& world) world.didDestroyWindowShell(this); } -JSDOMWindowShell* ScriptController::createWindowShell(DOMWrapperWorld& world) +JSDOMWindowShell& ScriptController::createWindowShell(DOMWrapperWorld& world) { ASSERT(!m_windowShells.contains(&world)); - VM& vm = *world.vm(); + VM& vm = world.vm(); Structure* structure = JSDOMWindowShell::createStructure(vm, jsNull()); Strong<JSDOMWindowShell> windowShell(vm, JSDOMWindowShell::create(vm, m_frame.document()->domWindow(), structure, world)); Strong<JSDOMWindowShell> windowShell2(windowShell); m_windowShells.add(&world, windowShell); world.didCreateWindowShell(this); - return windowShell.get(); + return *windowShell.get(); } -Deprecated::ScriptValue ScriptController::evaluateInWorld(const ScriptSourceCode& sourceCode, DOMWrapperWorld& world) +JSValue ScriptController::evaluateInWorld(const ScriptSourceCode& sourceCode, DOMWrapperWorld& world, ExceptionDetails* exceptionDetails) { + JSLockHolder lock(world.vm()); + const SourceCode& jsSourceCode = sourceCode.jsSourceCode(); String sourceURL = jsSourceCode.provider()->url(); @@ -136,77 +165,178 @@ Deprecated::ScriptValue ScriptController::evaluateInWorld(const ScriptSourceCode const String* savedSourceURL = m_sourceURL; m_sourceURL = &sourceURL; - JSLockHolder lock(exec); - - Ref<Frame> protect(m_frame); - - InspectorInstrumentationCookie cookie = InspectorInstrumentation::willEvaluateScript(&m_frame, sourceURL, sourceCode.startLine()); + Ref<Frame> protector(m_frame); - JSValue evaluationException; + InspectorInstrumentationCookie cookie = InspectorInstrumentation::willEvaluateScript(m_frame, sourceURL, sourceCode.startLine()); - JSValue returnValue = JSMainThreadExecState::evaluate(exec, jsSourceCode, shell, &evaluationException); + NakedPtr<JSC::Exception> evaluationException; + JSValue returnValue = JSMainThreadExecState::profiledEvaluate(exec, JSC::ProfilingReason::Other, jsSourceCode, shell, evaluationException); - InspectorInstrumentation::didEvaluateScript(cookie); + InspectorInstrumentation::didEvaluateScript(cookie, m_frame); if (evaluationException) { - reportException(exec, evaluationException, sourceCode.cachedScript()); + reportException(exec, evaluationException, sourceCode.cachedScript(), exceptionDetails); m_sourceURL = savedSourceURL; - return Deprecated::ScriptValue(); + return { }; } m_sourceURL = savedSourceURL; - return Deprecated::ScriptValue(exec->vm(), returnValue); + return returnValue; +} + +JSValue ScriptController::evaluate(const ScriptSourceCode& sourceCode, ExceptionDetails* exceptionDetails) +{ + return evaluateInWorld(sourceCode, mainThreadNormalWorld(), exceptionDetails); +} + +void ScriptController::loadModuleScriptInWorld(LoadableModuleScript& moduleScript, const String& moduleName, DOMWrapperWorld& world) +{ + JSLockHolder lock(world.vm()); + + auto& shell = *windowShell(world); + auto& state = *shell.window()->globalExec(); + + auto& promise = JSMainThreadExecState::loadModule(state, moduleName, JSC::JSScriptFetcher::create(state.vm(), { &moduleScript })); + setupModuleScriptHandlers(moduleScript, promise, world); +} + +void ScriptController::loadModuleScript(LoadableModuleScript& moduleScript, const String& moduleName) +{ + loadModuleScriptInWorld(moduleScript, moduleName, mainThreadNormalWorld()); +} + +void ScriptController::loadModuleScriptInWorld(LoadableModuleScript& moduleScript, const ScriptSourceCode& sourceCode, DOMWrapperWorld& world) +{ + JSLockHolder lock(world.vm()); + + auto& shell = *windowShell(world); + auto& state = *shell.window()->globalExec(); + + auto& promise = JSMainThreadExecState::loadModule(state, sourceCode.jsSourceCode(), JSC::JSScriptFetcher::create(state.vm(), { &moduleScript })); + setupModuleScriptHandlers(moduleScript, promise, world); +} + +void ScriptController::loadModuleScript(LoadableModuleScript& moduleScript, const ScriptSourceCode& sourceCode) +{ + loadModuleScriptInWorld(moduleScript, sourceCode, mainThreadNormalWorld()); +} + +JSC::JSValue ScriptController::linkAndEvaluateModuleScriptInWorld(LoadableModuleScript& moduleScript, DOMWrapperWorld& world) +{ + JSLockHolder lock(world.vm()); + + auto& shell = *windowShell(world); + auto& state = *shell.window()->globalExec(); + + // FIXME: Preventing Frame from being destroyed is essentially unnecessary. + // https://bugs.webkit.org/show_bug.cgi?id=164763 + Ref<Frame> protector(m_frame); + + NakedPtr<JSC::Exception> evaluationException; + auto returnValue = JSMainThreadExecState::linkAndEvaluateModule(state, Identifier::fromUid(&state.vm(), moduleScript.moduleKey()), jsUndefined(), evaluationException); + if (evaluationException) { + // FIXME: Give a chance to dump the stack trace if the "crossorigin" attribute allows. + // https://bugs.webkit.org/show_bug.cgi?id=164539 + reportException(&state, evaluationException, nullptr); + return jsUndefined(); + } + return returnValue; +} + +JSC::JSValue ScriptController::linkAndEvaluateModuleScript(LoadableModuleScript& moduleScript) +{ + return linkAndEvaluateModuleScriptInWorld(moduleScript, mainThreadNormalWorld()); +} + +JSC::JSValue ScriptController::evaluateModule(const URL& sourceURL, JSModuleRecord& moduleRecord, DOMWrapperWorld& world) +{ + JSLockHolder lock(world.vm()); + + const auto& jsSourceCode = moduleRecord.sourceCode(); + + auto& shell = *windowShell(world); + auto& state = *shell.window()->globalExec(); + SetForScope<const String*> sourceURLScope(m_sourceURL, &sourceURL.string()); + + Ref<Frame> protector(m_frame); + + auto cookie = InspectorInstrumentation::willEvaluateScript(m_frame, sourceURL, jsSourceCode.firstLine().oneBasedInt()); + + auto returnValue = moduleRecord.evaluate(&state); + InspectorInstrumentation::didEvaluateScript(cookie, m_frame); + + return returnValue; +} + +JSC::JSValue ScriptController::evaluateModule(const URL& sourceURL, JSModuleRecord& moduleRecord) +{ + return evaluateModule(sourceURL, moduleRecord, mainThreadNormalWorld()); } -Deprecated::ScriptValue ScriptController::evaluate(const ScriptSourceCode& sourceCode) +Ref<DOMWrapperWorld> ScriptController::createWorld() { - return evaluateInWorld(sourceCode, mainThreadNormalWorld()); + return DOMWrapperWorld::create(commonVM()); } -PassRefPtr<DOMWrapperWorld> ScriptController::createWorld() +Vector<JSC::Strong<JSDOMWindowShell>> ScriptController::windowShells() { - return DOMWrapperWorld::create(JSDOMWindow::commonVM()); + Vector<JSC::Strong<JSDOMWindowShell>> windowShells; + copyValuesToVector(m_windowShells, windowShells); + return windowShells; } void ScriptController::getAllWorlds(Vector<Ref<DOMWrapperWorld>>& worlds) { - static_cast<WebCoreJSClientData*>(JSDOMWindow::commonVM()->clientData)->getAllWorlds(worlds); + static_cast<JSVMClientData*>(commonVM().clientData)->getAllWorlds(worlds); } -void ScriptController::clearWindowShell(DOMWindow* newDOMWindow, bool goingIntoPageCache) +void ScriptController::clearWindowShellsNotMatchingDOMWindow(DOMWindow* newDOMWindow, bool goingIntoPageCache) { if (m_windowShells.isEmpty()) return; - JSLockHolder lock(JSDOMWindowBase::commonVM()); + JSLockHolder lock(commonVM()); - for (ShellMap::iterator iter = m_windowShells.begin(); iter != m_windowShells.end(); ++iter) { - JSDOMWindowShell* windowShell = iter->value.get(); - - if (&windowShell->window()->impl() == newDOMWindow) + for (auto& windowShell : windowShells()) { + if (&windowShell->window()->wrapped() == newDOMWindow) continue; - // Clear the debugger from the current window before setting the new window. - attachDebugger(windowShell, 0); - + // Clear the debugger and console from the current window before setting the new window. + attachDebugger(windowShell.get(), nullptr); + windowShell->window()->setConsoleClient(nullptr); windowShell->window()->willRemoveFromWindowShell(); - windowShell->setWindow(newDOMWindow); + } + // It's likely that resetting our windows created a lot of garbage, unless + // it went in a back/forward cache. + if (!goingIntoPageCache) + collectGarbageAfterWindowShellDestruction(); +} + +void ScriptController::setDOMWindowForWindowShell(DOMWindow* newDOMWindow) +{ + if (m_windowShells.isEmpty()) + return; + + JSLockHolder lock(commonVM()); + + for (auto& windowShell : windowShells()) { + if (&windowShell->window()->wrapped() == newDOMWindow) + continue; + + windowShell->setWindow(newDOMWindow); + // An m_cacheableBindingRootObject persists between page navigations // so needs to know about the new JSDOMWindow. if (m_cacheableBindingRootObject) m_cacheableBindingRootObject->updateGlobalObject(windowShell->window()); if (Page* page = m_frame.page()) { - attachDebugger(windowShell, page->debugger()); + attachDebugger(windowShell.get(), page->debugger()); windowShell->window()->setProfileGroup(page->group().identifier()); + windowShell->window()->setConsoleClient(&page->console()); } } - - // It's likely that resetting our windows created a lot of garbage, unless - // it went in a back/forward cache. - if (!goingIntoPageCache) - gcController().garbageCollectSoon(); } JSDOMWindowShell* ScriptController::initScript(DOMWrapperWorld& world) @@ -215,29 +345,97 @@ JSDOMWindowShell* ScriptController::initScript(DOMWrapperWorld& world) JSLockHolder lock(world.vm()); - JSDOMWindowShell* windowShell = createWindowShell(world); + JSDOMWindowShell& windowShell = createWindowShell(world); - windowShell->window()->updateDocument(); + windowShell.window()->updateDocument(); - if (m_frame.document()) - windowShell->window()->setEvalEnabled(m_frame.document()->contentSecurityPolicy()->allowEval(0, ContentSecurityPolicy::SuppressReport), m_frame.document()->contentSecurityPolicy()->evalDisabledErrorMessage()); + if (Document* document = m_frame.document()) + document->contentSecurityPolicy()->didCreateWindowShell(windowShell); if (Page* page = m_frame.page()) { - attachDebugger(windowShell, page->debugger()); - windowShell->window()->setProfileGroup(page->group().identifier()); + attachDebugger(&windowShell, page->debugger()); + windowShell.window()->setProfileGroup(page->group().identifier()); + windowShell.window()->setConsoleClient(&page->console()); } m_frame.loader().dispatchDidClearWindowObjectInWorld(world); - return windowShell; + return &windowShell; +} + +static Identifier jsValueToModuleKey(ExecState* exec, JSValue value) +{ + if (value.isSymbol()) + return Identifier::fromUid(jsCast<Symbol*>(value)->privateName()); + ASSERT(value.isString()); + return asString(value)->toIdentifier(exec); +} + +void ScriptController::setupModuleScriptHandlers(LoadableModuleScript& moduleScriptRef, JSInternalPromise& promise, DOMWrapperWorld& world) +{ + auto& shell = *windowShell(world); + auto& state = *shell.window()->globalExec(); + + // It is not guaranteed that either fulfillHandler or rejectHandler is eventually called. + // For example, if the page load is canceled, the DeferredPromise used in the module loader pipeline will stop executing JS code. + // Thus the promise returned from this function could remain unresolved. + + RefPtr<LoadableModuleScript> moduleScript(&moduleScriptRef); + + auto& fulfillHandler = *JSNativeStdFunction::create(state.vm(), shell.window(), 1, String(), [moduleScript](ExecState* exec) { + Identifier moduleKey = jsValueToModuleKey(exec, exec->argument(0)); + moduleScript->notifyLoadCompleted(*moduleKey.impl()); + return JSValue::encode(jsUndefined()); + }); + + auto& rejectHandler = *JSNativeStdFunction::create(state.vm(), shell.window(), 1, String(), [moduleScript](ExecState* exec) { + VM& vm = exec->vm(); + JSValue errorValue = exec->argument(0); + if (errorValue.isObject()) { + auto* object = JSC::asObject(errorValue); + if (JSValue failureKindValue = object->getDirect(vm, static_cast<JSVMClientData&>(*vm.clientData).builtinNames().failureKindPrivateName())) { + // This is host propagated error in the module loader pipeline. + switch (static_cast<ModuleFetchFailureKind>(failureKindValue.asInt32())) { + case ModuleFetchFailureKind::WasErrored: + moduleScript->notifyLoadFailed(LoadableScript::Error { + LoadableScript::ErrorType::CachedScript, + std::nullopt + }); + break; + case ModuleFetchFailureKind::WasCanceled: + moduleScript->notifyLoadWasCanceled(); + break; + } + return JSValue::encode(jsUndefined()); + } + } + + auto scope = DECLARE_CATCH_SCOPE(vm); + moduleScript->notifyLoadFailed(LoadableScript::Error { + LoadableScript::ErrorType::CachedScript, + LoadableScript::ConsoleMessage { + MessageSource::JS, + MessageLevel::Error, + retrieveErrorMessage(*exec, vm, errorValue, scope), + } + }); + return JSValue::encode(jsUndefined()); + }); + + promise.then(&state, &fulfillHandler, &rejectHandler); } TextPosition ScriptController::eventHandlerPosition() const { + // FIXME: If we are not currently parsing, we should use our current location + // in JavaScript, to cover cases like "element.setAttribute('click', ...)". + + // FIXME: This location maps to the end of the HTML tag, and not to the + // exact column number belonging to the event handler attribute. ScriptableDocumentParser* parser = m_frame.document()->scriptableDocumentParser(); if (parser) return parser->textPosition(); - return TextPosition::minimumPosition(); + return TextPosition(); } void ScriptController::enableEval() @@ -261,20 +459,27 @@ bool ScriptController::processingUserGesture() return UserGestureIndicator::processingUserGesture(); } -bool ScriptController::canAccessFromCurrentOrigin(Frame *frame) +bool ScriptController::processingUserGestureForMedia() { - ExecState* exec = JSMainThreadExecState::currentState(); - if (exec) - return shouldAllowAccessToFrame(exec, frame); - // If the current state is 0 we're in a call path where the DOM security - // check doesn't apply (eg. parser). - return true; + return UserGestureIndicator::processingUserGestureForMedia(); +} + +bool ScriptController::canAccessFromCurrentOrigin(Frame* frame) +{ + ExecState* state = JSMainThreadExecState::currentState(); + + // If the current state is null we're in a call path where the DOM security check doesn't apply (eg. parser). + if (!state) + return true; + + return BindingSecurity::shouldAllowAccessToFrame(state, frame); } void ScriptController::attachDebugger(JSC::Debugger* debugger) { - for (ShellMap::iterator iter = m_windowShells.begin(); iter != m_windowShells.end(); ++iter) - attachDebugger(iter->value.get(), debugger); + Vector<JSC::Strong<JSDOMWindowShell>> windowShells = this->windowShells(); + for (size_t i = 0; i < windowShells.size(); ++i) + attachDebugger(windowShells[i].get(), debugger); } void ScriptController::attachDebugger(JSDOMWindowShell* shell, JSC::Debugger* debugger) @@ -283,6 +488,7 @@ void ScriptController::attachDebugger(JSDOMWindowShell* shell, JSC::Debugger* de return; JSDOMWindow* globalObject = shell->window(); + JSLockHolder lock(globalObject->vm()); if (debugger) debugger->attach(globalObject); else if (JSC::Debugger* currentDebugger = globalObject->debugger()) @@ -291,9 +497,11 @@ void ScriptController::attachDebugger(JSDOMWindowShell* shell, JSC::Debugger* de void ScriptController::updateDocument() { - for (ShellMap::iterator iter = m_windowShells.begin(); iter != m_windowShells.end(); ++iter) { - JSLockHolder lock(iter->key->vm()); - iter->value->window()->updateDocument(); + Vector<JSC::Strong<JSDOMWindowShell>> windowShells = this->windowShells(); + for (size_t i = 0; i < windowShells.size(); ++i) { + JSDOMWindowShell* windowShell = windowShells[i].get(); + JSLockHolder lock(windowShell->world().vm()); + windowShell->window()->updateDocument(); } } @@ -303,7 +511,7 @@ Bindings::RootObject* ScriptController::cacheableBindingRootObject() return 0; if (!m_cacheableBindingRootObject) { - JSLockHolder lock(JSDOMWindowBase::commonVM()); + JSLockHolder lock(commonVM()); m_cacheableBindingRootObject = Bindings::RootObject::create(0, globalObject(pluginWorld())); } return m_cacheableBindingRootObject.get(); @@ -315,13 +523,13 @@ Bindings::RootObject* ScriptController::bindingRootObject() return 0; if (!m_bindingRootObject) { - JSLockHolder lock(JSDOMWindowBase::commonVM()); + JSLockHolder lock(commonVM()); m_bindingRootObject = Bindings::RootObject::create(0, globalObject(pluginWorld())); } return m_bindingRootObject.get(); } -PassRefPtr<Bindings::RootObject> ScriptController::createRootObject(void* nativeHandle) +RefPtr<Bindings::RootObject> ScriptController::createRootObject(void* nativeHandle) { RootObjectMap::iterator it = m_rootObjects.find(nativeHandle); if (it != m_rootObjects.end()) @@ -330,36 +538,28 @@ PassRefPtr<Bindings::RootObject> ScriptController::createRootObject(void* native RefPtr<Bindings::RootObject> rootObject = Bindings::RootObject::create(nativeHandle, globalObject(pluginWorld())); m_rootObjects.set(nativeHandle, rootObject); - return rootObject.release(); -} - -#if ENABLE(INSPECTOR) -void ScriptController::setCaptureCallStackForUncaughtExceptions(bool) -{ + return rootObject; } void ScriptController::collectIsolatedContexts(Vector<std::pair<JSC::ExecState*, SecurityOrigin*>>& result) { for (ShellMap::iterator iter = m_windowShells.begin(); iter != m_windowShells.end(); ++iter) { JSC::ExecState* exec = iter->value->window()->globalExec(); - SecurityOrigin* origin = iter->value->window()->impl().document()->securityOrigin(); + SecurityOrigin* origin = &iter->value->window()->wrapped().document()->securityOrigin(); result.append(std::pair<JSC::ExecState*, SecurityOrigin*>(exec, origin)); } } -#endif - #if ENABLE(NETSCAPE_PLUGIN_API) - NPObject* ScriptController::windowScriptNPObject() { if (!m_windowScriptNPObject) { + JSLockHolder lock(commonVM()); if (canExecuteScripts(NotAboutToExecuteScript)) { // JavaScript is enabled, so there is a JavaScript window object. // Return an NPObject bound to the window object. JSDOMWindow* win = windowShell(pluginWorld())->window(); ASSERT(win); - JSC::JSLockHolder lock(win->globalExec()); Bindings::RootObject* root = bindingRootObject(); m_windowScriptNPObject = _NPN_CreateScriptObject(0, win, root); } else { @@ -371,26 +571,15 @@ NPObject* ScriptController::windowScriptNPObject() return m_windowScriptNPObject; } - -NPObject* ScriptController::createScriptObjectForPluginElement(HTMLPlugInElement* plugin) -{ - JSObject* object = jsObjectForPluginElement(plugin); - if (!object) - return _NPN_CreateNoScriptObject(); - - // Wrap the JSObject in an NPObject - return _NPN_CreateScriptObject(0, object, bindingRootObject()); -} - #endif -#if !PLATFORM(MAC) -PassRefPtr<JSC::Bindings::Instance> ScriptController::createScriptInstanceForWidget(Widget* widget) +#if !PLATFORM(COCOA) +RefPtr<JSC::Bindings::Instance> ScriptController::createScriptInstanceForWidget(Widget* widget) { - if (!widget->isPluginView()) - return 0; + if (!is<PluginViewBase>(*widget)) + return nullptr; - return toPluginView(widget)->bindingInstance(); + return downcast<PluginViewBase>(*widget).bindingInstance(); } #endif @@ -400,9 +589,10 @@ JSObject* ScriptController::jsObjectForPluginElement(HTMLPlugInElement* plugin) if (!canExecuteScripts(NotAboutToExecuteScript)) return 0; + JSLockHolder lock(commonVM()); + // Create a JSObject bound to this element JSDOMWindow* globalObj = globalObject(pluginWorld()); - JSLockHolder lock(globalObj->globalExec()); // FIXME: is normal okay? - used for NP plugins? JSValue jsElementValue = toJS(globalObj->globalExec(), globalObj, plugin); if (!jsElementValue || !jsElementValue.isObject()) @@ -411,7 +601,7 @@ JSObject* ScriptController::jsObjectForPluginElement(HTMLPlugInElement* plugin) return jsElementValue.getObject(); } -#if !PLATFORM(MAC) +#if !PLATFORM(COCOA) void ScriptController::updatePlatformScriptObjects() { @@ -436,7 +626,7 @@ void ScriptController::cleanupScriptObjectsForPlugin(void* nativeHandle) void ScriptController::clearScriptObjects() { - JSLockHolder lock(JSDOMWindowBase::commonVM()); + JSLockHolder lock(commonVM()); RootObjectMap::const_iterator end = m_rootObjects.end(); for (RootObjectMap::const_iterator it = m_rootObjects.begin(); it != end; ++it) @@ -446,7 +636,7 @@ void ScriptController::clearScriptObjects() if (m_bindingRootObject) { m_bindingRootObject->invalidate(); - m_bindingRootObject = 0; + m_bindingRootObject = nullptr; } #if ENABLE(NETSCAPE_PLUGIN_API) @@ -455,67 +645,53 @@ void ScriptController::clearScriptObjects() // script object properly. // This shouldn't cause any problems for plugins since they should have already been stopped and destroyed at this point. _NPN_DeallocateObject(m_windowScriptNPObject); - m_windowScriptNPObject = 0; + m_windowScriptNPObject = nullptr; } #endif } -Deprecated::ScriptValue ScriptController::executeScriptInWorld(DOMWrapperWorld& world, const String& script, bool forceUserGesture) +JSValue ScriptController::executeScriptInWorld(DOMWrapperWorld& world, const String& script, bool forceUserGesture) { - UserGestureIndicator gestureIndicator(forceUserGesture ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture); - ScriptSourceCode sourceCode(script, m_frame.document()->url()); + UserGestureIndicator gestureIndicator(forceUserGesture ? std::optional<ProcessingUserGestureState>(ProcessingUserGesture) : std::nullopt); + ScriptSourceCode sourceCode(script, m_frame.document()->url(), TextPosition(), JSC::SourceProviderSourceType::Program, CachedScriptFetcher::create(m_frame.document()->charset())); if (!canExecuteScripts(AboutToExecuteScript) || isPaused()) - return Deprecated::ScriptValue(); + return { }; return evaluateInWorld(sourceCode, world); } -bool ScriptController::shouldBypassMainWorldContentSecurityPolicy() -{ - CallFrame* callFrame = JSDOMWindow::commonVM()->topCallFrame; - if (callFrame == CallFrame::noCaller()) - return false; - DOMWrapperWorld& domWrapperWorld = currentWorld(callFrame); - if (domWrapperWorld.isNormal()) - return false; - return true; -} - bool ScriptController::canExecuteScripts(ReasonForCallingCanExecuteScripts reason) { if (m_frame.document() && m_frame.document()->isSandboxed(SandboxScripts)) { // FIXME: This message should be moved off the console once a solution to https://bugs.webkit.org/show_bug.cgi?id=103274 exists. if (reason == AboutToExecuteScript) - m_frame.document()->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Blocked script execution in '" + m_frame.document()->url().stringCenterEllipsizedToLength() + "' because the document's frame is sandboxed and the 'allow-scripts' permission is not set."); + m_frame.document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, "Blocked script execution in '" + m_frame.document()->url().stringCenterEllipsizedToLength() + "' because the document's frame is sandboxed and the 'allow-scripts' permission is not set."); return false; } - if (m_frame.document() && m_frame.document()->isViewSource()) { - ASSERT(m_frame.document()->securityOrigin()->isUnique()); - return true; - } - if (!m_frame.page()) return false; return m_frame.loader().client().allowScript(m_frame.settings().isScriptEnabled()); } -Deprecated::ScriptValue ScriptController::executeScript(const String& script, bool forceUserGesture) +JSValue ScriptController::executeScript(const String& script, bool forceUserGesture, ExceptionDetails* exceptionDetails) { - UserGestureIndicator gestureIndicator(forceUserGesture ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture); - return executeScript(ScriptSourceCode(script, m_frame.document()->url())); + UserGestureIndicator gestureIndicator(forceUserGesture ? std::optional<ProcessingUserGestureState>(ProcessingUserGesture) : std::nullopt); + return executeScript(ScriptSourceCode(script, m_frame.document()->url(), TextPosition(), JSC::SourceProviderSourceType::Program, CachedScriptFetcher::create(m_frame.document()->charset())), exceptionDetails); } -Deprecated::ScriptValue ScriptController::executeScript(const ScriptSourceCode& sourceCode) +JSValue ScriptController::executeScript(const ScriptSourceCode& sourceCode, ExceptionDetails* exceptionDetails) { if (!canExecuteScripts(AboutToExecuteScript) || isPaused()) - return Deprecated::ScriptValue(); + return { }; // FIXME: Would jsNull be better? - Ref<Frame> protect(m_frame); // Script execution can destroy the frame, and thus the ScriptController. + // FIXME: Preventing Frame from being destroyed is essentially unnecessary. + // https://bugs.webkit.org/show_bug.cgi?id=164763 + Ref<Frame> protector(m_frame); // Script execution can destroy the frame, and thus the ScriptController. - return evaluate(sourceCode); + return evaluate(sourceCode, exceptionDetails); } bool ScriptController::executeIfJavaScriptURL(const URL& url, ShouldReplaceDocumentIfJavaScriptURL shouldReplaceDocumentIfJavaScriptURL) @@ -534,7 +710,7 @@ bool ScriptController::executeIfJavaScriptURL(const URL& url, ShouldReplaceDocum const int javascriptSchemeLength = sizeof("javascript:") - 1; String decodedURL = decodeURLEscapeSequences(url.string()); - Deprecated::ScriptValue result = executeScript(decodedURL.substring(javascriptSchemeLength)); + auto result = executeScript(decodedURL.substring(javascriptSchemeLength)); // If executing script caused this frame to be removed from the page, we // don't want to try to replace its document! @@ -542,9 +718,7 @@ bool ScriptController::executeIfJavaScriptURL(const URL& url, ShouldReplaceDocum return true; String scriptResult; - JSDOMWindowShell* shell = windowShell(mainThreadNormalWorld()); - JSC::ExecState* exec = shell->window()->globalExec(); - if (!result.getString(exec, scriptResult)) + if (!result || !result.getString(windowShell(mainThreadNormalWorld())->window()->globalExec(), scriptResult)) return true; // FIXME: We should always replace the document, but doing so diff --git a/Source/WebCore/bindings/js/ScriptController.h b/Source/WebCore/bindings/js/ScriptController.h index 67e96ec3c..58fd49da8 100644 --- a/Source/WebCore/bindings/js/ScriptController.h +++ b/Source/WebCore/bindings/js/ScriptController.h @@ -1,7 +1,7 @@ /* * Copyright (C) 1999 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008-2016 Apple Inc. All rights reserved. * Copyright (C) 2008 Eric Seidel <eric@webkit.org> * * This library is free software; you can redistribute it and/or @@ -19,8 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef ScriptController_h -#define ScriptController_h +#pragma once #include "FrameLoaderTypes.h" #include "JSDOMWindowShell.h" @@ -30,37 +29,40 @@ #include <wtf/RefPtr.h> #include <wtf/text/TextPosition.h> -#if PLATFORM(MAC) +#if PLATFORM(COCOA) #include <wtf/RetainPtr.h> -OBJC_CLASS WebScriptObject; OBJC_CLASS JSContext; +OBJC_CLASS WebScriptObject; #endif struct NPObject; -namespace Deprecated { -class ScriptValue; -} - namespace JSC { - class JSGlobalObject; - class ExecState; - - namespace Bindings { - class Instance; - class RootObject; - } +class ExecState; +class JSGlobalObject; +class JSInternalPromise; +class JSModuleRecord; + +namespace Bindings { +class Instance; +class RootObject; +} } namespace WebCore { -class HTMLPlugInElement; +class CachedScriptFetcher; class Frame; +class HTMLDocument; +class HTMLPlugInElement; +class LoadableModuleScript; class ScriptSourceCode; class SecurityOrigin; +class URL; class Widget; +struct ExceptionDetails; -typedef HashMap<void*, RefPtr<JSC::Bindings::RootObject>> RootObjectMap; +using RootObjectMap = HashMap<void*, RefPtr<JSC::Bindings::RootObject>>; enum ReasonForCallingCanExecuteScripts { AboutToExecuteScript, @@ -68,18 +70,21 @@ enum ReasonForCallingCanExecuteScripts { }; class ScriptController { - friend class ScriptCachedFrameData; + WTF_MAKE_FAST_ALLOCATED; + typedef HashMap<RefPtr<DOMWrapperWorld>, JSC::Strong<JSDOMWindowShell>> ShellMap; public: explicit ScriptController(Frame&); ~ScriptController(); - static PassRefPtr<DOMWrapperWorld> createWorld(); + WEBCORE_EXPORT static Ref<DOMWrapperWorld> createWorld(); - JSDOMWindowShell* createWindowShell(DOMWrapperWorld&); + JSDOMWindowShell& createWindowShell(DOMWrapperWorld&); void destroyWindowShell(DOMWrapperWorld&); + Vector<JSC::Strong<JSDOMWindowShell>> windowShells(); + JSDOMWindowShell* windowShell(DOMWrapperWorld& world) { ShellMap::iterator iter = m_windowShells.find(&world); @@ -97,9 +102,9 @@ public: static void getAllWorlds(Vector<Ref<DOMWrapperWorld>>&); - Deprecated::ScriptValue executeScript(const ScriptSourceCode&); - Deprecated::ScriptValue executeScript(const String& script, bool forceUserGesture = false); - Deprecated::ScriptValue executeScriptInWorld(DOMWrapperWorld&, const String& script, bool forceUserGesture = false); + JSC::JSValue executeScript(const ScriptSourceCode&, ExceptionDetails* = nullptr); + WEBCORE_EXPORT JSC::JSValue executeScript(const String& script, bool forceUserGesture = false, ExceptionDetails* = nullptr); + WEBCORE_EXPORT JSC::JSValue executeScriptInWorld(DOMWrapperWorld&, const String& script, bool forceUserGesture = false); // Returns true if argument is a JavaScript URL. bool executeIfJavaScriptURL(const URL&, ShouldReplaceDocumentIfJavaScriptURL shouldReplaceDocumentIfJavaScriptURL = ReplaceDocumentIfJavaScriptURL); @@ -108,18 +113,30 @@ public: // Darwin is an exception to this rule: it is OK to call this function from any thread, even reentrantly. static void initializeThreading(); - Deprecated::ScriptValue evaluate(const ScriptSourceCode&); - Deprecated::ScriptValue evaluateInWorld(const ScriptSourceCode&, DOMWrapperWorld&); + JSC::JSValue evaluate(const ScriptSourceCode&, ExceptionDetails* = nullptr); + JSC::JSValue evaluateInWorld(const ScriptSourceCode&, DOMWrapperWorld&, ExceptionDetails* = nullptr); + + void loadModuleScriptInWorld(LoadableModuleScript&, const String& moduleName, DOMWrapperWorld&); + void loadModuleScript(LoadableModuleScript&, const String& moduleName); + void loadModuleScriptInWorld(LoadableModuleScript&, const ScriptSourceCode&, DOMWrapperWorld&); + void loadModuleScript(LoadableModuleScript&, const ScriptSourceCode&); + + JSC::JSValue linkAndEvaluateModuleScriptInWorld(LoadableModuleScript& , DOMWrapperWorld&); + JSC::JSValue linkAndEvaluateModuleScript(LoadableModuleScript&); + + JSC::JSValue evaluateModule(const URL&, JSC::JSModuleRecord&, DOMWrapperWorld&); + JSC::JSValue evaluateModule(const URL&, JSC::JSModuleRecord&); WTF::TextPosition eventHandlerPosition() const; void enableEval(); void disableEval(const String& errorMessage); - static bool processingUserGesture(); + WEBCORE_EXPORT static bool processingUserGesture(); + WEBCORE_EXPORT static bool processingUserGestureForMedia(); static bool canAccessFromCurrentOrigin(Frame*); - bool canExecuteScripts(ReasonForCallingCanExecuteScripts); + WEBCORE_EXPORT bool canExecuteScripts(ReasonForCallingCanExecuteScripts); // Debugger can be 0 to detach any existing Debugger. void attachDebugger(JSC::Debugger*); // Attaches/detaches in all worlds/window shells. @@ -130,44 +147,40 @@ public: const String* sourceURL() const { return m_sourceURL; } // 0 if we are not evaluating any script - void clearWindowShell(DOMWindow* newDOMWindow, bool goingIntoPageCache); + void clearWindowShellsNotMatchingDOMWindow(DOMWindow*, bool goingIntoPageCache); + void setDOMWindowForWindowShell(DOMWindow*); void updateDocument(); void namedItemAdded(HTMLDocument*, const AtomicString&) { } void namedItemRemoved(HTMLDocument*, const AtomicString&) { } void clearScriptObjects(); - void cleanupScriptObjectsForPlugin(void*); + WEBCORE_EXPORT void cleanupScriptObjectsForPlugin(void*); void updatePlatformScriptObjects(); - PassRefPtr<JSC::Bindings::Instance> createScriptInstanceForWidget(Widget*); - JSC::Bindings::RootObject* bindingRootObject(); + RefPtr<JSC::Bindings::Instance> createScriptInstanceForWidget(Widget*); + WEBCORE_EXPORT JSC::Bindings::RootObject* bindingRootObject(); JSC::Bindings::RootObject* cacheableBindingRootObject(); - PassRefPtr<JSC::Bindings::RootObject> createRootObject(void* nativeHandle); + WEBCORE_EXPORT RefPtr<JSC::Bindings::RootObject> createRootObject(void* nativeHandle); -#if ENABLE(INSPECTOR) - static void setCaptureCallStackForUncaughtExceptions(bool); void collectIsolatedContexts(Vector<std::pair<JSC::ExecState*, SecurityOrigin*>>&); -#endif -#if PLATFORM(MAC) - WebScriptObject* windowScriptObject(); - JSContext *javaScriptContext(); +#if PLATFORM(COCOA) + WEBCORE_EXPORT WebScriptObject* windowScriptObject(); + WEBCORE_EXPORT JSContext *javaScriptContext(); #endif - JSC::JSObject* jsObjectForPluginElement(HTMLPlugInElement*); + WEBCORE_EXPORT JSC::JSObject* jsObjectForPluginElement(HTMLPlugInElement*); #if ENABLE(NETSCAPE_PLUGIN_API) - NPObject* createScriptObjectForPluginElement(HTMLPlugInElement*); - NPObject* windowScriptNPObject(); + WEBCORE_EXPORT NPObject* windowScriptNPObject(); #endif - bool shouldBypassMainWorldContentSecurityPolicy(); - private: - JSDOMWindowShell* initScript(DOMWrapperWorld&); + WEBCORE_EXPORT JSDOMWindowShell* initScript(DOMWrapperWorld&); + void setupModuleScriptHandlers(LoadableModuleScript&, JSC::JSInternalPromise&, DOMWrapperWorld&); void disconnectPlatformScriptObjects(); @@ -188,11 +201,9 @@ private: #if ENABLE(NETSCAPE_PLUGIN_API) NPObject* m_windowScriptNPObject; #endif -#if PLATFORM(MAC) +#if PLATFORM(COCOA) RetainPtr<WebScriptObject> m_windowScriptObject; #endif }; } // namespace WebCore - -#endif // ScriptController_h diff --git a/Source/WebCore/bindings/js/ScriptGlobalObject.cpp b/Source/WebCore/bindings/js/ScriptGlobalObject.cpp index a8b5a620f..2275ff939 100644 --- a/Source/WebCore/bindings/js/ScriptGlobalObject.cpp +++ b/Source/WebCore/bindings/js/ScriptGlobalObject.cpp @@ -31,63 +31,38 @@ #include "config.h" #include "ScriptGlobalObject.h" -#include "JSDOMBinding.h" -#include <bindings/ScriptObject.h> -#include <runtime/JSLock.h> - -#if ENABLE(INSPECTOR) +#include "JSDOMConvert.h" +#include "JSDOMExceptionHandling.h" #include "JSInspectorFrontendHost.h" -#endif +#include <runtime/IdentifierInlines.h> using namespace JSC; namespace WebCore { -static bool handleException(JSC::ExecState* scriptState) -{ - if (!scriptState->hadException()) - return true; - - reportException(scriptState, scriptState->exception()); - return false; -} - -bool ScriptGlobalObject::set(JSC::ExecState* scriptState, const char* name, const Deprecated::ScriptObject& value) -{ - JSLockHolder lock(scriptState); - scriptState->lexicalGlobalObject()->putDirect(scriptState->vm(), Identifier(scriptState, name), value.jsObject()); - return handleException(scriptState); -} - -#if ENABLE(INSPECTOR) -bool ScriptGlobalObject::set(JSC::ExecState* scriptState, const char* name, InspectorFrontendHost* value) +bool ScriptGlobalObject::set(ExecState& scriptState, const char* name, InspectorFrontendHost& value) { - JSLockHolder lock(scriptState); - JSDOMGlobalObject* globalObject = jsCast<JSDOMGlobalObject*>(scriptState->lexicalGlobalObject()); - globalObject->putDirect(scriptState->vm(), Identifier(scriptState, name), toJS(scriptState, globalObject, value)); - return handleException(scriptState); -} -#endif // ENABLE(INSPECTOR) - -bool ScriptGlobalObject::get(JSC::ExecState* scriptState, const char* name, Deprecated::ScriptObject& value) -{ - JSLockHolder lock(scriptState); - JSValue jsValue = scriptState->lexicalGlobalObject()->get(scriptState, Identifier(scriptState, name)); - if (!jsValue) - return false; - - if (!jsValue.isObject()) + auto& vm = scriptState.vm(); + JSLockHolder lock(vm); + auto scope = DECLARE_CATCH_SCOPE(vm); + auto& globalObject = *jsCast<JSDOMGlobalObject*>(scriptState.lexicalGlobalObject()); + globalObject.putDirect(vm, Identifier::fromString(&vm, name), toJS<IDLInterface<InspectorFrontendHost>>(scriptState, globalObject, value)); + if (UNLIKELY(scope.exception())) { + reportException(&scriptState, scope.exception()); return false; - - value = Deprecated::ScriptObject(scriptState, asObject(jsValue)); + } return true; } -bool ScriptGlobalObject::remove(JSC::ExecState* scriptState, const char* name) +bool ScriptGlobalObject::get(ExecState& scriptState, const char* name, JSObject*& object) { - JSLockHolder lock(scriptState); - scriptState->lexicalGlobalObject()->methodTable()->deleteProperty(scriptState->lexicalGlobalObject(), scriptState, Identifier(scriptState, name)); - return handleException(scriptState); + auto& vm = scriptState.vm(); + JSLockHolder lock(vm); + JSValue value = scriptState.lexicalGlobalObject()->get(&scriptState, Identifier::fromString(&vm, name)); + if (!value || !value.isObject()) + return false; + object = asObject(value); + return true; } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/ScriptGlobalObject.h b/Source/WebCore/bindings/js/ScriptGlobalObject.h index 8aa055bd6..f879a025d 100644 --- a/Source/WebCore/bindings/js/ScriptGlobalObject.h +++ b/Source/WebCore/bindings/js/ScriptGlobalObject.h @@ -28,15 +28,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ScriptGlobalObject_h -#define ScriptGlobalObject_h - -namespace Deprecated { -class ScriptObject; -} +#pragma once namespace JSC { class ExecState; +class JSObject; } namespace WebCore { @@ -45,17 +41,11 @@ class InspectorFrontendHost; class ScriptGlobalObject { public: - static bool set(JSC::ExecState*, const char* name, const Deprecated::ScriptObject&); -#if ENABLE(INSPECTOR) - static bool set(JSC::ExecState*, const char* name, InspectorFrontendHost*); -#endif + WEBCORE_EXPORT static bool set(JSC::ExecState&, const char* name, InspectorFrontendHost&); + static bool get(JSC::ExecState&, const char* name, JSC::JSObject*&); - static bool get(JSC::ExecState*, const char* name, Deprecated::ScriptObject&); - static bool remove(JSC::ExecState*, const char* name); private: - ScriptGlobalObject() { } + ScriptGlobalObject() = delete; }; } // namespace WebCore - -#endif // ScriptGlobalObject_h diff --git a/Source/WebCore/bindings/js/ScriptHeapSnapshot.h b/Source/WebCore/bindings/js/ScriptHeapSnapshot.h deleted file mode 100644 index 5269ff925..000000000 --- a/Source/WebCore/bindings/js/ScriptHeapSnapshot.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2010, Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef ScriptHeapSnapshot_h -#define ScriptHeapSnapshot_h - -#include <wtf/RefCounted.h> -#include <wtf/text/WTFString.h> - -namespace WebCore { - -typedef uint32_t SnapshotObjectId; - -class ScriptHeapSnapshot : public RefCounted<ScriptHeapSnapshot> { -public: - class OutputStream { - public: - virtual ~OutputStream() { } - virtual void Write(const String& chunk) = 0; - virtual void Close() = 0; - }; - - virtual ~ScriptHeapSnapshot() { } - - String title() const { return ""; } - unsigned int uid() const { return 0; } - - void writeJSON(OutputStream*) { } - SnapshotObjectId maxSnapshotJSObjectId() const { return 0; } - -private: - ScriptHeapSnapshot() { } -}; - -} // namespace WebCore - -#endif // ScriptHeapSnapshot_h diff --git a/Source/WebCore/bindings/js/ScriptModuleLoader.cpp b/Source/WebCore/bindings/js/ScriptModuleLoader.cpp new file mode 100644 index 000000000..b67ffa3e6 --- /dev/null +++ b/Source/WebCore/bindings/js/ScriptModuleLoader.cpp @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2015-2017 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 "ScriptModuleLoader.h" + +#include "CachedModuleScriptLoader.h" +#include "CachedScript.h" +#include "CachedScriptFetcher.h" +#include "Document.h" +#include "Frame.h" +#include "JSDOMBinding.h" +#include "LoadableModuleScript.h" +#include "MIMETypeRegistry.h" +#include "ModuleFetchFailureKind.h" +#include "ScriptController.h" +#include "ScriptSourceCode.h" +#include "WebCoreJSClientData.h" +#include <runtime/Completion.h> +#include <runtime/JSInternalPromise.h> +#include <runtime/JSInternalPromiseDeferred.h> +#include <runtime/JSModuleRecord.h> +#include <runtime/JSScriptFetcher.h> +#include <runtime/JSSourceCode.h> +#include <runtime/JSString.h> +#include <runtime/Symbol.h> + +namespace WebCore { + +ScriptModuleLoader::ScriptModuleLoader(Document& document) + : m_document(document) +{ +} + +ScriptModuleLoader::~ScriptModuleLoader() +{ + for (auto& loader : m_loaders) + loader->clearClient(); +} + +static bool isRootModule(JSC::JSValue importerModuleKey) +{ + return importerModuleKey.isSymbol() || importerModuleKey.isUndefined(); +} + +static Expected<URL, ASCIILiteral> resolveModuleSpecifier(Document& document, const String& specifier, const URL& baseURL) +{ + // https://html.spec.whatwg.org/multipage/webappapis.html#resolve-a-module-specifier + + URL absoluteURL(URL(), specifier); + if (absoluteURL.isValid()) + return absoluteURL; + + if (!specifier.startsWith('/') && !specifier.startsWith("./") && !specifier.startsWith("../")) + return makeUnexpected(ASCIILiteral("Module specifier does not start with \"/\", \"./\", or \"../\".")); + + auto result = document.completeURL(specifier, baseURL); + if (!result.isValid()) + return makeUnexpected(ASCIILiteral("Module name does not resolve to a valid URL.")); + return result; +} + +JSC::JSInternalPromise* ScriptModuleLoader::resolve(JSC::JSGlobalObject* jsGlobalObject, JSC::ExecState* exec, JSC::JSModuleLoader*, JSC::JSValue moduleNameValue, JSC::JSValue importerModuleKey, JSC::JSValue) +{ + auto& globalObject = *JSC::jsCast<JSDOMGlobalObject*>(jsGlobalObject); + auto& jsPromise = *JSC::JSInternalPromiseDeferred::create(exec, &globalObject); + auto promise = DeferredPromise::create(globalObject, jsPromise); + + // We use a Symbol as a special purpose; It means this module is an inline module. + // So there is no correct URL to retrieve the module source code. If the module name + // value is a Symbol, it is used directly as a module key. + if (moduleNameValue.isSymbol()) { + promise->resolve<IDLAny>(JSC::Symbol::create(exec->vm(), asSymbol(moduleNameValue)->privateName().uid())); + return jsPromise.promise(); + } + + if (!moduleNameValue.isString()) { + promise->reject(TypeError, ASCIILiteral("Importer module key is not a Symbol or a String.")); + return jsPromise.promise(); + } + + String specifier = asString(moduleNameValue)->value(exec); + URL baseURL; + if (isRootModule(importerModuleKey)) + baseURL = m_document.baseURL(); + else { + ASSERT(importerModuleKey.isString()); + URL importerModuleRequestURL(URL(), asString(importerModuleKey)->value(exec)); + ASSERT_WITH_MESSAGE(importerModuleRequestURL.isValid(), "Invalid module referrer never starts importing dependent modules."); + + auto iterator = m_requestURLToResponseURLMap.find(importerModuleRequestURL); + ASSERT_WITH_MESSAGE(iterator != m_requestURLToResponseURLMap.end(), "Module referrer must register itself to the map before starting importing dependent modules."); + baseURL = iterator->value; + } + + auto result = resolveModuleSpecifier(m_document, specifier, baseURL); + if (!result) { + promise->reject(TypeError, result.error()); + return jsPromise.promise(); + } + + promise->resolve<IDLDOMString>(result->string()); + return jsPromise.promise(); +} + +static void rejectToPropagateNetworkError(DeferredPromise& deferred, ModuleFetchFailureKind failureKind, ASCIILiteral message) +{ + deferred.rejectWithCallback([&] (JSC::ExecState& state, JSDOMGlobalObject&) { + // We annotate exception with special private symbol. It allows us to distinguish these errors from the user thrown ones. + JSC::VM& vm = state.vm(); + // FIXME: Propagate more descriptive error. + // https://bugs.webkit.org/show_bug.cgi?id=167553 + auto* error = JSC::createTypeError(&state, message); + ASSERT(error); + error->putDirect(vm, static_cast<JSVMClientData&>(*vm.clientData).builtinNames().failureKindPrivateName(), JSC::jsNumber(static_cast<int32_t>(failureKind))); + return error; + }); +} + +JSC::JSInternalPromise* ScriptModuleLoader::fetch(JSC::JSGlobalObject* jsGlobalObject, JSC::ExecState* exec, JSC::JSModuleLoader*, JSC::JSValue moduleKeyValue, JSC::JSValue scriptFetcher) +{ + ASSERT(JSC::jsDynamicCast<JSC::JSScriptFetcher*>(exec->vm(), scriptFetcher)); + + auto& globalObject = *JSC::jsCast<JSDOMGlobalObject*>(jsGlobalObject); + auto& jsPromise = *JSC::JSInternalPromiseDeferred::create(exec, &globalObject); + auto deferred = DeferredPromise::create(globalObject, jsPromise); + if (moduleKeyValue.isSymbol()) { + deferred->reject(TypeError, ASCIILiteral("Symbol module key should be already fulfilled with the inlined resource.")); + return jsPromise.promise(); + } + + if (!moduleKeyValue.isString()) { + deferred->reject(TypeError, ASCIILiteral("Module key is not Symbol or String.")); + return jsPromise.promise(); + } + + // https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-single-module-script + + URL completedURL(URL(), asString(moduleKeyValue)->value(exec)); + if (!completedURL.isValid()) { + deferred->reject(TypeError, ASCIILiteral("Module key is a valid URL.")); + return jsPromise.promise(); + } + + auto loader = CachedModuleScriptLoader::create(*this, deferred.get(), *static_cast<CachedScriptFetcher*>(JSC::jsCast<JSC::JSScriptFetcher*>(scriptFetcher)->fetcher())); + m_loaders.add(loader.copyRef()); + if (!loader->load(m_document, completedURL)) { + loader->clearClient(); + m_loaders.remove(WTFMove(loader)); + rejectToPropagateNetworkError(deferred.get(), ModuleFetchFailureKind::WasErrored, ASCIILiteral("Importing a module script failed.")); + return jsPromise.promise(); + } + + return jsPromise.promise(); +} + +JSC::JSValue ScriptModuleLoader::evaluate(JSC::JSGlobalObject*, JSC::ExecState* exec, JSC::JSModuleLoader*, JSC::JSValue moduleKeyValue, JSC::JSValue moduleRecordValue, JSC::JSValue) +{ + JSC::VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + // FIXME: Currently, we only support JSModuleRecord. + // Once the reflective part of the module loader is supported, we will handle arbitrary values. + // https://whatwg.github.io/loader/#registry-prototype-provide + auto* moduleRecord = jsDynamicDowncast<JSC::JSModuleRecord*>(vm, moduleRecordValue); + if (!moduleRecord) + return JSC::jsUndefined(); + + URL sourceURL; + if (moduleKeyValue.isSymbol()) + sourceURL = m_document.url(); + else if (moduleKeyValue.isString()) + sourceURL = URL(URL(), asString(moduleKeyValue)->value(exec)); + else + return JSC::throwTypeError(exec, scope, ASCIILiteral("Module key is not Symbol or String.")); + + if (!sourceURL.isValid()) + return JSC::throwTypeError(exec, scope, ASCIILiteral("Module key is an invalid URL.")); + + if (auto* frame = m_document.frame()) + return frame->script().evaluateModule(sourceURL, *moduleRecord); + return JSC::jsUndefined(); +} + +static JSC::JSInternalPromise* rejectPromise(JSC::ExecState& state, JSDOMGlobalObject& globalObject, ExceptionCode ec, ASCIILiteral message) +{ + auto& jsPromise = *JSC::JSInternalPromiseDeferred::create(&state, &globalObject); + auto deferred = DeferredPromise::create(globalObject, jsPromise); + deferred->reject(ec, WTFMove(message)); + return jsPromise.promise(); +} + +JSC::JSInternalPromise* ScriptModuleLoader::importModule(JSC::JSGlobalObject* jsGlobalObject, JSC::ExecState* exec, JSC::JSModuleLoader*, JSC::JSString* moduleName, const JSC::SourceOrigin& sourceOrigin) +{ + auto& state = *exec; + JSC::VM& vm = exec->vm(); + auto& globalObject = *JSC::jsCast<JSDOMGlobalObject*>(jsGlobalObject); + + // If SourceOrigin and/or CachedScriptFetcher is null, we import the module with the default fetcher. + // SourceOrigin can be null if the source code is not coupled with the script file. + // The examples, + // 1. The code evaluated by the inspector. + // 2. The other unusual code execution like the evaluation through the NPAPI. + // 3. The code from injected bundle's script. + // 4. The code from extension script. + URL baseURL; + RefPtr<JSC::ScriptFetcher> scriptFetcher; + if (sourceOrigin.isNull()) { + baseURL = m_document.baseURL(); + scriptFetcher = CachedScriptFetcher::create(m_document.charset()); + } else { + baseURL = URL(URL(), sourceOrigin.string()); + if (!baseURL.isValid()) + return rejectPromise(state, globalObject, TypeError, ASCIILiteral("Importer module key is not a Symbol or a String.")); + + if (sourceOrigin.fetcher()) + scriptFetcher = sourceOrigin.fetcher(); + else + scriptFetcher = CachedScriptFetcher::create(m_document.charset()); + } + ASSERT(baseURL.isValid()); + ASSERT(scriptFetcher); + + auto specifier = moduleName->value(exec); + auto result = resolveModuleSpecifier(m_document, specifier, baseURL); + if (!result) + return rejectPromise(state, globalObject, TypeError, result.error()); + + return JSC::importModule(exec, JSC::Identifier::fromString(&vm, result->string()), JSC::JSScriptFetcher::create(vm, WTFMove(scriptFetcher) )); +} + +void ScriptModuleLoader::notifyFinished(CachedModuleScriptLoader& loader, RefPtr<DeferredPromise> promise) +{ + // https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-single-module-script + + if (!m_loaders.remove(&loader)) + return; + loader.clearClient(); + + auto& cachedScript = *loader.cachedScript(); + + if (cachedScript.resourceError().isAccessControl()) { + promise->reject(TypeError, ASCIILiteral("Cross-origin script load denied by Cross-Origin Resource Sharing policy.")); + return; + } + + if (cachedScript.errorOccurred()) { + rejectToPropagateNetworkError(*promise, ModuleFetchFailureKind::WasErrored, ASCIILiteral("Importing a module script failed.")); + return; + } + + if (cachedScript.wasCanceled()) { + rejectToPropagateNetworkError(*promise, ModuleFetchFailureKind::WasCanceled, ASCIILiteral("Importing a module script is canceled.")); + return; + } + + if (!MIMETypeRegistry::isSupportedJavaScriptMIMEType(cachedScript.response().mimeType())) { + // https://html.spec.whatwg.org/multipage/webappapis.html#fetch-a-single-module-script + // The result of extracting a MIME type from response's header list (ignoring parameters) is not a JavaScript MIME type. + // For historical reasons, fetching a classic script does not include MIME type checking. In contrast, module scripts will fail to load if they are not of a correct MIME type. + promise->reject(TypeError, makeString("'", cachedScript.response().mimeType(), "' is not a valid JavaScript MIME type.")); + return; + } + + m_requestURLToResponseURLMap.add(cachedScript.url(), cachedScript.response().url()); + promise->resolveWithCallback([&] (JSC::ExecState& state, JSDOMGlobalObject&) { + return JSC::JSSourceCode::create(state.vm(), + JSC::SourceCode { ScriptSourceCode { &cachedScript, JSC::SourceProviderSourceType::Module, loader.scriptFetcher() }.jsSourceCode() }); + }); +} + +} diff --git a/Source/WebCore/bindings/js/ScriptModuleLoader.h b/Source/WebCore/bindings/js/ScriptModuleLoader.h new file mode 100644 index 000000000..6e7a61b57 --- /dev/null +++ b/Source/WebCore/bindings/js/ScriptModuleLoader.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2015, 2016 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. + */ + +#pragma once + +#include "CachedModuleScriptLoader.h" +#include "CachedModuleScriptLoaderClient.h" +#include "URL.h" +#include "URLHash.h" +#include <runtime/JSCJSValue.h> +#include <wtf/Noncopyable.h> + +namespace JSC { + +class ExecState; +class JSGlobalObject; +class JSInternalPromise; +class JSModuleLoader; +class SourceOrigin; + +} + +namespace WebCore { + +class Document; +class JSDOMGlobalObject; + +class ScriptModuleLoader final : private CachedModuleScriptLoaderClient { + WTF_MAKE_NONCOPYABLE(ScriptModuleLoader); WTF_MAKE_FAST_ALLOCATED; +public: + explicit ScriptModuleLoader(Document&); + ~ScriptModuleLoader(); + + Document& document() { return m_document; } + + JSC::JSInternalPromise* resolve(JSC::JSGlobalObject*, JSC::ExecState*, JSC::JSModuleLoader*, JSC::JSValue moduleName, JSC::JSValue importerModuleKey, JSC::JSValue scriptFetcher); + JSC::JSInternalPromise* fetch(JSC::JSGlobalObject*, JSC::ExecState*, JSC::JSModuleLoader*, JSC::JSValue moduleKey, JSC::JSValue scriptFetcher); + JSC::JSValue evaluate(JSC::JSGlobalObject*, JSC::ExecState*, JSC::JSModuleLoader*, JSC::JSValue moduleKey, JSC::JSValue moduleRecord, JSC::JSValue scriptFetcher); + JSC::JSInternalPromise* importModule(JSC::JSGlobalObject*, JSC::ExecState*, JSC::JSModuleLoader*, JSC::JSString*, const JSC::SourceOrigin&); + +private: + void notifyFinished(CachedModuleScriptLoader&, RefPtr<DeferredPromise>) final; + + Document& m_document; + HashMap<URL, URL> m_requestURLToResponseURLMap; + HashSet<Ref<CachedModuleScriptLoader>> m_loaders; +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/ScriptProfile.cpp b/Source/WebCore/bindings/js/ScriptProfile.cpp deleted file mode 100644 index c8778a580..000000000 --- a/Source/WebCore/bindings/js/ScriptProfile.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2010 Apple Inc. All rights reserved. - * Copyright (C) 2010 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 COMPUTER, INC. ``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 COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#include "ScriptProfile.h" - -#include "JSDOMBinding.h" -#include <inspector/InspectorValues.h> -#include <profiler/Profile.h> -#include <profiler/ProfileNode.h> - -namespace WebCore { - -PassRefPtr<ScriptProfile> ScriptProfile::create(PassRefPtr<JSC::Profile> profile) -{ - if (!profile) - return 0; - return adoptRef(new ScriptProfile(profile)); -} - -ScriptProfile::ScriptProfile(PassRefPtr<JSC::Profile> profile) - : m_profile(profile) -{ -} - -ScriptProfile::~ScriptProfile() -{ -} - -String ScriptProfile::title() const -{ - return m_profile->title(); -} - -unsigned int ScriptProfile::uid() const -{ - return m_profile->uid(); -} - -ScriptProfileNode* ScriptProfile::head() const -{ - return m_profile->head(); -} - -double ScriptProfile::idleTime() const -{ - return 0.0; -} - -#if ENABLE(INSPECTOR) -static PassRefPtr<Inspector::TypeBuilder::Profiler::CPUProfileNode> buildInspectorObjectFor(const JSC::ProfileNode* node) -{ - typedef Vector<RefPtr<JSC::ProfileNode>> ProfileNodesList; - const ProfileNodesList& nodeChildren = node->children(); - ProfileNodesList::const_iterator end = nodeChildren.end(); - RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Profiler::CPUProfileNode>> children = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Profiler::CPUProfileNode>::create(); - for (ProfileNodesList::const_iterator iter = nodeChildren.begin(); iter != end; ++iter) - children->addItem(buildInspectorObjectFor(iter->get())); - - RefPtr<Inspector::TypeBuilder::Profiler::CPUProfileNode> result = Inspector::TypeBuilder::Profiler::CPUProfileNode::create() - .setFunctionName(node->functionName()) - .setUrl(node->url()) - .setLineNumber(node->lineNumber()) - .setTotalTime(node->totalTime()) - .setSelfTime(node->selfTime()) - .setNumberOfCalls(node->numberOfCalls()) - .setCallUID(node->callIdentifier().hash()) - .setChildren(children.release()); - return result.release(); -} - -PassRefPtr<Inspector::TypeBuilder::Profiler::CPUProfileNode> ScriptProfile::buildInspectorObjectForHead() const -{ - return buildInspectorObjectFor(m_profile->head()); -} - -PassRefPtr<Inspector::TypeBuilder::Profiler::CPUProfileNode> ScriptProfile::buildInspectorObjectForBottomUpHead() const -{ - return 0; -} -#endif - -} // namespace WebCore diff --git a/Source/WebCore/bindings/js/ScriptProfile.h b/Source/WebCore/bindings/js/ScriptProfile.h deleted file mode 100644 index 1f4c03ec9..000000000 --- a/Source/WebCore/bindings/js/ScriptProfile.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2010 Apple Inc. All rights reserved. - * Copyright (C) 2010 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 COMPUTER, INC. ``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 COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef ScriptProfile_h -#define ScriptProfile_h - -#include "ScriptProfileNode.h" -#include <wtf/Forward.h> -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> -#include <wtf/RefPtr.h> - -#if ENABLE(INSPECTOR) -#include "InspectorWebTypeBuilders.h" -#endif - -namespace JSC { -class Profile; -} - -namespace WebCore { - -class ScriptProfile : public RefCounted<ScriptProfile> { -public: - static PassRefPtr<ScriptProfile> create(PassRefPtr<JSC::Profile> profile); - virtual ~ScriptProfile(); - - String title() const; - unsigned int uid() const; - ScriptProfileNode* head() const; - double idleTime() const; - -#if ENABLE(INSPECTOR) - PassRefPtr<Inspector::TypeBuilder::Profiler::CPUProfileNode> buildInspectorObjectForHead() const; - PassRefPtr<Inspector::TypeBuilder::Profiler::CPUProfileNode> buildInspectorObjectForBottomUpHead() const; -#endif - -private: - ScriptProfile(PassRefPtr<JSC::Profile> profile); - - RefPtr<JSC::Profile> m_profile; -}; - - -} // namespace WebCore - -#endif // ScriptProfile_h diff --git a/Source/WebCore/bindings/js/ScriptProfiler.cpp b/Source/WebCore/bindings/js/ScriptProfiler.cpp deleted file mode 100644 index a30e7b285..000000000 --- a/Source/WebCore/bindings/js/ScriptProfiler.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2010 Apple Inc. All rights reserved. - * Copyright (C) 2010 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 COMPUTER, INC. ``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 COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#include "ScriptProfiler.h" - -#include "GCController.h" -#include "JSDOMBinding.h" -#include "JSDOMWindow.h" -#include "MainFrame.h" -#include "Page.h" -#include "ScriptState.h" -#include <bindings/ScriptObject.h> -#include <bindings/ScriptValue.h> -#include <profiler/LegacyProfiler.h> -#include <wtf/Forward.h> - -namespace WebCore { - -void ScriptProfiler::collectGarbage() -{ - gcController().garbageCollectSoon(); -} - -Deprecated::ScriptObject ScriptProfiler::objectByHeapObjectId(unsigned) -{ - return Deprecated::ScriptObject(); -} - -unsigned ScriptProfiler::getHeapObjectId(const Deprecated::ScriptValue&) -{ - return 0; -} - -void ScriptProfiler::start(JSC::ExecState* state, const String& title) -{ - JSC::LegacyProfiler::profiler()->startProfiling(state, title); -} - -void ScriptProfiler::startForPage(Page* inspectedPage, const String& title) -{ - JSC::ExecState* scriptState = toJSDOMWindow(&inspectedPage->mainFrame(), debuggerWorld())->globalExec(); - start(scriptState, title); -} - -void ScriptProfiler::startForWorkerGlobalScope(WorkerGlobalScope* context, const String& title) -{ - start(execStateFromWorkerGlobalScope(context), title); -} - -PassRefPtr<ScriptProfile> ScriptProfiler::stop(JSC::ExecState* state, const String& title) -{ - RefPtr<JSC::Profile> profile = JSC::LegacyProfiler::profiler()->stopProfiling(state, title); - return ScriptProfile::create(profile); -} - -PassRefPtr<ScriptProfile> ScriptProfiler::stopForPage(Page* inspectedPage, const String& title) -{ - JSC::ExecState* scriptState = toJSDOMWindow(&inspectedPage->mainFrame(), debuggerWorld())->globalExec(); - return stop(scriptState, title); -} - -PassRefPtr<ScriptProfile> ScriptProfiler::stopForWorkerGlobalScope(WorkerGlobalScope* context, const String& title) -{ - return stop(execStateFromWorkerGlobalScope(context), title); -} - -} // namespace WebCore diff --git a/Source/WebCore/bindings/js/ScriptProfiler.h b/Source/WebCore/bindings/js/ScriptProfiler.h deleted file mode 100644 index 3e99168a4..000000000 --- a/Source/WebCore/bindings/js/ScriptProfiler.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2010 Apple Inc. All rights reserved. - * Copyright (C) 2010 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 COMPUTER, INC. ``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 COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef ScriptProfiler_h -#define ScriptProfiler_h - -#include "ScriptHeapSnapshot.h" -#include "ScriptProfile.h" -#include "ScriptState.h" -#include <wtf/Forward.h> -#include <wtf/PassRefPtr.h> - -namespace Deprecated { -class ScriptObject; -class ScriptValue; -} - -namespace WebCore { - -class Page; -class WorkerGlobalScope; - -class ScriptProfiler { - WTF_MAKE_NONCOPYABLE(ScriptProfiler); -public: - class HeapSnapshotProgress { - public: - virtual ~HeapSnapshotProgress() { } - virtual void Start(int totalWork) = 0; - virtual void Worked(int workDone) = 0; - virtual void Done() = 0; - virtual bool isCanceled() = 0; - }; - - static void collectGarbage(); - static Deprecated::ScriptObject objectByHeapObjectId(unsigned id); - static unsigned getHeapObjectId(const Deprecated::ScriptValue&); - static void start(JSC::ExecState*, const String& title); - static void startForPage(Page*, const String& title); - static void startForWorkerGlobalScope(WorkerGlobalScope*, const String& title); - static PassRefPtr<ScriptProfile> stop(JSC::ExecState*, const String& title); - static PassRefPtr<ScriptProfile> stopForPage(Page*, const String& title); - static PassRefPtr<ScriptProfile> stopForWorkerGlobalScope(WorkerGlobalScope*, const String& title); - static PassRefPtr<ScriptHeapSnapshot> takeHeapSnapshot(const String&, HeapSnapshotProgress*) { return 0; } - static bool isSampling() { return false; } - static bool hasHeapProfiler() { return false; } - static HashMap<String, double>* currentProfileNameIdleTimeMap() { return 0; } -}; - -} // namespace WebCore - -#endif // ScriptProfiler_h diff --git a/Source/WebCore/bindings/js/ScriptSourceCode.h b/Source/WebCore/bindings/js/ScriptSourceCode.h index 2d3c15970..06a8edc83 100644 --- a/Source/WebCore/bindings/js/ScriptSourceCode.h +++ b/Source/WebCore/bindings/js/ScriptSourceCode.h @@ -28,11 +28,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ScriptSourceCode_h -#define ScriptSourceCode_h +#pragma once #include "CachedResourceHandle.h" #include "CachedScript.h" +#include "CachedScriptFetcher.h" #include "CachedScriptSourceProvider.h" #include "URL.h" #include <parser/SourceProvider.h> @@ -43,43 +43,44 @@ namespace WebCore { class ScriptSourceCode { public: - ScriptSourceCode(const String& source, const URL& url = URL(), const TextPosition& startPosition = TextPosition::minimumPosition()) - : m_provider(JSC::StringSourceProvider::create(source, url.isNull() ? String() : url.string(), startPosition)) - , m_code(m_provider, startPosition.m_line.oneBasedInt(), startPosition.m_column.oneBasedInt()) + ScriptSourceCode(const String& source, const URL& url = URL(), const TextPosition& startPosition = TextPosition(), JSC::SourceProviderSourceType sourceType = JSC::SourceProviderSourceType::Program) + : m_provider(JSC::StringSourceProvider::create(source, JSC::SourceOrigin { url.string() }, url.string(), startPosition, sourceType)) + , m_code(m_provider.copyRef(), startPosition.m_line.oneBasedInt(), startPosition.m_column.oneBasedInt()) , m_url(url) { } - explicit ScriptSourceCode(CachedScript* cachedScript) - : m_provider(CachedScriptSourceProvider::create(cachedScript)) - , m_code(m_provider) + ScriptSourceCode(CachedScript* cachedScript, JSC::SourceProviderSourceType sourceType, Ref<CachedScriptFetcher>&& scriptFetcher) + : m_provider(CachedScriptSourceProvider::create(cachedScript, sourceType, WTFMove(scriptFetcher))) + , m_code(m_provider.copyRef()) , m_cachedScript(cachedScript) { } + ScriptSourceCode(const String& source, const URL& url, const TextPosition& startPosition, JSC::SourceProviderSourceType sourceType, Ref<CachedScriptFetcher>&& scriptFetcher) + : m_provider(JSC::StringSourceProvider::create(source, JSC::SourceOrigin { url.string(), WTFMove(scriptFetcher) }, url.string(), startPosition, sourceType)) + , m_code(m_provider.copyRef(), startPosition.m_line.oneBasedInt(), startPosition.m_column.oneBasedInt()) + , m_url(url) + { + } + bool isEmpty() const { return m_code.length() == 0; } const JSC::SourceCode& jsSourceCode() const { return m_code; } - const String& source() const { return m_provider->source(); } + StringView source() const { return m_provider->source(); } - int startLine() const { return m_code.firstLine(); } + int startLine() const { return m_code.firstLine().oneBasedInt(); } CachedScript* cachedScript() const { return m_cachedScript.get(); } const URL& url() const { return m_url; } private: - RefPtr<JSC::SourceProvider> m_provider; - + Ref<JSC::SourceProvider> m_provider; JSC::SourceCode m_code; - CachedResourceHandle<CachedScript> m_cachedScript; - URL m_url; - }; } // namespace WebCore - -#endif // ScriptSourceCode_h diff --git a/Source/WebCore/bindings/js/ScriptState.cpp b/Source/WebCore/bindings/js/ScriptState.cpp index af1048dce..301c7cc50 100644 --- a/Source/WebCore/bindings/js/ScriptState.cpp +++ b/Source/WebCore/bindings/js/ScriptState.cpp @@ -50,23 +50,32 @@ namespace WebCore { DOMWindow* domWindowFromExecState(JSC::ExecState* scriptState) { JSC::JSGlobalObject* globalObject = scriptState->lexicalGlobalObject(); - if (!globalObject->inherits(JSDOMWindowBase::info())) - return 0; - return &JSC::jsCast<JSDOMWindowBase*>(globalObject)->impl(); + JSC::VM& vm = globalObject->vm(); + if (!globalObject->inherits(vm, JSDOMWindowBase::info())) + return nullptr; + return &JSC::jsCast<JSDOMWindowBase*>(globalObject)->wrapped(); +} + +Frame* frameFromExecState(JSC::ExecState* scriptState) +{ + ScriptExecutionContext* context = scriptExecutionContextFromExecState(scriptState); + Document* document = is<Document>(context) ? downcast<Document>(context) : nullptr; + return document ? document->frame() : nullptr; } ScriptExecutionContext* scriptExecutionContextFromExecState(JSC::ExecState* scriptState) { JSC::JSGlobalObject* globalObject = scriptState->lexicalGlobalObject(); - if (!globalObject->inherits(JSDOMGlobalObject::info())) - return 0; + JSC::VM& vm = globalObject->vm(); + if (!globalObject->inherits(vm, JSDOMGlobalObject::info())) + return nullptr; return JSC::jsCast<JSDOMGlobalObject*>(globalObject)->scriptExecutionContext(); } JSC::ExecState* mainWorldExecState(Frame* frame) { if (!frame) - return 0; + return nullptr; JSDOMWindowShell* shell = frame->script().windowShell(mainThreadNormalWorld()); return shell->window()->globalExec(); } @@ -74,18 +83,18 @@ JSC::ExecState* mainWorldExecState(Frame* frame) JSC::ExecState* execStateFromNode(DOMWrapperWorld& world, Node* node) { if (!node) - return 0; + return nullptr; Frame* frame = node->document().frame(); if (!frame) - return 0; + return nullptr; if (!frame->script().canExecuteScripts(NotAboutToExecuteScript)) - return 0; + return nullptr; return frame->script().globalObject(world)->globalExec(); } JSC::ExecState* execStateFromPage(DOMWrapperWorld& world, Page* page) { - return page->mainFrame().script().globalObject(world)->globalExec(); + return page ? page->mainFrame().script().globalObject(world)->globalExec() : nullptr; } JSC::ExecState* execStateFromWorkerGlobalScope(WorkerGlobalScope* workerGlobalScope) diff --git a/Source/WebCore/bindings/js/ScriptState.h b/Source/WebCore/bindings/js/ScriptState.h index 70d14c7cd..74421fd95 100644 --- a/Source/WebCore/bindings/js/ScriptState.h +++ b/Source/WebCore/bindings/js/ScriptState.h @@ -29,14 +29,14 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ScriptState_h -#define ScriptState_h +#pragma once namespace JSC { class ExecState; } namespace WebCore { + class DOMWindow; class DOMWrapperWorld; class Frame; @@ -45,21 +45,14 @@ class Page; class ScriptExecutionContext; class WorkerGlobalScope; -// The idea is to expose "state-like" methods (hadException, and any other -// methods where ExecState just dips into vm) of JSC::ExecState as a -// separate abstraction. -// For now, the separation is purely by convention. -typedef JSC::ExecState ScriptState; - DOMWindow* domWindowFromExecState(JSC::ExecState*); +Frame* frameFromExecState(JSC::ExecState*); ScriptExecutionContext* scriptExecutionContextFromExecState(JSC::ExecState*); JSC::ExecState* mainWorldExecState(Frame*); JSC::ExecState* execStateFromNode(DOMWrapperWorld&, Node*); -JSC::ExecState* execStateFromPage(DOMWrapperWorld&, Page*); +WEBCORE_EXPORT JSC::ExecState* execStateFromPage(DOMWrapperWorld&, Page*); JSC::ExecState* execStateFromWorkerGlobalScope(WorkerGlobalScope*); } // namespace WebCore - -#endif // ScriptState_h diff --git a/Source/WebCore/bindings/js/ScriptWrappable.h b/Source/WebCore/bindings/js/ScriptWrappable.h index 5b6c65e30..fc0dca0a8 100644 --- a/Source/WebCore/bindings/js/ScriptWrappable.h +++ b/Source/WebCore/bindings/js/ScriptWrappable.h @@ -29,8 +29,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ScriptWrappable_h -#define ScriptWrappable_h +#pragma once #include <heap/Weak.h> @@ -40,18 +39,22 @@ class WeakHandleOwner; namespace WebCore { -class JSDOMWrapper; +class JSDOMObject; class ScriptWrappable { public: - JSDOMWrapper* wrapper() const; - void setWrapper(JSDOMWrapper*, JSC::WeakHandleOwner*, void*); - void clearWrapper(JSDOMWrapper*); + JSDOMObject* wrapper() const; + void setWrapper(JSDOMObject*, JSC::WeakHandleOwner*, void*); + void clearWrapper(JSDOMObject*); + + template<typename Derived> + static ptrdiff_t offsetOfWrapper() { return CAST_OFFSET(Derived*, ScriptWrappable*) + OBJECT_OFFSETOF(ScriptWrappable, m_wrapper); } + +protected: + ~ScriptWrappable() { } private: - JSC::Weak<JSDOMWrapper> m_wrapper; + JSC::Weak<JSDOMObject> m_wrapper; }; } // namespace WebCore - -#endif // ScriptWrappable_h diff --git a/Source/WebCore/bindings/js/ScriptWrappableInlines.h b/Source/WebCore/bindings/js/ScriptWrappableInlines.h index dabb657eb..f102c217c 100644 --- a/Source/WebCore/bindings/js/ScriptWrappableInlines.h +++ b/Source/WebCore/bindings/js/ScriptWrappableInlines.h @@ -29,8 +29,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef ScriptWrappableInlines_h -#define ScriptWrappableInlines_h +#pragma once #include "JSDOMWrapper.h" #include <heap/Weak.h> @@ -38,22 +37,20 @@ namespace WebCore { -inline JSDOMWrapper* ScriptWrappable::wrapper() const +inline JSDOMObject* ScriptWrappable::wrapper() const { return m_wrapper.get(); } -inline void ScriptWrappable::setWrapper(JSDOMWrapper* wrapper, JSC::WeakHandleOwner* wrapperOwner, void* context) +inline void ScriptWrappable::setWrapper(JSDOMObject* wrapper, JSC::WeakHandleOwner* wrapperOwner, void* context) { ASSERT(!m_wrapper); - m_wrapper = JSC::Weak<JSDOMWrapper>(wrapper, wrapperOwner, context); + m_wrapper = JSC::Weak<JSDOMObject>(wrapper, wrapperOwner, context); } -inline void ScriptWrappable::clearWrapper(JSDOMWrapper* wrapper) +inline void ScriptWrappable::clearWrapper(JSDOMObject* wrapper) { weakClear(m_wrapper, wrapper); } } // namespace WebCore - -#endif // ScriptWrappableInlines_h diff --git a/Source/WebCore/bindings/js/SerializedScriptValue.cpp b/Source/WebCore/bindings/js/SerializedScriptValue.cpp index 1f7919289..c9904c091 100644 --- a/Source/WebCore/bindings/js/SerializedScriptValue.cpp +++ b/Source/WebCore/bindings/js/SerializedScriptValue.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2013, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -28,49 +28,56 @@ #include "SerializedScriptValue.h" #include "Blob.h" +#include "BlobRegistry.h" #include "CryptoKeyAES.h" #include "CryptoKeyDataOctetSequence.h" #include "CryptoKeyDataRSAComponents.h" #include "CryptoKeyHMAC.h" #include "CryptoKeyRSA.h" -#include "ExceptionCode.h" #include "File.h" #include "FileList.h" +#include "IDBValue.h" #include "ImageData.h" #include "JSBlob.h" #include "JSCryptoKey.h" +#include "JSDOMBinding.h" #include "JSDOMGlobalObject.h" #include "JSFile.h" #include "JSFileList.h" #include "JSImageData.h" #include "JSMessagePort.h" #include "JSNavigator.h" -#include "NotImplemented.h" +#include "ScriptExecutionContext.h" +#include "ScriptState.h" #include "SharedBuffer.h" #include "WebCoreJSClientData.h" #include <limits> #include <JavaScriptCore/APICast.h> -#include <JavaScriptCore/APIShims.h> #include <runtime/ArrayBuffer.h> #include <runtime/BooleanObject.h> #include <runtime/DateInstance.h> #include <runtime/Error.h> +#include <runtime/Exception.h> #include <runtime/ExceptionHelpers.h> +#include <runtime/IterationKind.h> #include <runtime/JSArrayBuffer.h> #include <runtime/JSArrayBufferView.h> +#include <runtime/JSCInlines.h> #include <runtime/JSDataView.h> #include <runtime/JSMap.h> +#include <runtime/JSMapIterator.h> #include <runtime/JSSet.h> +#include <runtime/JSSetIterator.h> #include <runtime/JSTypedArrays.h> -#include <runtime/MapData.h> #include <runtime/ObjectConstructor.h> -#include <runtime/Operations.h> #include <runtime/PropertyNameArray.h> #include <runtime/RegExp.h> #include <runtime/RegExpObject.h> #include <runtime/TypedArrayInlines.h> #include <runtime/TypedArrays.h> #include <wtf/HashTraits.h> +#include <wtf/MainThread.h> +#include <wtf/RunLoop.h> #include <wtf/Vector.h> using namespace JSC; @@ -85,9 +92,20 @@ namespace WebCore { static const unsigned maximumFilterRecursion = 40000; +enum class SerializationReturnCode { + SuccessfullyCompleted, + StackOverflowError, + InterruptedExecutionError, + ValidationError, + ExistingExceptionError, + DataCloneError, + UnspecifiedError +}; + enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember, ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember, - MapDataStartVisitEntry, MapDataEndVisitKey, MapDataEndVisitValue }; + MapDataStartVisitEntry, MapDataEndVisitKey, MapDataEndVisitValue, + SetDataStartVisitEntry, SetDataEndVisitKey }; // These can't be reordered, and any new types must be added to the end of the list enum SerializationTag { @@ -122,9 +140,11 @@ enum SerializationTag { SetObjectTag = 29, MapObjectTag = 30, NonMapPropertiesTag = 31, + NonSetPropertiesTag = 32, #if ENABLE(SUBTLE_CRYPTO) - CryptoKeyTag = 32, + CryptoKeyTag = 33, #endif + SharedArrayBufferTag = 34, ErrorTag = 255 }; @@ -166,6 +186,8 @@ static unsigned typedArrayElementSize(ArrayBufferViewSubtag tag) #if ENABLE(SUBTLE_CRYPTO) +const uint32_t currentKeyFormatVersion = 1; + enum class CryptoKeyClassSubtag { HMAC = 0, AES = 1, @@ -217,7 +239,7 @@ enum class CryptoAlgorithmIdentifierTag { }; const uint8_t cryptoAlgorithmIdentifierTagMaximumValue = 21; -static unsigned countUsages(CryptoKeyUsage usages) +static unsigned countUsages(CryptoKeyUsageBitmap usages) { // Fast bit count algorithm for sparse bit maps. unsigned count = 0; @@ -239,12 +261,16 @@ static unsigned countUsages(CryptoKeyUsage usages) * and EmptyStringObjectTag for serialization of Boolean, Number and String objects. * Version 4. added support for serializing non-index properties of arrays. * Version 5. added support for Map and Set types. + * Version 6. added support for 8-bit strings. */ -static const unsigned CurrentVersion = 5; +static const unsigned CurrentVersion = 6; static const unsigned TerminatorTag = 0xFFFFFFFF; static const unsigned StringPoolTag = 0xFFFFFFFE; static const unsigned NonIndexPropertiesTag = 0xFFFFFFFD; +// The high bit of a StringData's length determines the character size. +static const unsigned StringDataIs8BitFlag = 0x80000000; + /* * Object serialization is performed according to the following grammar, all tags * are recorded as a single uint8_t. @@ -264,9 +290,10 @@ static const unsigned NonIndexPropertiesTag = 0xFFFFFFFD; * * Map :- MapObjectTag MapData * - * Set :- SetObjectTag MapData + * Set :- SetObjectTag SetData * - * MapData :- (<key:Value><value:Value>) NonMapPropertiesTag (<name:StringData><value:Value>)* TerminatorTag + * MapData :- (<key:Value><value:Value>)* NonMapPropertiesTag (<name:StringData><value:Value>)* TerminatorTag + * SetData :- (<key:Value>)* NonSetPropertiesTag (<name:StringData><value:Value>)* TerminatorTag * * Terminal :- * UndefinedTag @@ -293,7 +320,11 @@ static const unsigned NonIndexPropertiesTag = 0xFFFFFFFD; * | ArrayBuffer * | ArrayBufferViewTag ArrayBufferViewSubtag <byteOffset:uint32_t> <byteLength:uint32_t> (ArrayBuffer | ObjectReference) * | ArrayBufferTransferTag <value:uint32_t> - * | CryptoKeyTag <extractable:int32_t> <usagesCount:uint32_t> <usages:byte{usagesCount}> CryptoKeyClassSubtag (CryptoKeyHMAC | CryptoKeyAES | CryptoKeyRSA) + * | CryptoKeyTag <wrappedKeyLength:uint32_t> <factor:byte{wrappedKeyLength}> + * + * Inside wrapped crypto key, data is serialized in this format: + * + * <keyFormatVersion:uint32_t> <extractable:int32_t> <usagesCount:uint32_t> <usages:byte{usagesCount}> CryptoKeyClassSubtag (CryptoKeyHMAC | CryptoKeyAES | CryptoKeyRSA) * * String :- * EmptyStringTag @@ -305,13 +336,13 @@ static const unsigned NonIndexPropertiesTag = 0xFFFFFFFD; * * StringData :- * StringPoolTag <cpIndex:IndexType> - * (not (TerminatorTag | StringPoolTag))<length:uint32_t><characters:UChar{length}> // Added to constant pool when seen, string length 0xFFFFFFFF is disallowed + * (not (TerminatorTag | StringPoolTag))<is8Bit:uint32_t:1><length:uint32_t:31><characters:CharType{length}> // Added to constant pool when seen, string length 0xFFFFFFFF is disallowed * * File :- * FileTag FileData * * FileData :- - * <path:StringData> <url:StringData> <type:StringData> + * <path:StringData> <url:StringData> <type:StringData> <name:StringData> * * FileList :- * FileListTag <length:uint32_t>(<file:FileData>){length} @@ -354,7 +385,7 @@ static const unsigned NonIndexPropertiesTag = 0xFFFFFFFD; * <factorSize:uint32_t> <factor:byte{factorSize}> <crtExponentSize:uint32_t> <crtExponent:byte{crtExponentSize}> <crtCoefficientSize:uint32_t> <crtCoefficient:byte{crtCoefficientSize}> */ -typedef std::pair<JSC::JSValue, SerializationReturnCode> DeserializationResult; +using DeserializationResult = std::pair<JSC::JSValue, SerializationReturnCode>; class CloneBase { protected: @@ -366,18 +397,13 @@ protected: bool shouldTerminate() { - return m_exec->hadException(); - } - - void throwStackOverflow() - { - m_exec->vm().throwException(m_exec, createStackOverflowError(m_exec)); + VM& vm = m_exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + return scope.exception(); } - NO_RETURN_DUE_TO_ASSERT void fail() { - ASSERT_NOT_REACHED(); m_failed = true; } @@ -386,6 +412,24 @@ protected: MarkedArgumentBuffer m_gcBuffer; }; +#if ENABLE(SUBTLE_CRYPTO) +static bool wrapCryptoKey(ExecState* exec, const Vector<uint8_t>& key, Vector<uint8_t>& wrappedKey) +{ + ScriptExecutionContext* scriptExecutionContext = scriptExecutionContextFromExecState(exec); + if (!scriptExecutionContext) + return false; + return scriptExecutionContext->wrapCryptoKey(key, wrappedKey); +} + +static bool unwrapCryptoKey(ExecState* exec, const Vector<uint8_t>& wrappedKey, Vector<uint8_t>& key) +{ + ScriptExecutionContext* scriptExecutionContext = scriptExecutionContextFromExecState(exec); + if (!scriptExecutionContext) + return false; + return scriptExecutionContext->unwrapCryptoKey(wrappedKey, key); +} +#endif + #if ASSUME_LITTLE_ENDIAN template <typename T> static void writeLittleEndian(Vector<uint8_t>& buffer, T value) { @@ -433,24 +477,26 @@ template <> bool writeLittleEndian<uint8_t>(Vector<uint8_t>& buffer, const uint8 class CloneSerializer : CloneBase { public: - static SerializationReturnCode serialize(ExecState* exec, JSValue value, - MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, - Vector<String>& blobURLs, Vector<uint8_t>& out) + static SerializationReturnCode serialize(ExecState* exec, JSValue value, Vector<RefPtr<MessagePort>>& messagePorts, Vector<RefPtr<JSC::ArrayBuffer>>& arrayBuffers, Vector<String>& blobURLs, Vector<uint8_t>& out, SerializationContext context, ArrayBufferContentsArray& sharedBuffers) { - CloneSerializer serializer(exec, messagePorts, arrayBuffers, blobURLs, out); + CloneSerializer serializer(exec, messagePorts, arrayBuffers, blobURLs, out, context, sharedBuffers); return serializer.serialize(value); } - static bool serialize(const String& s, Vector<uint8_t>& out) + static bool serialize(StringView string, Vector<uint8_t>& out) { writeLittleEndian(out, CurrentVersion); - if (s.isEmpty()) { + if (string.isEmpty()) { writeLittleEndian<uint8_t>(out, EmptyStringTag); return true; } writeLittleEndian<uint8_t>(out, StringTag); - writeLittleEndian(out, s.length()); - return writeLittleEndian(out, s.impl()->deprecatedCharacters(), s.length()); + if (string.is8Bit()) { + writeLittleEndian(out, string.length() | StringDataIs8BitFlag); + return writeLittleEndian(out, string.characters8(), string.length()); + } + writeLittleEndian(out, string.length()); + return writeLittleEndian(out, string.characters16(), string.length()); } static void serializeUndefined(Vector<uint8_t>& out) @@ -480,11 +526,13 @@ public: private: typedef HashMap<JSObject*, uint32_t> ObjectPool; - CloneSerializer(ExecState* exec, MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, Vector<String>& blobURLs, Vector<uint8_t>& out) + CloneSerializer(ExecState* exec, Vector<RefPtr<MessagePort>>& messagePorts, Vector<RefPtr<JSC::ArrayBuffer>>& arrayBuffers, Vector<String>& blobURLs, Vector<uint8_t>& out, SerializationContext context, ArrayBufferContentsArray& sharedBuffers) : CloneBase(exec) , m_buffer(out) , m_blobURLs(blobURLs) - , m_emptyIdentifier(exec, emptyString()) + , m_emptyIdentifier(Identifier::fromString(exec, emptyString())) + , m_context(context) + , m_sharedBuffers(sharedBuffers) { write(CurrentVersion); fillTransferMap(messagePorts, m_transferredMessagePorts); @@ -492,13 +540,13 @@ private: } template <class T> - void fillTransferMap(Vector<RefPtr<T>, 1>* input, ObjectPool& result) + void fillTransferMap(Vector<RefPtr<T>>& input, ObjectPool& result) { - if (!input) + if (input.isEmpty()) return; JSDOMGlobalObject* globalObject = jsCast<JSDOMGlobalObject*>(m_exec->lexicalGlobalObject()); - for (size_t i = 0; i < input->size(); i++) { - JSC::JSValue value = toJS(m_exec, globalObject, input->at(i).get()); + for (size_t i = 0; i < input.size(); i++) { + JSC::JSValue value = toJS(m_exec, globalObject, input[i].get()); JSC::JSObject* obj = value.getObject(); if (obj && !result.contains(obj)) result.add(obj, i); @@ -507,27 +555,27 @@ private: SerializationReturnCode serialize(JSValue in); - bool isArray(JSValue value) + bool isArray(VM& vm, JSValue value) { if (!value.isObject()) return false; JSObject* object = asObject(value); - return isJSArray(object) || object->inherits(JSArray::info()); + return isJSArray(object) || object->inherits(vm, JSArray::info()); } - bool isMap(JSValue value) + bool isMap(VM& vm, JSValue value) { if (!value.isObject()) return false; JSObject* object = asObject(value); - return object->inherits(JSMap::info()); + return object->inherits(vm, JSMap::info()); } - bool isSet(JSValue value) + bool isSet(VM& vm, JSValue value) { if (!value.isObject()) return false; JSObject* object = asObject(value); - return object->inherits(JSSet::info()); + return object->inherits(vm, JSSet::info()); } bool checkForDuplicate(JSObject* object) @@ -538,7 +586,7 @@ private: // Handle duplicate references if (found != m_objectPool.end()) { write(ObjectReferenceTag); - ASSERT(static_cast<int32_t>(found->value) < m_objectPool.size()); + ASSERT(found->value < m_objectPool.size()); writeObjectIndex(found->value); return true; } @@ -604,7 +652,7 @@ private: JSValue getProperty(JSObject* object, const Identifier& propertyName) { - PropertySlot slot(object); + PropertySlot slot(object, PropertySlot::InternalMethodType::Get); if (object->methodTable()->getOwnPropertySlot(object, m_exec, propertyName, slot)) return slot.getValue(m_exec, propertyName); return JSValue(); @@ -638,58 +686,59 @@ private: } } - void dumpString(String str) + void dumpString(const String& string) { - if (str.isEmpty()) + if (string.isEmpty()) write(EmptyStringTag); else { write(StringTag); - write(str); + write(string); } } - void dumpStringObject(String str) + void dumpStringObject(const String& string) { - if (str.isEmpty()) + if (string.isEmpty()) write(EmptyStringObjectTag); else { write(StringObjectTag); - write(str); + write(string); } } bool dumpArrayBufferView(JSObject* obj, SerializationReturnCode& code) { + VM& vm = m_exec->vm(); write(ArrayBufferViewTag); - if (obj->inherits(JSDataView::info())) + if (obj->inherits(vm, JSDataView::info())) write(DataViewTag); - else if (obj->inherits(JSUint8ClampedArray::info())) + else if (obj->inherits(vm, JSUint8ClampedArray::info())) write(Uint8ClampedArrayTag); - else if (obj->inherits(JSInt8Array::info())) + else if (obj->inherits(vm, JSInt8Array::info())) write(Int8ArrayTag); - else if (obj->inherits(JSUint8Array::info())) + else if (obj->inherits(vm, JSUint8Array::info())) write(Uint8ArrayTag); - else if (obj->inherits(JSInt16Array::info())) + else if (obj->inherits(vm, JSInt16Array::info())) write(Int16ArrayTag); - else if (obj->inherits(JSUint16Array::info())) + else if (obj->inherits(vm, JSUint16Array::info())) write(Uint16ArrayTag); - else if (obj->inherits(JSInt32Array::info())) + else if (obj->inherits(vm, JSInt32Array::info())) write(Int32ArrayTag); - else if (obj->inherits(JSUint32Array::info())) + else if (obj->inherits(vm, JSUint32Array::info())) write(Uint32ArrayTag); - else if (obj->inherits(JSFloat32Array::info())) + else if (obj->inherits(vm, JSFloat32Array::info())) write(Float32ArrayTag); - else if (obj->inherits(JSFloat64Array::info())) + else if (obj->inherits(vm, JSFloat64Array::info())) write(Float64ArrayTag); else return false; - RefPtr<ArrayBufferView> arrayBufferView = toArrayBufferView(obj); + RefPtr<ArrayBufferView> arrayBufferView = toPossiblySharedArrayBufferView(vm, obj); write(static_cast<uint32_t>(arrayBufferView->byteOffset())); write(static_cast<uint32_t>(arrayBufferView->byteLength())); - RefPtr<ArrayBuffer> arrayBuffer = arrayBufferView->buffer(); + RefPtr<ArrayBuffer> arrayBuffer = arrayBufferView->possiblySharedBuffer(); if (!arrayBuffer) { - code = ValidationError; + code = SerializationReturnCode::ValidationError; return true; } JSValue bufferObj = toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_exec->lexicalGlobalObject()), arrayBuffer.get()); @@ -704,8 +753,7 @@ private: } if (value.isString()) { - String str = asString(value)->value(m_exec); - dumpString(str); + dumpString(asString(value)->value(m_exec)); return true; } @@ -715,31 +763,32 @@ private: return true; } - if (value.isObject() && asObject(value)->inherits(DateInstance::info())) { + VM& vm = m_exec->vm(); + if (value.isObject() && asObject(value)->inherits(vm, DateInstance::info())) { write(DateTag); write(asDateInstance(value)->internalNumber()); return true; } - if (isArray(value)) + if (isArray(vm, value)) return false; if (value.isObject()) { JSObject* obj = asObject(value); - if (obj->inherits(BooleanObject::info())) { + if (obj->inherits(vm, BooleanObject::info())) { if (!startObjectInternal(obj)) // handle duplicates return true; write(asBooleanObject(value)->internalValue().toBoolean(m_exec) ? TrueObjectTag : FalseObjectTag); return true; } - if (obj->inherits(StringObject::info())) { + if (obj->inherits(vm, StringObject::info())) { if (!startObjectInternal(obj)) // handle duplicates return true; String str = asString(asStringObject(value)->internalValue())->value(m_exec); dumpStringObject(str); return true; } - if (obj->inherits(NumberObject::info())) { + if (obj->inherits(vm, NumberObject::info())) { if (!startObjectInternal(obj)) // handle duplicates return true; write(NumberObjectTag); @@ -747,12 +796,12 @@ private: write(obj->internalValue().asNumber()); return true; } - if (File* file = toFile(obj)) { + if (File* file = JSFile::toWrapped(vm, obj)) { write(FileTag); write(file); return true; } - if (FileList* list = toFileList(obj)) { + if (FileList* list = JSFileList::toWrapped(vm, obj)) { write(FileListTag); unsigned length = list->length(); write(length); @@ -760,7 +809,7 @@ private: write(list->item(i)); return true; } - if (Blob* blob = toBlob(obj)) { + if (Blob* blob = JSBlob::toWrapped(vm, obj)) { write(BlobTag); m_blobURLs.append(blob->url()); write(blob->url()); @@ -768,7 +817,7 @@ private: write(blob->size()); return true; } - if (ImageData* data = toImageData(obj)) { + if (ImageData* data = JSImageData::toWrapped(vm, obj)) { write(ImageDataTag); write(data->width()); write(data->height()); @@ -776,7 +825,7 @@ private: write(data->data()->data(), data->data()->length()); return true; } - if (obj->inherits(RegExpObject::info())) { + if (obj->inherits(vm, RegExpObject::info())) { RegExpObject* regExp = asRegExpObject(obj); char flags[3]; int flagCount = 0; @@ -791,7 +840,7 @@ private: write(String(flags, flagCount)); return true; } - if (obj->inherits(JSMessagePort::info())) { + if (obj->inherits(vm, JSMessagePort::info())) { ObjectPool::iterator index = m_transferredMessagePorts.find(obj); if (index != m_transferredMessagePorts.end()) { write(MessagePortReferenceTag); @@ -799,12 +848,12 @@ private: return true; } // MessagePort object could not be found in transferred message ports - code = ValidationError; + code = SerializationReturnCode::ValidationError; return true; } - if (ArrayBuffer* arrayBuffer = toArrayBuffer(obj)) { + if (ArrayBuffer* arrayBuffer = toPossiblySharedArrayBuffer(vm, obj)) { if (arrayBuffer->isNeutered()) { - code = ValidationError; + code = SerializationReturnCode::ValidationError; return true; } ObjectPool::iterator index = m_transferredArrayBuffers.find(obj); @@ -815,12 +864,25 @@ private: } if (!startObjectInternal(obj)) // handle duplicates return true; + + if (arrayBuffer->isShared() + && m_context == SerializationContext::WorkerPostMessage) { + uint32_t index = m_sharedBuffers.size(); + ArrayBufferContents contents; + if (arrayBuffer->shareWith(contents)) { + write(SharedArrayBufferTag); + m_sharedBuffers.append(WTFMove(contents)); + write(index); + return true; + } + } + write(ArrayBufferTag); write(arrayBuffer->byteLength()); write(static_cast<const uint8_t*>(arrayBuffer->data()), arrayBuffer->byteLength()); return true; } - if (obj->inherits(JSArrayBufferView::info())) { + if (obj->inherits(vm, JSArrayBufferView::info())) { if (checkForDuplicate(obj)) return true; bool success = dumpArrayBufferView(obj, code); @@ -828,9 +890,19 @@ private: return success; } #if ENABLE(SUBTLE_CRYPTO) - if (CryptoKey* key = toCryptoKey(obj)) { + if (CryptoKey* key = JSCryptoKey::toWrapped(vm, obj)) { write(CryptoKeyTag); - write(key); + Vector<uint8_t> serializedKey; + Vector<String> dummyBlobURLs; + Vector<RefPtr<MessagePort>> dummyMessagePorts; + Vector<RefPtr<JSC::ArrayBuffer>> dummyArrayBuffers; + ArrayBufferContentsArray dummySharedBuffers; + CloneSerializer rawKeySerializer(m_exec, dummyMessagePorts, dummyArrayBuffers, dummyBlobURLs, serializedKey, SerializationContext::Default, dummySharedBuffers); + rawKeySerializer.write(key); + Vector<uint8_t> wrappedKey; + if (!wrapCryptoKey(m_exec, serializedKey, wrappedKey)) + return false; + write(wrappedKey); return true; } #endif @@ -921,7 +993,7 @@ private: template <class T> void writeConstantPoolIndex(const T& constantPool, unsigned i) { - ASSERT(static_cast<int32_t>(i) < constantPool.size()); + ASSERT(i < constantPool.size()); if (constantPool.size() <= 0xFF) write(static_cast<uint8_t>(i)); else if (constantPool.size() <= 0xFFFF) @@ -933,28 +1005,34 @@ private: void write(const Identifier& ident) { const String& str = ident.string(); - StringConstantPool::AddResult addResult = m_constantPool.add(str.impl(), m_constantPool.size()); + StringConstantPool::AddResult addResult = m_constantPool.add(ident.impl(), m_constantPool.size()); if (!addResult.isNewEntry) { write(StringPoolTag); writeStringIndex(addResult.iterator->value); return; } - // This condition is unlikely to happen as they would imply an ~8gb - // string but we should guard against it anyway - if (str.length() >= StringPoolTag) { - fail(); - return; - } + unsigned length = str.length(); // Guard against overflow - if (str.length() > (std::numeric_limits<uint32_t>::max() - sizeof(uint32_t)) / sizeof(UChar)) { + if (length > (std::numeric_limits<uint32_t>::max() - sizeof(uint32_t)) / sizeof(UChar)) { fail(); return; } - writeLittleEndian<uint32_t>(m_buffer, str.length()); - if (!writeLittleEndian<uint16_t>(m_buffer, reinterpret_cast<const uint16_t*>(str.deprecatedCharacters()), str.length())) + if (str.is8Bit()) + writeLittleEndian<uint32_t>(m_buffer, length | StringDataIs8BitFlag); + else + writeLittleEndian<uint32_t>(m_buffer, length); + + if (!length) + return; + if (str.is8Bit()) { + if (!writeLittleEndian(m_buffer, str.characters8(), length)) + fail(); + return; + } + if (!writeLittleEndian(m_buffer, str.characters16(), length)) fail(); } @@ -963,7 +1041,7 @@ private: if (str.isNull()) write(m_emptyIdentifier); else - write(Identifier(m_exec, str)); + write(Identifier::fromString(m_exec, str)); } void write(const Vector<uint8_t>& vector) @@ -979,6 +1057,7 @@ private: write(file->path()); write(file->url()); write(file->type()); + write(file->name()); } #if ENABLE(SUBTLE_CRYPTO) @@ -1095,9 +1174,11 @@ private: void write(const CryptoKey* key) { + write(currentKeyFormatVersion); + write(key->extractable()); - CryptoKeyUsage usages = key->usagesBitmap(); + CryptoKeyUsageBitmap usages = key->usagesBitmap(); write(countUsages(usages)); if (usages & CryptoKeyUsageEncrypt) write(CryptoKeyUsageTag::Encrypt); @@ -1119,23 +1200,23 @@ private: switch (key->keyClass()) { case CryptoKeyClass::HMAC: write(CryptoKeyClassSubtag::HMAC); - write(toCryptoKeyHMAC(key)->key()); - write(toCryptoKeyHMAC(key)->hashAlgorithmIdentifier()); + write(downcast<CryptoKeyHMAC>(*key).key()); + write(downcast<CryptoKeyHMAC>(*key).hashAlgorithmIdentifier()); break; case CryptoKeyClass::AES: write(CryptoKeyClassSubtag::AES); write(key->algorithmIdentifier()); - write(toCryptoKeyAES(key)->key()); + write(downcast<CryptoKeyAES>(*key).key()); break; case CryptoKeyClass::RSA: write(CryptoKeyClassSubtag::RSA); write(key->algorithmIdentifier()); CryptoAlgorithmIdentifier hash; - bool isRestrictedToHash = toCryptoKeyRSA(key)->isRestrictedToHash(hash); + bool isRestrictedToHash = downcast<CryptoKeyRSA>(*key).isRestrictedToHash(hash); write(isRestrictedToHash); if (isRestrictedToHash) write(hash); - write(toCryptoKeyDataRSAComponents(*key->exportData())); + write(downcast<CryptoKeyDataRSAComponents>(*key->exportData())); break; } } @@ -1151,20 +1232,23 @@ private: ObjectPool m_objectPool; ObjectPool m_transferredMessagePorts; ObjectPool m_transferredArrayBuffers; - typedef HashMap<RefPtr<StringImpl>, uint32_t, IdentifierRepHash> StringConstantPool; + typedef HashMap<RefPtr<UniquedStringImpl>, uint32_t, IdentifierRepHash> StringConstantPool; StringConstantPool m_constantPool; Identifier m_emptyIdentifier; + SerializationContext m_context; + ArrayBufferContentsArray& m_sharedBuffers; }; SerializationReturnCode CloneSerializer::serialize(JSValue in) { + VM& vm = m_exec->vm(); Vector<uint32_t, 16> indexStack; Vector<uint32_t, 16> lengthStack; Vector<PropertyNameArray, 16> propertyStack; Vector<JSObject*, 32> inputObjectStack; - Vector<MapData*, 4> mapDataStack; - Vector<MapData::const_iterator, 4> iteratorStack; - Vector<JSValue, 4> iteratorValueStack; + Vector<JSMapIterator*, 4> mapIteratorStack; + Vector<JSSetIterator*, 4> setIteratorStack; + Vector<JSValue, 4> mapIteratorValueStack; Vector<WalkerState, 16> stateStack; WalkerState state = StateUnknown; JSValue inValue = in; @@ -1172,9 +1256,9 @@ SerializationReturnCode CloneSerializer::serialize(JSValue in) switch (state) { arrayStartState: case ArrayStartState: { - ASSERT(isArray(inValue)); + ASSERT(isArray(vm, inValue)); if (inputObjectStack.size() > maximumFilterRecursion) - return StackOverflowError; + return SerializationReturnCode::StackOverflowError; JSArray* inArray = asArray(inValue); unsigned length = inArray->length(); @@ -1193,8 +1277,8 @@ SerializationReturnCode CloneSerializer::serialize(JSValue in) indexStack.removeLast(); lengthStack.removeLast(); - propertyStack.append(PropertyNameArray(m_exec)); - array->methodTable()->getOwnNonIndexPropertyNames(array, m_exec, propertyStack.last(), ExcludeDontEnumProperties); + propertyStack.append(PropertyNameArray(m_exec, PropertyNameMode::Strings)); + array->methodTable()->getOwnNonIndexPropertyNames(array, m_exec, propertyStack.last(), EnumerationMode()); if (propertyStack.last().size()) { write(NonIndexPropertiesTag); indexStack.append(0); @@ -1213,9 +1297,9 @@ SerializationReturnCode CloneSerializer::serialize(JSValue in) } write(index); - SerializationReturnCode terminalCode = SuccessfullyCompleted; + auto terminalCode = SerializationReturnCode::SuccessfullyCompleted; if (dumpIfTerminal(inValue, terminalCode)) { - if (terminalCode != SuccessfullyCompleted) + if (terminalCode != SerializationReturnCode::SuccessfullyCompleted) return terminalCode; indexStack.last()++; goto arrayStartVisitMember; @@ -1231,7 +1315,7 @@ SerializationReturnCode CloneSerializer::serialize(JSValue in) case ObjectStartState: { ASSERT(inValue.isObject()); if (inputObjectStack.size() > maximumFilterRecursion) - return StackOverflowError; + return SerializationReturnCode::StackOverflowError; JSObject* inObject = asObject(inValue); if (!startObject(inObject)) break; @@ -1239,12 +1323,12 @@ SerializationReturnCode CloneSerializer::serialize(JSValue in) // objects have been handled. If we reach this point and // the input is not an Object object then we should throw // a DataCloneError. - if (inObject->classInfo() != JSFinalObject::info()) - return DataCloneError; + if (inObject->classInfo(vm) != JSFinalObject::info()) + return SerializationReturnCode::DataCloneError; inputObjectStack.append(inObject); indexStack.append(0); - propertyStack.append(PropertyNameArray(m_exec)); - inObject->methodTable()->getOwnPropertyNames(inObject, m_exec, propertyStack.last(), ExcludeDontEnumProperties); + propertyStack.append(PropertyNameArray(m_exec, PropertyNameMode::Strings)); + inObject->methodTable()->getOwnPropertyNames(inObject, m_exec, propertyStack.last(), EnumerationMode()); } objectStartVisitMember: FALLTHROUGH; @@ -1261,7 +1345,7 @@ SerializationReturnCode CloneSerializer::serialize(JSValue in) } inValue = getProperty(object, properties[index]); if (shouldTerminate()) - return ExistingExceptionError; + return SerializationReturnCode::ExistingExceptionError; if (!inValue) { // Property was removed during serialisation @@ -1271,20 +1355,20 @@ SerializationReturnCode CloneSerializer::serialize(JSValue in) write(properties[index]); if (shouldTerminate()) - return ExistingExceptionError; + return SerializationReturnCode::ExistingExceptionError; - SerializationReturnCode terminalCode = SuccessfullyCompleted; + auto terminalCode = SerializationReturnCode::SuccessfullyCompleted; if (!dumpIfTerminal(inValue, terminalCode)) { stateStack.append(ObjectEndVisitMember); goto stateUnknown; } - if (terminalCode != SuccessfullyCompleted) + if (terminalCode != SerializationReturnCode::SuccessfullyCompleted) return terminalCode; FALLTHROUGH; } case ObjectEndVisitMember: { if (shouldTerminate()) - return ExistingExceptionError; + return SerializationReturnCode::ExistingExceptionError; indexStack.last()++; goto objectStartVisitMember; @@ -1292,78 +1376,97 @@ SerializationReturnCode CloneSerializer::serialize(JSValue in) mapStartState: { ASSERT(inValue.isObject()); if (inputObjectStack.size() > maximumFilterRecursion) - return StackOverflowError; + return SerializationReturnCode::StackOverflowError; JSMap* inMap = jsCast<JSMap*>(inValue); if (!startMap(inMap)) break; - MapData* mapData = inMap->mapData(); - m_gcBuffer.append(mapData); - mapDataStack.append(mapData); - iteratorStack.append(mapData->begin()); + JSMapIterator* iterator = JSMapIterator::create(vm, m_exec->lexicalGlobalObject()->mapIteratorStructure(), inMap, IterateKeyValue); + m_gcBuffer.append(inMap); + m_gcBuffer.append(iterator); + mapIteratorStack.append(iterator); inputObjectStack.append(inMap); goto mapDataStartVisitEntry; } - setStartState: { - ASSERT(inValue.isObject()); - if (inputObjectStack.size() > maximumFilterRecursion) - return StackOverflowError; - JSSet* inSet = jsCast<JSSet*>(inValue); - if (!startSet(inSet)) - break; - MapData* mapData = inSet->mapData(); - m_gcBuffer.append(mapData); - mapDataStack.append(mapData); - iteratorStack.append(mapData->begin()); - inputObjectStack.append(inSet); - goto mapDataStartVisitEntry; - } mapDataStartVisitEntry: case MapDataStartVisitEntry: { - MapData::const_iterator& ptr = iteratorStack.last(); - MapData* mapData = mapDataStack.last(); - if (ptr == mapData->end()) { - iteratorStack.removeLast(); - mapDataStack.removeLast(); + JSMapIterator* iterator = mapIteratorStack.last(); + JSValue key, value; + if (!iterator->nextKeyValue(m_exec, key, value)) { + mapIteratorStack.removeLast(); JSObject* object = inputObjectStack.last(); - ASSERT(jsDynamicCast<JSSet*>(object) || jsDynamicCast<JSMap*>(object)); - propertyStack.append(PropertyNameArray(m_exec)); - object->methodTable()->getOwnPropertyNames(object, m_exec, propertyStack.last(), ExcludeDontEnumProperties); + ASSERT(jsDynamicDowncast<JSMap*>(vm, object)); + propertyStack.append(PropertyNameArray(m_exec, PropertyNameMode::Strings)); + object->methodTable()->getOwnPropertyNames(object, m_exec, propertyStack.last(), EnumerationMode()); write(NonMapPropertiesTag); indexStack.append(0); goto objectStartVisitMember; } - inValue = ptr.key(); - m_gcBuffer.append(ptr.value()); - iteratorValueStack.append(ptr.value()); + inValue = key; + m_gcBuffer.append(value); + mapIteratorValueStack.append(value); stateStack.append(MapDataEndVisitKey); goto stateUnknown; } case MapDataEndVisitKey: { - inValue = iteratorValueStack.last(); - iteratorValueStack.removeLast(); + inValue = mapIteratorValueStack.last(); + mapIteratorValueStack.removeLast(); stateStack.append(MapDataEndVisitValue); goto stateUnknown; } case MapDataEndVisitValue: { - if (iteratorStack.last() != mapDataStack.last()->end()) - ++iteratorStack.last(); goto mapDataStartVisitEntry; } + setStartState: { + ASSERT(inValue.isObject()); + if (inputObjectStack.size() > maximumFilterRecursion) + return SerializationReturnCode::StackOverflowError; + JSSet* inSet = jsCast<JSSet*>(inValue); + if (!startSet(inSet)) + break; + JSSetIterator* iterator = JSSetIterator::create(vm, m_exec->lexicalGlobalObject()->setIteratorStructure(), inSet, IterateKey); + m_gcBuffer.append(inSet); + m_gcBuffer.append(iterator); + setIteratorStack.append(iterator); + inputObjectStack.append(inSet); + goto setDataStartVisitEntry; + } + setDataStartVisitEntry: + case SetDataStartVisitEntry: { + JSSetIterator* iterator = setIteratorStack.last(); + JSValue key; + if (!iterator->next(m_exec, key)) { + setIteratorStack.removeLast(); + JSObject* object = inputObjectStack.last(); + ASSERT(jsDynamicDowncast<JSSet*>(vm, object)); + propertyStack.append(PropertyNameArray(m_exec, PropertyNameMode::Strings)); + object->methodTable()->getOwnPropertyNames(object, m_exec, propertyStack.last(), EnumerationMode()); + write(NonSetPropertiesTag); + indexStack.append(0); + goto objectStartVisitMember; + } + inValue = key; + stateStack.append(SetDataEndVisitKey); + goto stateUnknown; + } + case SetDataEndVisitKey: { + goto setDataStartVisitEntry; + } + stateUnknown: case StateUnknown: { - SerializationReturnCode terminalCode = SuccessfullyCompleted; + auto terminalCode = SerializationReturnCode::SuccessfullyCompleted; if (dumpIfTerminal(inValue, terminalCode)) { - if (terminalCode != SuccessfullyCompleted) + if (terminalCode != SerializationReturnCode::SuccessfullyCompleted) return terminalCode; break; } - if (isArray(inValue)) + if (isArray(vm, inValue)) goto arrayStartState; - if (isMap(inValue)) + if (isMap(vm, inValue)) goto mapStartState; - if (isSet(inValue)) + if (isSet(vm, inValue)) goto setStartState; goto objectStartState; } @@ -1375,13 +1478,11 @@ SerializationReturnCode CloneSerializer::serialize(JSValue in) stateStack.removeLast(); } if (m_failed) - return UnspecifiedError; + return SerializationReturnCode::UnspecifiedError; - return SuccessfullyCompleted; + return SerializationReturnCode::SuccessfullyCompleted; } -typedef Vector<JSC::ArrayBufferContents> ArrayBufferContentsArray; - class CloneDeserializer : CloneBase { public: static String deserializeString(const Vector<uint8_t>& buffer) @@ -1397,23 +1498,23 @@ public: if (!readLittleEndian(ptr, end, tag) || tag != StringTag) return String(); uint32_t length; - if (!readLittleEndian(ptr, end, length) || length >= StringPoolTag) + if (!readLittleEndian(ptr, end, length)) return String(); + bool is8Bit = length & StringDataIs8BitFlag; + length &= ~StringDataIs8BitFlag; String str; - if (!readString(ptr, end, str, length)) + if (!readString(ptr, end, str, length, is8Bit)) return String(); - return String(str.impl()); + return str; } - static DeserializationResult deserialize(ExecState* exec, JSGlobalObject* globalObject, - MessagePortArray* messagePorts, ArrayBufferContentsArray* arrayBufferContentsArray, - const Vector<uint8_t>& buffer) + static DeserializationResult deserialize(ExecState* exec, JSGlobalObject* globalObject, Vector<RefPtr<MessagePort>>& messagePorts, ArrayBufferContentsArray* arrayBufferContentsArray, const Vector<uint8_t>& buffer, const Vector<String>& blobURLs, const Vector<String> blobFilePaths, ArrayBufferContentsArray* sharedBuffers) { if (!buffer.size()) - return std::make_pair(jsNull(), UnspecifiedError); - CloneDeserializer deserializer(exec, globalObject, messagePorts, arrayBufferContentsArray, buffer); + return std::make_pair(jsNull(), SerializationReturnCode::UnspecifiedError); + CloneDeserializer deserializer(exec, globalObject, messagePorts, arrayBufferContentsArray, buffer, blobURLs, blobFilePaths, sharedBuffers); if (!deserializer.isValid()) - return std::make_pair(JSValue(), ValidationError); + return std::make_pair(JSValue(), SerializationReturnCode::ValidationError); return deserializer.deserialize(); } @@ -1456,12 +1557,10 @@ private: size_t m_index; }; - CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject, - MessagePortArray* messagePorts, ArrayBufferContentsArray* arrayBufferContents, - const Vector<uint8_t>& buffer) + CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject, Vector<RefPtr<MessagePort>>& messagePorts, ArrayBufferContentsArray* arrayBufferContents, const Vector<uint8_t>& buffer) : CloneBase(exec) , m_globalObject(globalObject) - , m_isDOMGlobalObject(globalObject->inherits(JSDOMGlobalObject::info())) + , m_isDOMGlobalObject(globalObject->inherits(globalObject->vm(), JSDOMGlobalObject::info())) , m_ptr(buffer.data()) , m_end(buffer.data() + buffer.size()) , m_version(0xFFFFFFFF) @@ -1473,13 +1572,26 @@ private: m_version = 0xFFFFFFFF; } - DeserializationResult deserialize(); - - void throwValidationError() + CloneDeserializer(ExecState* exec, JSGlobalObject* globalObject, Vector<RefPtr<MessagePort>>& messagePorts, ArrayBufferContentsArray* arrayBufferContents, const Vector<uint8_t>& buffer, const Vector<String>& blobURLs, const Vector<String> blobFilePaths, ArrayBufferContentsArray* sharedBuffers) + : CloneBase(exec) + , m_globalObject(globalObject) + , m_isDOMGlobalObject(globalObject->inherits(globalObject->vm(), JSDOMGlobalObject::info())) + , m_ptr(buffer.data()) + , m_end(buffer.data() + buffer.size()) + , m_version(0xFFFFFFFF) + , m_messagePorts(messagePorts) + , m_arrayBufferContents(arrayBufferContents) + , m_arrayBuffers(arrayBufferContents ? arrayBufferContents->size() : 0) + , m_blobURLs(blobURLs) + , m_blobFilePaths(blobFilePaths) + , m_sharedBuffers(sharedBuffers) { - m_exec->vm().throwException(m_exec, createTypeError(m_exec, "Unable to deserialize data.")); + if (!read(m_version)) + m_version = 0xFFFFFFFF; } + DeserializationResult deserialize(); + bool isValid() const { return m_version <= CurrentVersion; } template <typename T> bool readLittleEndian(T& value) @@ -1582,11 +1694,19 @@ private: return read(i); } - static bool readString(const uint8_t*& ptr, const uint8_t* end, String& str, unsigned length) + static bool readString(const uint8_t*& ptr, const uint8_t* end, String& str, unsigned length, bool is8Bit) { if (length >= std::numeric_limits<int32_t>::max() / sizeof(UChar)) return false; + if (is8Bit) { + if ((end - ptr) < static_cast<int>(length)) + return false; + str = String(reinterpret_cast<const LChar*>(ptr), length); + ptr += length; + return true; + } + unsigned size = length * sizeof(UChar); if ((end - ptr) < static_cast<int>(size)) return false; @@ -1602,7 +1722,7 @@ private: readLittleEndian(ptr, end, ch); buffer.append(ch); } - str = String::adopt(buffer); + str = String::adopt(WTFMove(buffer)); #endif return true; } @@ -1637,8 +1757,10 @@ private: cachedString = CachedStringRef(&m_constantPool, index); return true; } + bool is8Bit = length & StringDataIs8BitFlag; + length &= ~StringDataIs8BitFlag; String str; - if (!readString(m_ptr, m_end, str, length)) { + if (!readString(m_ptr, m_end, str, length, is8Bit)) { fail(); return false; } @@ -1683,8 +1805,17 @@ private: CachedStringRef type; if (!readStringData(type)) return 0; + CachedStringRef name; + if (!readStringData(name)) + return 0; + + // If the blob URL for this file has an associated blob file path, prefer that one over the "built-in" path. + String filePath = blobFilePathForBlobURL(url->string()); + if (filePath.isEmpty()) + filePath = path->string(); + if (m_isDOMGlobalObject) - file = File::create(path->string(), URL(URL(), url->string()), type->string()); + file = File::deserialize(filePath, URL(URL(), url->string()), type->string(), name->string()); return true; } @@ -1700,7 +1831,7 @@ private: return true; } - bool readArrayBufferView(JSValue& arrayBufferView) + bool readArrayBufferView(VM& vm, JSValue& arrayBufferView) { ArrayBufferViewSubtag arrayBufferViewSubtag; if (!readArrayBufferViewSubtag(arrayBufferViewSubtag)) @@ -1712,7 +1843,7 @@ private: if (!read(byteLength)) return false; JSObject* arrayBufferObj = asObject(readTerminal()); - if (!arrayBufferObj || !arrayBufferObj->inherits(JSArrayBuffer::info())) + if (!arrayBufferObj || !arrayBufferObj->inherits(vm, JSArrayBuffer::info())) return false; unsigned elementSize = typedArrayElementSize(arrayBufferViewSubtag); @@ -1722,37 +1853,37 @@ private: if (length * elementSize != byteLength) return false; - RefPtr<ArrayBuffer> arrayBuffer = toArrayBuffer(arrayBufferObj); + RefPtr<ArrayBuffer> arrayBuffer = toPossiblySharedArrayBuffer(vm, arrayBufferObj); switch (arrayBufferViewSubtag) { case DataViewTag: - arrayBufferView = getJSValue(DataView::create(arrayBuffer, byteOffset, length).get()); + arrayBufferView = getJSValue(DataView::create(WTFMove(arrayBuffer), byteOffset, length).get()); return true; case Int8ArrayTag: - arrayBufferView = getJSValue(Int8Array::create(arrayBuffer, byteOffset, length).get()); + arrayBufferView = toJS(m_exec, m_globalObject, Int8Array::create(WTFMove(arrayBuffer), byteOffset, length).get()); return true; case Uint8ArrayTag: - arrayBufferView = getJSValue(Uint8Array::create(arrayBuffer, byteOffset, length).get()); + arrayBufferView = toJS(m_exec, m_globalObject, Uint8Array::create(WTFMove(arrayBuffer), byteOffset, length).get()); return true; case Uint8ClampedArrayTag: - arrayBufferView = getJSValue(Uint8ClampedArray::create(arrayBuffer, byteOffset, length).get()); + arrayBufferView = toJS(m_exec, m_globalObject, Uint8ClampedArray::create(WTFMove(arrayBuffer), byteOffset, length).get()); return true; case Int16ArrayTag: - arrayBufferView = getJSValue(Int16Array::create(arrayBuffer, byteOffset, length).get()); + arrayBufferView = toJS(m_exec, m_globalObject, Int16Array::create(WTFMove(arrayBuffer), byteOffset, length).get()); return true; case Uint16ArrayTag: - arrayBufferView = getJSValue(Uint16Array::create(arrayBuffer, byteOffset, length).get()); + arrayBufferView = toJS(m_exec, m_globalObject, Uint16Array::create(WTFMove(arrayBuffer), byteOffset, length).get()); return true; case Int32ArrayTag: - arrayBufferView = getJSValue(Int32Array::create(arrayBuffer, byteOffset, length).get()); + arrayBufferView = toJS(m_exec, m_globalObject, Int32Array::create(WTFMove(arrayBuffer), byteOffset, length).get()); return true; case Uint32ArrayTag: - arrayBufferView = getJSValue(Uint32Array::create(arrayBuffer, byteOffset, length).get()); + arrayBufferView = toJS(m_exec, m_globalObject, Uint32Array::create(WTFMove(arrayBuffer), byteOffset, length).get()); return true; case Float32ArrayTag: - arrayBufferView = getJSValue(Float32Array::create(arrayBuffer, byteOffset, length).get()); + arrayBufferView = toJS(m_exec, m_globalObject, Float32Array::create(WTFMove(arrayBuffer), byteOffset, length).get()); return true; case Float64ArrayTag: - arrayBufferView = getJSValue(Float64Array::create(arrayBuffer, byteOffset, length).get()); + arrayBufferView = toJS(m_exec, m_globalObject, Float64Array::create(WTFMove(arrayBuffer), byteOffset, length).get()); return true; default: return false; @@ -1884,7 +2015,7 @@ private: return true; } - bool readHMACKey(bool extractable, CryptoKeyUsage usages, RefPtr<CryptoKey>& result) + bool readHMACKey(bool extractable, CryptoKeyUsageBitmap usages, RefPtr<CryptoKey>& result) { Vector<uint8_t> keyData; if (!read(keyData)) @@ -1896,7 +2027,7 @@ private: return true; } - bool readAESKey(bool extractable, CryptoKeyUsage usages, RefPtr<CryptoKey>& result) + bool readAESKey(bool extractable, CryptoKeyUsageBitmap usages, RefPtr<CryptoKey>& result) { CryptoAlgorithmIdentifier algorithm; if (!read(algorithm)) @@ -1910,7 +2041,7 @@ private: return true; } - bool readRSAKey(bool extractable, CryptoKeyUsage usages, RefPtr<CryptoKey>& result) + bool readRSAKey(bool extractable, CryptoKeyUsageBitmap usages, RefPtr<CryptoKey>& result) { CryptoAlgorithmIdentifier algorithm; if (!read(algorithm)) @@ -1936,10 +2067,8 @@ private: if (type == CryptoKeyAsymmetricTypeSubtag::Public) { auto keyData = CryptoKeyDataRSAComponents::createPublic(modulus, exponent); - auto key = CryptoKeyRSA::create(algorithm, *keyData, extractable, usages); - if (isRestrictedToHash) - key->restrictToHash(hash); - result = std::move(key); + auto key = CryptoKeyRSA::create(algorithm, hash, isRestrictedToHash, *keyData, extractable, usages); + result = WTFMove(key); return true; } @@ -1953,10 +2082,8 @@ private: if (!primeCount) { auto keyData = CryptoKeyDataRSAComponents::createPrivate(modulus, exponent, privateExponent); - auto key = CryptoKeyRSA::create(algorithm, *keyData, extractable, usages); - if (isRestrictedToHash) - key->restrictToHash(hash); - result = std::move(key); + auto key = CryptoKeyRSA::create(algorithm, hash, isRestrictedToHash, *keyData, extractable, usages); + result = WTFMove(key); return true; } @@ -1987,15 +2114,17 @@ private: } auto keyData = CryptoKeyDataRSAComponents::createPrivateWithAdditionalData(modulus, exponent, privateExponent, firstPrimeInfo, secondPrimeInfo, otherPrimeInfos); - auto key = CryptoKeyRSA::create(algorithm, *keyData, extractable, usages); - if (isRestrictedToHash) - key->restrictToHash(hash); - result = std::move(key); + auto key = CryptoKeyRSA::create(algorithm, hash, isRestrictedToHash, *keyData, extractable, usages); + result = WTFMove(key); return true; } bool readCryptoKey(JSValue& cryptoKey) { + uint32_t keyFormatVersion; + if (!read(keyFormatVersion) || keyFormatVersion > currentKeyFormatVersion) + return false; + int32_t extractable; if (!read(extractable)) return false; @@ -2004,7 +2133,7 @@ private: if (!read(usagesCount)) return false; - CryptoKeyUsage usages = 0; + CryptoKeyUsageBitmap usages = 0; for (uint32_t i = 0; i < usagesCount; ++i) { CryptoKeyUsageTag usage; if (!read(usage)) @@ -2066,6 +2195,12 @@ private: return toJS(m_exec, jsCast<JSDOMGlobalObject*>(m_globalObject), nativeObj); } + template<class T> + JSValue getJSValue(T& nativeObj) + { + return getJSValue(&nativeObj); + } + JSValue readTerminal() { SerializationTag tag = readTag(); @@ -2132,29 +2267,29 @@ private: unsigned length = 0; if (!read(length)) return JSValue(); - RefPtr<FileList> result = FileList::create(); + Vector<RefPtr<File>> files; for (unsigned i = 0; i < length; i++) { RefPtr<File> file; if (!readFile(file)) return JSValue(); if (m_isDOMGlobalObject) - result->append(file.get()); + files.append(WTFMove(file)); } if (!m_isDOMGlobalObject) return jsNull(); - return getJSValue(result.get()); + return getJSValue(FileList::create(WTFMove(files)).get()); } case ImageDataTag: { - int32_t width; + uint32_t width; if (!read(width)) return JSValue(); - int32_t height; + uint32_t height; if (!read(height)) return JSValue(); uint32_t length; if (!read(length)) return JSValue(); - if (m_end < ((uint8_t*)0) + length || m_ptr > m_end - length) { + if (static_cast<uint32_t>(m_end - m_ptr) < length) { fail(); return JSValue(); } @@ -2162,8 +2297,17 @@ private: m_ptr += length; return jsNull(); } - RefPtr<ImageData> result = ImageData::create(IntSize(width, height)); - memcpy(result->data()->data(), m_ptr, length); + IntSize imageSize(width, height); + RELEASE_ASSERT(!length || (imageSize.area() * 4).unsafeGet() <= length); + RefPtr<ImageData> result = ImageData::create(imageSize); + if (!result) { + fail(); + return JSValue(); + } + if (length) + memcpy(result->data()->data(), m_ptr, length); + else + result->data()->zeroFill(); m_ptr += length; return getJSValue(result.get()); } @@ -2179,7 +2323,7 @@ private: return JSValue(); if (!m_isDOMGlobalObject) return jsNull(); - return getJSValue(Blob::create(URL(URL(), url->string()), type->string(), size).get()); + return getJSValue(Blob::deserialize(URL(URL(), url->string()), type->string(), size, blobFilePathForBlobURL(url->string())).get()); } case StringTag: { CachedStringRef cachedString; @@ -2227,11 +2371,11 @@ private: case MessagePortReferenceTag: { uint32_t index; bool indexSuccessfullyRead = read(index); - if (!indexSuccessfullyRead || !m_messagePorts || index >= m_messagePorts->size()) { + if (!indexSuccessfullyRead || index >= m_messagePorts.size()) { fail(); return JSValue(); } - return getJSValue(m_messagePorts->at(index).get()); + return getJSValue(m_messagePorts[index].get()); } case ArrayBufferTag: { RefPtr<ArrayBuffer> arrayBuffer; @@ -2239,7 +2383,14 @@ private: fail(); return JSValue(); } - JSValue result = getJSValue(arrayBuffer.get()); + Structure* structure = m_globalObject->arrayBufferStructure(arrayBuffer->sharingMode()); + // A crazy RuntimeFlags mismatch could mean that we are not equipped to handle shared + // array buffers while the sender is. In that case, we would see a null structure here. + if (!structure) { + fail(); + return JSValue(); + } + JSValue result = JSArrayBuffer::create(m_exec->vm(), structure, WTFMove(arrayBuffer)); m_gcBuffer.append(result); return result; } @@ -2252,13 +2403,27 @@ private: } if (!m_arrayBuffers[index]) - m_arrayBuffers[index] = ArrayBuffer::create(m_arrayBufferContents->at(index)); + m_arrayBuffers[index] = ArrayBuffer::create(WTFMove(m_arrayBufferContents->at(index))); return getJSValue(m_arrayBuffers[index].get()); } + case SharedArrayBufferTag: { + uint32_t index = UINT_MAX; + bool indexSuccessfullyRead = read(index); + if (!indexSuccessfullyRead || !m_sharedBuffers || index >= m_sharedBuffers->size()) { + fail(); + return JSValue(); + } + + RELEASE_ASSERT(m_sharedBuffers->at(index)); + RefPtr<ArrayBuffer> buffer = ArrayBuffer::create(WTFMove(m_sharedBuffers->at(index))); + JSValue result = getJSValue(buffer.get()); + m_gcBuffer.append(result); + return result; + } case ArrayBufferViewTag: { JSValue arrayBufferView; - if (!readArrayBufferView(arrayBufferView)) { + if (!readArrayBufferView(m_exec->vm(), arrayBufferView)) { fail(); return JSValue(); } @@ -2267,8 +2432,20 @@ private: } #if ENABLE(SUBTLE_CRYPTO) case CryptoKeyTag: { + Vector<uint8_t> wrappedKey; + if (!read(wrappedKey)) { + fail(); + return JSValue(); + } + Vector<uint8_t> serializedKey; + if (!unwrapCryptoKey(m_exec, wrappedKey, serializedKey)) { + fail(); + return JSValue(); + } JSValue cryptoKey; - if (!readCryptoKey(cryptoKey)) { + Vector<RefPtr<MessagePort>> dummyMessagePorts; + CloneDeserializer rawKeyDeserializer(m_exec, m_globalObject, dummyMessagePorts, nullptr, serializedKey); + if (!rawKeyDeserializer.readCryptoKey(cryptoKey)) { fail(); return JSValue(); } @@ -2282,9 +2459,10 @@ private: } } - bool consumeMapDataTerminationIfPossible() + template<SerializationTag Tag> + bool consumeCollectionDataTerminationIfPossible() { - if (readTag() == NonMapPropertiesTag) + if (readTag() == Tag) return true; m_ptr--; return false; @@ -2296,18 +2474,36 @@ private: const uint8_t* m_end; unsigned m_version; Vector<CachedString> m_constantPool; - MessagePortArray* m_messagePorts; + Vector<RefPtr<MessagePort>>& m_messagePorts; ArrayBufferContentsArray* m_arrayBufferContents; - ArrayBufferArray m_arrayBuffers; + Vector<RefPtr<JSC::ArrayBuffer>> m_arrayBuffers; + Vector<String> m_blobURLs; + Vector<String> m_blobFilePaths; + ArrayBufferContentsArray* m_sharedBuffers; + + String blobFilePathForBlobURL(const String& blobURL) + { + size_t i = 0; + for (; i < m_blobURLs.size(); ++i) { + if (m_blobURLs[i] == blobURL) + break; + } + + return i < m_blobURLs.size() ? m_blobFilePaths[i] : String(); + } }; DeserializationResult CloneDeserializer::deserialize() { + VM& vm = m_exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + Vector<uint32_t, 16> indexStack; Vector<Identifier, 16> propertyNameStack; Vector<JSObject*, 32> outputObjectStack; - Vector<JSValue, 4> keyStack; - Vector<MapData*, 4> mapDataStack; + Vector<JSValue, 4> mapKeyStack; + Vector<JSMap*, 4> mapStack; + Vector<JSSet*, 4> setStack; Vector<WalkerState, 16> stateStack; WalkerState state = StateUnknown; JSValue outValue; @@ -2322,6 +2518,8 @@ DeserializationResult CloneDeserializer::deserialize() goto error; } JSArray* outArray = constructEmptyArray(m_exec, 0, m_globalObject, length); + if (UNLIKELY(scope.exception())) + goto error; m_gcBuffer.append(outArray); outputObjectStack.append(outArray); } @@ -2361,7 +2559,7 @@ DeserializationResult CloneDeserializer::deserialize() objectStartState: case ObjectStartState: { if (outputObjectStack.size() > maximumFilterRecursion) - return std::make_pair(JSValue(), StackOverflowError); + return std::make_pair(JSValue(), SerializationReturnCode::StackOverflowError); JSObject* outObject = constructEmptyObject(m_exec, m_globalObject->objectPrototype()); m_gcBuffer.append(outObject); outputObjectStack.append(outObject); @@ -2382,11 +2580,11 @@ DeserializationResult CloneDeserializer::deserialize() } if (JSValue terminal = readTerminal()) { - putProperty(outputObjectStack.last(), Identifier(m_exec, cachedString->string()), terminal); + putProperty(outputObjectStack.last(), Identifier::fromString(m_exec, cachedString->string()), terminal); goto objectStartVisitMember; } stateStack.append(ObjectEndVisitMember); - propertyNameStack.append(Identifier(m_exec, cachedString->string())); + propertyNameStack.append(Identifier::fromString(m_exec, cachedString->string())); goto stateUnknown; } case ObjectEndVisitMember: { @@ -2396,45 +2594,61 @@ DeserializationResult CloneDeserializer::deserialize() } mapObjectStartState: { if (outputObjectStack.size() > maximumFilterRecursion) - return std::make_pair(JSValue(), StackOverflowError); - JSMap* map = JSMap::create(m_exec->vm(), m_globalObject->mapStructure()); + return std::make_pair(JSValue(), SerializationReturnCode::StackOverflowError); + JSMap* map = JSMap::create(m_exec, m_exec->vm(), m_globalObject->mapStructure()); + if (UNLIKELY(scope.exception())) + goto error; m_gcBuffer.append(map); outputObjectStack.append(map); - MapData* mapData = map->mapData(); - mapDataStack.append(mapData); - goto mapDataStartVisitEntry; - } - setObjectStartState: { - if (outputObjectStack.size() > maximumFilterRecursion) - return std::make_pair(JSValue(), StackOverflowError); - JSSet* set = JSSet::create(m_exec->vm(), m_globalObject->setStructure()); - m_gcBuffer.append(set); - outputObjectStack.append(set); - MapData* mapData = set->mapData(); - mapDataStack.append(mapData); + mapStack.append(map); goto mapDataStartVisitEntry; } mapDataStartVisitEntry: case MapDataStartVisitEntry: { - if (consumeMapDataTerminationIfPossible()) { - mapDataStack.removeLast(); + if (consumeCollectionDataTerminationIfPossible<NonMapPropertiesTag>()) { + mapStack.removeLast(); goto objectStartVisitMember; } stateStack.append(MapDataEndVisitKey); goto stateUnknown; } - case MapDataEndVisitKey: { - keyStack.append(outValue); + mapKeyStack.append(outValue); stateStack.append(MapDataEndVisitValue); goto stateUnknown; } - case MapDataEndVisitValue: { - mapDataStack.last()->set(m_exec, keyStack.last(), outValue); - keyStack.removeLast(); + mapStack.last()->set(m_exec, mapKeyStack.last(), outValue); + mapKeyStack.removeLast(); goto mapDataStartVisitEntry; } + + setObjectStartState: { + if (outputObjectStack.size() > maximumFilterRecursion) + return std::make_pair(JSValue(), SerializationReturnCode::StackOverflowError); + JSSet* set = JSSet::create(m_exec, m_exec->vm(), m_globalObject->setStructure()); + if (UNLIKELY(scope.exception())) + goto error; + m_gcBuffer.append(set); + outputObjectStack.append(set); + setStack.append(set); + goto setDataStartVisitEntry; + } + setDataStartVisitEntry: + case SetDataStartVisitEntry: { + if (consumeCollectionDataTerminationIfPossible<NonSetPropertiesTag>()) { + setStack.removeLast(); + goto objectStartVisitMember; + } + stateStack.append(SetDataEndVisitKey); + goto stateUnknown; + } + case SetDataEndVisitKey: { + JSSet* set = setStack.last(); + set->add(m_exec, outValue); + goto setDataStartVisitEntry; + } + stateUnknown: case StateUnknown: if (JSValue terminal = readTerminal()) { @@ -2460,63 +2674,39 @@ DeserializationResult CloneDeserializer::deserialize() } ASSERT(outValue); ASSERT(!m_failed); - return std::make_pair(outValue, SuccessfullyCompleted); + return std::make_pair(outValue, SerializationReturnCode::SuccessfullyCompleted); error: fail(); - return std::make_pair(JSValue(), ValidationError); -} - -void SerializedScriptValue::addBlobURL(const String& string) -{ - m_blobURLs.append(Vector<uint16_t>()); - m_blobURLs.last().reserveCapacity(string.length()); - for (size_t i = 0; i < string.length(); i++) - m_blobURLs.last().append(string.characterAt(i)); - m_blobURLs.last().resize(m_blobURLs.last().size()); + return std::make_pair(JSValue(), SerializationReturnCode::ValidationError); } SerializedScriptValue::~SerializedScriptValue() { } -SerializedScriptValue::SerializedScriptValue(const Vector<uint8_t>& buffer) - : m_data(buffer) +SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>&& buffer) + : m_data(WTFMove(buffer)) { } -SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer) +SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>&& buffer, const Vector<String>& blobURLs, std::unique_ptr<ArrayBufferContentsArray> arrayBufferContentsArray, std::unique_ptr<ArrayBufferContentsArray> sharedBufferContentsArray) + : m_data(WTFMove(buffer)) + , m_arrayBufferContentsArray(WTFMove(arrayBufferContentsArray)) + , m_sharedBufferContentsArray(WTFMove(sharedBufferContentsArray)) { - m_data.swap(buffer); + // Since this SerializedScriptValue is meant to be passed between threads, its String data members + // need to be isolatedCopies so we don't run into thread safety issues for the StringImpls. + m_blobURLs.reserveInitialCapacity(blobURLs.size()); + for (auto& url : blobURLs) + m_blobURLs.uncheckedAppend(url.isolatedCopy()); } -SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer, Vector<String>& blobURLs) +static ExceptionOr<std::unique_ptr<ArrayBufferContentsArray>> transferArrayBuffers(VM& vm, const Vector<RefPtr<JSC::ArrayBuffer>>& arrayBuffers) { - m_data.swap(buffer); - for (auto& string : blobURLs) - addBlobURL(string); -} + if (arrayBuffers.isEmpty()) + return nullptr; -SerializedScriptValue::SerializedScriptValue(Vector<uint8_t>& buffer, Vector<String>& blobURLs, PassOwnPtr<ArrayBufferContentsArray> arrayBufferContentsArray) - : m_arrayBufferContentsArray(arrayBufferContentsArray) -{ - m_data.swap(buffer); - for (auto& string : blobURLs) - addBlobURL(string); -} - -PassOwnPtr<SerializedScriptValue::ArrayBufferContentsArray> SerializedScriptValue::transferArrayBuffers( - ExecState* exec, ArrayBufferArray& arrayBuffers, SerializationReturnCode& code) -{ - for (size_t i = 0; i < arrayBuffers.size(); i++) { - if (arrayBuffers[i]->isNeutered()) { - code = ValidationError; - return nullptr; - } - } - - OwnPtr<ArrayBufferContentsArray> contents = adoptPtr(new ArrayBufferContentsArray(arrayBuffers.size())); - Vector<Ref<DOMWrapperWorld>> worlds; - static_cast<WebCoreJSClientData*>(exec->vm().clientData)->getAllWorlds(worlds); + auto contents = std::make_unique<ArrayBufferContentsArray>(arrayBuffers.size()); HashSet<JSC::ArrayBuffer*> visited; for (size_t arrayBufferIndex = 0; arrayBufferIndex < arrayBuffers.size(); arrayBufferIndex++) { @@ -2524,207 +2714,255 @@ PassOwnPtr<SerializedScriptValue::ArrayBufferContentsArray> SerializedScriptValu continue; visited.add(arrayBuffers[arrayBufferIndex].get()); - bool result = arrayBuffers[arrayBufferIndex]->transfer(contents->at(arrayBufferIndex)); - if (!result) { - code = ValidationError; - return nullptr; - } + bool result = arrayBuffers[arrayBufferIndex]->transferTo(vm, contents->at(arrayBufferIndex)); + if (!result) + return Exception { TypeError }; + } + + return WTFMove(contents); +} + +static void maybeThrowExceptionIfSerializationFailed(ExecState& state, SerializationReturnCode code) +{ + auto& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + + switch (code) { + case SerializationReturnCode::SuccessfullyCompleted: + break; + case SerializationReturnCode::StackOverflowError: + throwException(&state, scope, createStackOverflowError(&state)); + break; + case SerializationReturnCode::ValidationError: + throwTypeError(&state, scope, ASCIILiteral("Unable to deserialize data.")); + break; + case SerializationReturnCode::DataCloneError: + throwDataCloneError(state, scope); + break; + case SerializationReturnCode::ExistingExceptionError: + case SerializationReturnCode::UnspecifiedError: + break; + case SerializationReturnCode::InterruptedExecutionError: + ASSERT_NOT_REACHED(); } - return contents.release(); } +static Exception exceptionForSerializationFailure(SerializationReturnCode code) +{ + ASSERT(code != SerializationReturnCode::SuccessfullyCompleted); + + switch (code) { + case SerializationReturnCode::StackOverflowError: + return Exception { StackOverflowError }; + case SerializationReturnCode::ValidationError: + return Exception { TypeError }; + case SerializationReturnCode::DataCloneError: + return Exception { DATA_CLONE_ERR }; + case SerializationReturnCode::ExistingExceptionError: + return Exception { ExistingExceptionError }; + case SerializationReturnCode::UnspecifiedError: + return Exception { TypeError }; + case SerializationReturnCode::SuccessfullyCompleted: + case SerializationReturnCode::InterruptedExecutionError: + ASSERT_NOT_REACHED(); + return Exception { TypeError }; + } + ASSERT_NOT_REACHED(); + return Exception { TypeError }; +} -PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(ExecState* exec, JSValue value, - MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, - SerializationErrorMode throwExceptions) +RefPtr<SerializedScriptValue> SerializedScriptValue::create(ExecState& exec, JSValue value, SerializationErrorMode throwExceptions) { Vector<uint8_t> buffer; Vector<String> blobURLs; - SerializationReturnCode code = CloneSerializer::serialize(exec, value, messagePorts, arrayBuffers, blobURLs, buffer); - - OwnPtr<ArrayBufferContentsArray> arrayBufferContentsArray; + Vector<RefPtr<MessagePort>> dummyMessagePorts; + Vector<RefPtr<JSC::ArrayBuffer>> dummyArrayBuffers; + ArrayBufferContentsArray dummySharedBuffers; + auto code = CloneSerializer::serialize(&exec, value, dummyMessagePorts, dummyArrayBuffers, blobURLs, buffer, SerializationContext::Default, dummySharedBuffers); - if (arrayBuffers && serializationDidCompleteSuccessfully(code)) - arrayBufferContentsArray = transferArrayBuffers(exec, *arrayBuffers, code); - - if (throwExceptions == Throwing) + if (throwExceptions == SerializationErrorMode::Throwing) maybeThrowExceptionIfSerializationFailed(exec, code); - if (!serializationDidCompleteSuccessfully(code)) - return 0; + if (code != SerializationReturnCode::SuccessfullyCompleted) + return nullptr; - return adoptRef(new SerializedScriptValue(buffer, blobURLs, arrayBufferContentsArray.release())); + return adoptRef(*new SerializedScriptValue(WTFMove(buffer), blobURLs, nullptr, nullptr)); } -PassRefPtr<SerializedScriptValue> SerializedScriptValue::create() +ExceptionOr<Ref<SerializedScriptValue>> SerializedScriptValue::create(ExecState& state, JSValue value, Vector<JSC::Strong<JSC::JSObject>>&& transferList, Vector<RefPtr<MessagePort>>& messagePorts, SerializationContext context) { - Vector<uint8_t> buffer; - return adoptRef(new SerializedScriptValue(buffer)); -} + VM& vm = state.vm(); + Vector<RefPtr<JSC::ArrayBuffer>> arrayBuffers; + for (auto& transferable : transferList) { + if (auto arrayBuffer = toPossiblySharedArrayBuffer(vm, transferable.get())) { + if (arrayBuffer->isNeutered()) + return Exception { DATA_CLONE_ERR }; + if (arrayBuffer->isShared()) + return Exception { TypeError }; + arrayBuffers.append(WTFMove(arrayBuffer)); + continue; + } + if (auto port = JSMessagePort::toWrapped(vm, transferable.get())) { + // FIXME: This should check if the port is detached as per https://html.spec.whatwg.org/multipage/infrastructure.html#istransferable. + messagePorts.append(WTFMove(port)); + continue; + } + + return Exception { DATA_CLONE_ERR }; + } -PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(const String& string) -{ Vector<uint8_t> buffer; - if (!CloneSerializer::serialize(string, buffer)) - return 0; - return adoptRef(new SerializedScriptValue(buffer)); -} + Vector<String> blobURLs; + std::unique_ptr<ArrayBufferContentsArray> sharedBuffers = std::make_unique<ArrayBufferContentsArray>(); + auto code = CloneSerializer::serialize(&state, value, messagePorts, arrayBuffers, blobURLs, buffer, context, *sharedBuffers); -#if ENABLE(INDEXED_DATABASE) -PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSC::ExecState* exec, JSC::JSValue value) -{ - return SerializedScriptValue::create(exec, value, 0, 0); -} + if (code != SerializationReturnCode::SuccessfullyCompleted) + return exceptionForSerializationFailure(code); -PassRefPtr<SerializedScriptValue> SerializedScriptValue::numberValue(double value) -{ - Vector<uint8_t> buffer; - CloneSerializer::serializeNumber(value, buffer); - return adoptRef(new SerializedScriptValue(buffer)); + auto arrayBufferContentsArray = transferArrayBuffers(vm, arrayBuffers); + if (arrayBufferContentsArray.hasException()) + return arrayBufferContentsArray.releaseException(); + + return adoptRef(*new SerializedScriptValue(WTFMove(buffer), blobURLs, arrayBufferContentsArray.releaseReturnValue(), context == SerializationContext::WorkerPostMessage ? WTFMove(sharedBuffers) : nullptr)); } -JSValue SerializedScriptValue::deserialize(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject) +RefPtr<SerializedScriptValue> SerializedScriptValue::create(StringView string) { - return deserialize(exec, globalObject, 0); + Vector<uint8_t> buffer; + if (!CloneSerializer::serialize(string, buffer)) + return nullptr; + return adoptRef(*new SerializedScriptValue(WTFMove(buffer))); } -#endif -PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSContextRef originContext, JSValueRef apiValue, - MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, - JSValueRef* exception) +RefPtr<SerializedScriptValue> SerializedScriptValue::create(JSContextRef originContext, JSValueRef apiValue, JSValueRef* exception) { ExecState* exec = toJS(originContext); - APIEntryShim entryShim(exec); + VM& vm = exec->vm(); + JSLockHolder locker(vm); + auto scope = DECLARE_CATCH_SCOPE(vm); + JSValue value = toJS(exec, apiValue); - RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(exec, value, messagePorts, arrayBuffers); - if (exec->hadException()) { + RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(*exec, value); + if (UNLIKELY(scope.exception())) { if (exception) - *exception = toRef(exec, exec->exception()); - exec->clearException(); - return 0; + *exception = toRef(exec, scope.exception()->value()); + scope.clearException(); + return nullptr; } ASSERT(serializedValue); - return serializedValue.release(); + return serializedValue; } -PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(JSContextRef originContext, JSValueRef apiValue, - JSValueRef* exception) +String SerializedScriptValue::toString() { - return create(originContext, apiValue, 0, 0, exception); + return CloneDeserializer::deserializeString(m_data); } -String SerializedScriptValue::toString() +JSValue SerializedScriptValue::deserialize(ExecState& exec, JSGlobalObject* globalObject, SerializationErrorMode throwExceptions) { - return CloneDeserializer::deserializeString(m_data); + Vector<RefPtr<MessagePort>> dummyMessagePorts; + return deserialize(exec, globalObject, dummyMessagePorts, throwExceptions); } -JSValue SerializedScriptValue::deserialize(ExecState* exec, JSGlobalObject* globalObject, - MessagePortArray* messagePorts, SerializationErrorMode throwExceptions) +JSValue SerializedScriptValue::deserialize(ExecState& exec, JSGlobalObject* globalObject, Vector<RefPtr<MessagePort>>& messagePorts, SerializationErrorMode throwExceptions) { - DeserializationResult result = CloneDeserializer::deserialize(exec, globalObject, messagePorts, - m_arrayBufferContentsArray.get(), m_data); - if (throwExceptions == Throwing) - maybeThrowExceptionIfSerializationFailed(exec, result.second); - return result.first; + Vector<String> dummyBlobs; + Vector<String> dummyPaths; + return deserialize(exec, globalObject, messagePorts, dummyBlobs, dummyPaths, throwExceptions); } -#if ENABLE(INSPECTOR) -Deprecated::ScriptValue SerializedScriptValue::deserializeForInspector(JSC::ExecState* scriptState) +JSValue SerializedScriptValue::deserialize(ExecState& exec, JSGlobalObject* globalObject, Vector<RefPtr<MessagePort>>& messagePorts, const Vector<String>& blobURLs, const Vector<String>& blobFilePaths, SerializationErrorMode throwExceptions) { - JSValue value = deserialize(scriptState, scriptState->lexicalGlobalObject(), 0); - return Deprecated::ScriptValue(scriptState->vm(), value); + DeserializationResult result = CloneDeserializer::deserialize(&exec, globalObject, messagePorts, m_arrayBufferContentsArray.get(), m_data, blobURLs, blobFilePaths, m_sharedBufferContentsArray.get()); + if (throwExceptions == SerializationErrorMode::Throwing) + maybeThrowExceptionIfSerializationFailed(exec, result.second); + return result.first ? result.first : jsNull(); } -#endif -JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, JSValueRef* exception, MessagePortArray* messagePorts) +JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, JSValueRef* exception) { ExecState* exec = toJS(destinationContext); - APIEntryShim entryShim(exec); - JSValue value = deserialize(exec, exec->lexicalGlobalObject(), messagePorts); - if (exec->hadException()) { + VM& vm = exec->vm(); + JSLockHolder locker(vm); + auto scope = DECLARE_CATCH_SCOPE(vm); + + JSValue value = deserialize(*exec, exec->lexicalGlobalObject()); + if (UNLIKELY(scope.exception())) { if (exception) - *exception = toRef(exec, exec->exception()); - exec->clearException(); - return 0; + *exception = toRef(exec, scope.exception()->value()); + scope.clearException(); + return nullptr; } ASSERT(value); return toRef(exec, value); } - -JSValueRef SerializedScriptValue::deserialize(JSContextRef destinationContext, JSValueRef* exception) +Ref<SerializedScriptValue> SerializedScriptValue::nullValue() { - return deserialize(destinationContext, exception, 0); + return adoptRef(*new SerializedScriptValue(Vector<uint8_t>())); } -PassRefPtr<SerializedScriptValue> SerializedScriptValue::nullValue() +uint32_t SerializedScriptValue::wireFormatVersion() { - return SerializedScriptValue::create(); + return CurrentVersion; } -PassRefPtr<SerializedScriptValue> SerializedScriptValue::undefinedValue() +#if ENABLE(INDEXED_DATABASE) +Vector<String> SerializedScriptValue::blobURLsIsolatedCopy() const { - Vector<uint8_t> buffer; - CloneSerializer::serializeUndefined(buffer); - return adoptRef(new SerializedScriptValue(buffer)); -} + Vector<String> result; + result.reserveInitialCapacity(m_blobURLs.size()); + for (auto& url : m_blobURLs) + result.uncheckedAppend(url.isolatedCopy()); -PassRefPtr<SerializedScriptValue> SerializedScriptValue::booleanValue(bool value) -{ - Vector<uint8_t> buffer; - CloneSerializer::serializeBoolean(value, buffer); - return adoptRef(new SerializedScriptValue(buffer)); + return result; } -PassRefPtr<SerializedScriptValue> SerializedScriptValue::serialize(const Deprecated::ScriptValue& value, JSC::ExecState* scriptState, SerializationErrorMode throwExceptions) +void SerializedScriptValue::writeBlobsToDiskForIndexedDB(WTF::Function<void (const IDBValue&)>&& completionHandler) { - return SerializedScriptValue::create(scriptState, value.jsValue(), nullptr, nullptr, throwExceptions); -} + ASSERT(isMainThread()); + ASSERT(hasBlobURLs()); -PassRefPtr<SerializedScriptValue> SerializedScriptValue::serialize(const Deprecated::ScriptValue& value, JSC::ExecState* scriptState, MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, bool& didThrow) -{ - RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(scriptState, value.jsValue(), messagePorts, arrayBuffers); - didThrow = scriptState->hadException(); - return serializedValue.release(); -} + RefPtr<SerializedScriptValue> protectedThis(this); + blobRegistry().writeBlobsToTemporaryFiles(m_blobURLs, [completionHandler = WTFMove(completionHandler), this, protectedThis = WTFMove(protectedThis)](auto& blobFilePaths) { + ASSERT(isMainThread()); -Deprecated::ScriptValue SerializedScriptValue::deserialize(JSC::ExecState* scriptState, SerializedScriptValue* value, SerializationErrorMode throwExceptions) -{ - return Deprecated::ScriptValue(scriptState->vm(), value->deserialize(scriptState, scriptState->lexicalGlobalObject(), 0, throwExceptions)); -} + if (blobFilePaths.isEmpty()) { + // We should have successfully written blobs to temporary files. + // If we failed, then we can't successfully store this record. + completionHandler({ }); + return; + } -void SerializedScriptValue::maybeThrowExceptionIfSerializationFailed(ExecState* exec, SerializationReturnCode code) -{ - if (code == SuccessfullyCompleted) - return; - - switch (code) { - case StackOverflowError: - exec->vm().throwException(exec, createStackOverflowError(exec)); - break; - case ValidationError: - exec->vm().throwException(exec, createTypeError(exec, "Unable to deserialize data.")); - break; - case DataCloneError: - setDOMException(exec, DATA_CLONE_ERR); - break; - case ExistingExceptionError: - break; - case UnspecifiedError: - break; - default: - ASSERT_NOT_REACHED(); - } + ASSERT(m_blobURLs.size() == blobFilePaths.size()); + + completionHandler({ *this, m_blobURLs, blobFilePaths }); + }); } -bool SerializedScriptValue::serializationDidCompleteSuccessfully(SerializationReturnCode code) +IDBValue SerializedScriptValue::writeBlobsToDiskForIndexedDBSynchronously() { - return (code == SuccessfullyCompleted); -} + ASSERT(!isMainThread()); -uint32_t SerializedScriptValue::wireFormatVersion() -{ - return CurrentVersion; -} + IDBValue value; + Lock lock; + Condition condition; + lock.lock(); + + RunLoop::main().dispatch([this, conditionPtr = &condition, valuePtr = &value] { + writeBlobsToDiskForIndexedDB([conditionPtr, valuePtr](const IDBValue& result) { + ASSERT(isMainThread()); + valuePtr->setAsIsolatedCopy(result); + + conditionPtr->notifyAll(); + }); + }); + condition.wait(lock); + + return value; } + +#endif // ENABLE(INDEXED_DATABASE) + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/SerializedScriptValue.h b/Source/WebCore/bindings/js/SerializedScriptValue.h index 37b31729a..1729011c4 100644 --- a/Source/WebCore/bindings/js/SerializedScriptValue.h +++ b/Source/WebCore/bindings/js/SerializedScriptValue.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2009, 2013, 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,10 +10,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -24,16 +24,14 @@ * */ -#ifndef SerializedScriptValue_h -#define SerializedScriptValue_h +#pragma once -#include "ScriptState.h" -#include <bindings/ScriptValue.h> +#include "ExceptionOr.h" #include <heap/Strong.h> #include <runtime/ArrayBuffer.h> #include <runtime/JSCJSValue.h> #include <wtf/Forward.h> -#include <wtf/PassRefPtr.h> +#include <wtf/Function.h> #include <wtf/RefCounted.h> #include <wtf/text/WTFString.h> @@ -42,96 +40,67 @@ typedef const struct OpaqueJSValue* JSValueRef; namespace WebCore { +class IDBValue; class MessagePort; -typedef Vector<RefPtr<MessagePort>, 1> MessagePortArray; -typedef Vector<RefPtr<JSC::ArrayBuffer>, 1> ArrayBufferArray; - -enum SerializationReturnCode { - SuccessfullyCompleted, - StackOverflowError, - InterruptedExecutionError, - ValidationError, - ExistingExceptionError, - DataCloneError, - UnspecifiedError -}; - -enum SerializationErrorMode { NonThrowing, Throwing }; - class SharedBuffer; +enum class SerializationReturnCode; -class SerializedScriptValue : -#if ENABLE(INDEXED_DATABASE) - public ThreadSafeRefCounted<SerializedScriptValue> { -#else - public RefCounted<SerializedScriptValue> { -#endif +enum class SerializationErrorMode { NonThrowing, Throwing }; +enum class SerializationContext { Default, WorkerPostMessage }; + +using ArrayBufferContentsArray = Vector<JSC::ArrayBufferContents>; + +class SerializedScriptValue : public ThreadSafeRefCounted<SerializedScriptValue> { public: - static PassRefPtr<SerializedScriptValue> create(JSC::ExecState*, JSC::JSValue, MessagePortArray*, ArrayBufferArray*, SerializationErrorMode = Throwing); - static PassRefPtr<SerializedScriptValue> create(JSContextRef, JSValueRef, MessagePortArray*, ArrayBufferArray*, JSValueRef* exception); - static PassRefPtr<SerializedScriptValue> create(JSContextRef, JSValueRef, JSValueRef* exception); + WEBCORE_EXPORT static RefPtr<SerializedScriptValue> create(JSC::ExecState&, JSC::JSValue, SerializationErrorMode = SerializationErrorMode::Throwing); + + WEBCORE_EXPORT static ExceptionOr<Ref<SerializedScriptValue>> create(JSC::ExecState&, JSC::JSValue, Vector<JSC::Strong<JSC::JSObject>>&& transfer, Vector<RefPtr<MessagePort>>&, SerializationContext = SerializationContext::Default); - static PassRefPtr<SerializedScriptValue> create(const String&); - static PassRefPtr<SerializedScriptValue> adopt(Vector<uint8_t>& buffer) + WEBCORE_EXPORT static RefPtr<SerializedScriptValue> create(StringView); + static Ref<SerializedScriptValue> adopt(Vector<uint8_t>&& buffer) { - return adoptRef(new SerializedScriptValue(buffer)); + return adoptRef(*new SerializedScriptValue(WTFMove(buffer))); } - static PassRefPtr<SerializedScriptValue> create(); - static PassRefPtr<SerializedScriptValue> nullValue(); - static PassRefPtr<SerializedScriptValue> undefinedValue(); - static PassRefPtr<SerializedScriptValue> booleanValue(bool value); + static Ref<SerializedScriptValue> nullValue(); - static PassRefPtr<SerializedScriptValue> serialize(const Deprecated::ScriptValue&, JSC::ExecState*, SerializationErrorMode = Throwing); - static PassRefPtr<SerializedScriptValue> serialize(const Deprecated::ScriptValue&, JSC::ExecState*, MessagePortArray*, ArrayBufferArray*, bool&); - static Deprecated::ScriptValue deserialize(JSC::ExecState*, SerializedScriptValue*, SerializationErrorMode = Throwing); + WEBCORE_EXPORT JSC::JSValue deserialize(JSC::ExecState&, JSC::JSGlobalObject*, SerializationErrorMode = SerializationErrorMode::Throwing); + WEBCORE_EXPORT JSC::JSValue deserialize(JSC::ExecState&, JSC::JSGlobalObject*, Vector<RefPtr<MessagePort>>&, SerializationErrorMode = SerializationErrorMode::Throwing); + JSC::JSValue deserialize(JSC::ExecState&, JSC::JSGlobalObject*, Vector<RefPtr<MessagePort>>&, const Vector<String>& blobURLs, const Vector<String>& blobFilePaths, SerializationErrorMode = SerializationErrorMode::Throwing); static uint32_t wireFormatVersion(); String toString(); - - JSC::JSValue deserialize(JSC::ExecState*, JSC::JSGlobalObject*, MessagePortArray*, SerializationErrorMode = Throwing); - JSValueRef deserialize(JSContextRef, JSValueRef* exception, MessagePortArray*); - JSValueRef deserialize(JSContextRef, JSValueRef* exception); -#if ENABLE(INSPECTOR) - Deprecated::ScriptValue deserializeForInspector(JSC::ExecState*); -#endif + // API implementation helpers. These don't expose special behavior for ArrayBuffers or MessagePorts. + WEBCORE_EXPORT static RefPtr<SerializedScriptValue> create(JSContextRef, JSValueRef, JSValueRef* exception); + WEBCORE_EXPORT JSValueRef deserialize(JSContextRef, JSValueRef* exception); const Vector<uint8_t>& data() const { return m_data; } bool hasBlobURLs() const { return !m_blobURLs.isEmpty(); } - void blobURLs(Vector<String>&) const; #if ENABLE(INDEXED_DATABASE) - static PassRefPtr<SerializedScriptValue> create(JSC::ExecState*, JSC::JSValue); - static PassRefPtr<SerializedScriptValue> numberValue(double value); - JSC::JSValue deserialize(JSC::ExecState*, JSC::JSGlobalObject*); -#endif + Vector<String> blobURLsIsolatedCopy() const; + void writeBlobsToDiskForIndexedDB(WTF::Function<void (const IDBValue&)>&& completionHandler); + IDBValue writeBlobsToDiskForIndexedDBSynchronously(); +#endif // ENABLE(INDEXED_DATABASE) - static PassRefPtr<SerializedScriptValue> createFromWireBytes(const Vector<uint8_t>& data) + static Ref<SerializedScriptValue> createFromWireBytes(Vector<uint8_t>&& data) { - return adoptRef(new SerializedScriptValue(data)); + return adoptRef(*new SerializedScriptValue(WTFMove(data))); } const Vector<uint8_t>& toWireBytes() const { return m_data; } - ~SerializedScriptValue(); + WEBCORE_EXPORT ~SerializedScriptValue(); private: - typedef Vector<JSC::ArrayBufferContents> ArrayBufferContentsArray; - static void maybeThrowExceptionIfSerializationFailed(JSC::ExecState*, SerializationReturnCode); - static bool serializationDidCompleteSuccessfully(SerializationReturnCode); - static PassOwnPtr<ArrayBufferContentsArray> transferArrayBuffers(JSC::ExecState*, ArrayBufferArray&, SerializationReturnCode&); - void addBlobURL(const String&); - - SerializedScriptValue(const Vector<unsigned char>&); - SerializedScriptValue(Vector<unsigned char>&); - SerializedScriptValue(Vector<unsigned char>&, Vector<String>& blobURLs); - SerializedScriptValue(Vector<unsigned char>&, Vector<String>& blobURLs, PassOwnPtr<ArrayBufferContentsArray>); + WEBCORE_EXPORT SerializedScriptValue(Vector<unsigned char>&&); + SerializedScriptValue(Vector<unsigned char>&&, const Vector<String>& blobURLs, std::unique_ptr<ArrayBufferContentsArray>, std::unique_ptr<ArrayBufferContentsArray> sharedBuffers); + Vector<unsigned char> m_data; - OwnPtr<ArrayBufferContentsArray> m_arrayBufferContentsArray; - Vector<Vector<uint16_t>> m_blobURLs; + std::unique_ptr<ArrayBufferContentsArray> m_arrayBufferContentsArray; + std::unique_ptr<ArrayBufferContentsArray> m_sharedBufferContentsArray; + Vector<String> m_blobURLs; }; } - -#endif // SerializedScriptValue_h diff --git a/Source/WebCore/bindings/js/StructuredClone.cpp b/Source/WebCore/bindings/js/StructuredClone.cpp new file mode 100644 index 000000000..4869ac0df --- /dev/null +++ b/Source/WebCore/bindings/js/StructuredClone.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2016 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. ``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 + * 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 "StructuredClone.h" + +#include "JSDOMBinding.h" +#include "JSDOMExceptionHandling.h" +#include <runtime/JSTypedArrays.h> + +using namespace JSC; + +namespace WebCore { + +EncodedJSValue JSC_HOST_CALL structuredCloneArrayBuffer(ExecState* state) +{ + ASSERT(state); + ASSERT(state->argumentCount()); + ASSERT(state->lexicalGlobalObject()); + + VM& vm = state->vm(); + auto* buffer = toUnsharedArrayBuffer(vm, state->uncheckedArgument(0)); + if (!buffer) { + auto scope = DECLARE_THROW_SCOPE(vm); + throwDataCloneError(*state, scope); + return { }; + } + return JSValue::encode(JSArrayBuffer::create(state->vm(), state->lexicalGlobalObject()->arrayBufferStructure(ArrayBufferSharingMode::Default), ArrayBuffer::tryCreate(buffer->data(), buffer->byteLength()))); +} + +EncodedJSValue JSC_HOST_CALL structuredCloneArrayBufferView(ExecState* state) +{ + ASSERT(state); + ASSERT(state->argumentCount()); + + JSValue value = state->uncheckedArgument(0); + VM& vm = state->vm(); + auto* bufferView = jsDynamicDowncast<JSArrayBufferView*>(vm, value); + ASSERT(bufferView); + + auto* buffer = bufferView->unsharedBuffer(); + if (!buffer) { + auto scope = DECLARE_THROW_SCOPE(vm); + throwDataCloneError(*state, scope); + return { }; + } + auto bufferClone = ArrayBuffer::tryCreate(buffer->data(), buffer->byteLength()); + + if (jsDynamicDowncast<JSInt8Array*>(vm, value)) + return JSValue::encode(JSInt8Array::create(state, bufferView->structure(), WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length())); + if (jsDynamicDowncast<JSInt16Array*>(vm, value)) + return JSValue::encode(JSInt16Array::create(state, bufferView->structure(), WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length())); + if (jsDynamicDowncast<JSInt32Array*>(vm, value)) + return JSValue::encode(JSInt32Array::create(state, bufferView->structure(), WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length())); + if (jsDynamicDowncast<JSUint8Array*>(vm, value)) + return JSValue::encode(JSUint8Array::create(state, bufferView->structure(), WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length())); + if (jsDynamicDowncast<JSUint8ClampedArray*>(vm, value)) + return JSValue::encode(JSUint8ClampedArray::create(state, bufferView->structure(), WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length())); + if (jsDynamicDowncast<JSUint16Array*>(vm, value)) + return JSValue::encode(JSUint16Array::create(state, bufferView->structure(), WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length())); + if (jsDynamicDowncast<JSUint32Array*>(vm, value)) + return JSValue::encode(JSUint32Array::create(state, bufferView->structure(), WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length())); + if (jsDynamicDowncast<JSFloat32Array*>(vm, value)) + return JSValue::encode(JSFloat32Array::create(state, bufferView->structure(), WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length())); + if (jsDynamicDowncast<JSFloat64Array*>(vm, value)) + return JSValue::encode(JSFloat64Array::create(state, bufferView->structure(), WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length())); + if (jsDynamicDowncast<JSDataView*>(vm, value)) + return JSValue::encode(JSDataView::create(state, bufferView->structure(), WTFMove(bufferClone), bufferView->byteOffset(), bufferView->length())); + + ASSERT_NOT_REACHED(); + return JSValue::encode(jsUndefined()); +} + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/JSHTMLInputElementCustom.h b/Source/WebCore/bindings/js/StructuredClone.h index f5222d24c..ea6d01b69 100644 --- a/Source/WebCore/bindings/js/JSHTMLInputElementCustom.h +++ b/Source/WebCore/bindings/js/StructuredClone.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2016 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -20,12 +20,18 @@ * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * */ -#ifndef JSHTMLInputElementCustom_h -#define JSHTMLInputElementCustom_h +namespace JSC { +using EncodedJSValue = int64_t; +class ExecState; +} + +namespace WebCore { -#include "JSHTMLInputElement.h" +JSC::EncodedJSValue JSC_HOST_CALL structuredCloneArrayBuffer(JSC::ExecState*); +JSC::EncodedJSValue JSC_HOST_CALL structuredCloneArrayBufferView(JSC::ExecState*); -#endif // JSHTMLInputElementCustom_h +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/WebCoreBuiltinNames.h b/Source/WebCore/bindings/js/WebCoreBuiltinNames.h new file mode 100644 index 000000000..8ab00bc07 --- /dev/null +++ b/Source/WebCore/bindings/js/WebCoreBuiltinNames.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2015, Canon 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. + * 3. Neither the name of Canon Inc. nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY CANON 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 CANON INC. AND 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. + */ + +#pragma once + +#include <builtins/BuiltinUtils.h> + +namespace WebCore { + +#define WEBCORE_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(macro)\ + macro(addTrack) \ + macro(appendFromJS) \ + macro(autoAllocateChunkSize) \ + macro(body) \ + macro(cancel) \ + macro(cloneForJS) \ + macro(closeRequested) \ + macro(closedPromiseCapability) \ + macro(consume) \ + macro(consumeChunk) \ + macro(controlledReadableStream) \ + macro(controller) \ + macro(createReadableStreamSource) \ + macro(disturbed) \ + macro(failureKind) \ + macro(fetchRequest) \ + macro(fillFromJS) \ + macro(finishConsumingStream) \ + macro(getUserMedia) \ + macro(getRemoteStreams) \ + macro(getSenders) \ + macro(getTracks) \ + macro(initializeWith) \ + macro(isDisturbed) \ + macro(isLoading) \ + macro(localStreams) \ + macro(makeThisTypeError) \ + macro(makeGetterTypeError) \ + macro(mediaStreamTrackConstraints) \ + macro(operations) \ + macro(ownerReadableStream) \ + macro(pendingPullIntos) \ + macro(privateGetStats) \ + macro(pull) \ + macro(pulling) \ + macro(pullAgain) \ + macro(queue) \ + macro(queuedAddIceCandidate) \ + macro(queuedCreateAnswer) \ + macro(queuedCreateOffer) \ + macro(queuedSetLocalDescription) \ + macro(queuedSetRemoteDescription) \ + macro(reader) \ + macro(readIntoRequests) \ + macro(readRequests) \ + macro(readableStreamController) \ + macro(readyPromiseCapability) \ + macro(removeTrack) \ + macro(responseCacheIsValid) \ + macro(retrieveResponse) \ + macro(response) \ + macro(setBody) \ + macro(setStatus) \ + macro(state) \ + macro(startConsumingStream) \ + macro(started) \ + macro(startedPromise) \ + macro(storedError) \ + macro(strategy) \ + macro(strategyHWM) \ + macro(streamClosed) \ + macro(streamClosing) \ + macro(streamErrored) \ + macro(streamReadable) \ + macro(streamWaiting) \ + macro(streamWritable) \ + macro(structuredCloneArrayBuffer) \ + macro(structuredCloneArrayBufferView) \ + macro(totalQueuedBytes) \ + macro(underlyingByteSource) \ + macro(underlyingSink) \ + macro(underlyingSource) \ + macro(writing) \ + macro(Headers) \ + macro(MediaStream) \ + macro(MediaStreamTrack) \ + macro(ReadableByteStreamController) \ + macro(ReadableStream) \ + macro(ReadableStreamDefaultController) \ + macro(ReadableStreamDefaultReader) \ + macro(Request) \ + macro(Response) \ + macro(RTCIceCandidate) \ + macro(RTCSessionDescription) \ + macro(XMLHttpRequest) + +class WebCoreBuiltinNames { +public: + explicit WebCoreBuiltinNames(JSC::VM* vm) + : m_vm(*vm) + WEBCORE_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_BUILTIN_NAMES) + { +#define EXPORT_NAME(name) m_vm.propertyNames->appendExternalName(name##PublicName(), name##PrivateName()); + WEBCORE_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(EXPORT_NAME) +#undef EXPORT_NAME + } + + WEBCORE_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(DECLARE_BUILTIN_IDENTIFIER_ACCESSOR) + +private: + JSC::VM& m_vm; + WEBCORE_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(DECLARE_BUILTIN_NAMES) +}; + +} // namespace WebCore diff --git a/Source/WebCore/bindings/js/WebCoreJSClientData.cpp b/Source/WebCore/bindings/js/WebCoreJSClientData.cpp new file mode 100644 index 000000000..d87931f6e --- /dev/null +++ b/Source/WebCore/bindings/js/WebCoreJSClientData.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2017 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. ``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 + * 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 "WebCoreJSClientData.h" + +#include "JSDOMBinding.h" +#include <heap/HeapInlines.h> +#include <heap/MarkingConstraint.h> +#include <heap/MarkedAllocatorInlines.h> +#include <heap/MarkedBlockInlines.h> +#include <heap/SubspaceInlines.h> +#include <heap/VisitingTimeout.h> +#include <runtime/VM.h> +#include <wtf/MainThread.h> + +using namespace JSC; + +namespace WebCore { + +JSVMClientData::JSVMClientData(VM& vm) + : m_builtinFunctions(vm) + , m_builtinNames(&vm) + , m_outputConstraintSpace("WebCore Wrapper w/ Output Constraint", vm.heap) + , m_globalObjectOutputConstraintSpace("WebCore Global Object w/ Output Constraint", vm.heap) +{ +} + +JSVMClientData::~JSVMClientData() +{ + ASSERT(m_worldSet.contains(m_normalWorld.get())); + ASSERT(m_worldSet.size() == 1); + ASSERT(m_normalWorld->hasOneRef()); + m_normalWorld = nullptr; + ASSERT(m_worldSet.isEmpty()); +} + +void JSVMClientData::getAllWorlds(Vector<Ref<DOMWrapperWorld>>& worlds) +{ + ASSERT(worlds.isEmpty()); + + worlds.reserveInitialCapacity(m_worldSet.size()); + for (auto it = m_worldSet.begin(), end = m_worldSet.end(); it != end; ++it) + worlds.uncheckedAppend(*(*it)); +} + +void JSVMClientData::initNormalWorld(VM* vm) +{ + JSVMClientData* clientData = new JSVMClientData(*vm); + vm->clientData = clientData; // ~VM deletes this pointer. + + auto constraint = std::make_unique<MarkingConstraint>( + "Wcoc", "WebCore Output Constraints", + [vm, clientData, lastExecutionVersion = vm->heap.mutatorExecutionVersion()] + (SlotVisitor& slotVisitor, const VisitingTimeout&) mutable { + Heap& heap = vm->heap; + + if (heap.mutatorExecutionVersion() == lastExecutionVersion) + return; + + lastExecutionVersion = heap.mutatorExecutionVersion(); + + // We have to manage the visit count here ourselves. We need to know that if this adds + // opaque roots then we cannot declare termination yet. The way we signal this to the + // constraint solver is by adding to the visit count. + + size_t numOpaqueRootsBefore = heap.numOpaqueRoots(); + + // FIXME: Make this parallel! + unsigned numRevisited = 0; + clientData->forEachOutputConstraintSpace( + [&] (Subspace& subspace) { + subspace.forEachMarkedCell( + [&] (HeapCell* heapCell, HeapCell::Kind) { + JSCell* cell = static_cast<JSCell*>(heapCell); + cell->methodTable(*vm)->visitOutputConstraints(cell, slotVisitor); + numRevisited++; + }); + }); + if (Options::logGC()) + dataLog("(", numRevisited, ")"); + + slotVisitor.mergeIfNecessary(); + + slotVisitor.addToVisitCount(heap.numOpaqueRoots() - numOpaqueRootsBefore); + }, + ConstraintVolatility::SeldomGreyed); + vm->heap.addMarkingConstraint(WTFMove(constraint)); + + clientData->m_normalWorld = DOMWrapperWorld::create(*vm, true); + vm->m_typedArrayController = adoptRef(new WebCoreTypedArrayController()); +} + +} // namespace WebCore + diff --git a/Source/WebCore/bindings/js/WebCoreJSClientData.h b/Source/WebCore/bindings/js/WebCoreJSClientData.h index 87e95de0f..47243c6de 100644 --- a/Source/WebCore/bindings/js/WebCoreJSClientData.h +++ b/Source/WebCore/bindings/js/WebCoreJSClientData.h @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2003-2017 Apple Inc. All rights reserved. * Copyright (C) 2007 Samuel Weinig <sam@webkit.org> * Copyright (C) 2009 Google, Inc. All rights reserved. * @@ -19,46 +19,31 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef WebCoreJSClientData_h -#define WebCoreJSClientData_h +#pragma once #include "DOMWrapperWorld.h" -#include "DOMObjectHashTableMap.h" +#include "WebCoreBuiltinNames.h" +#include "WebCoreJSBuiltins.h" #include "WebCoreTypedArrayController.h" #include <wtf/HashSet.h> #include <wtf/RefPtr.h> namespace WebCore { -class WebCoreJSClientData : public JSC::VM::ClientData { - WTF_MAKE_NONCOPYABLE(WebCoreJSClientData); WTF_MAKE_FAST_ALLOCATED; +class JSVMClientData : public JSC::VM::ClientData { + WTF_MAKE_NONCOPYABLE(JSVMClientData); WTF_MAKE_FAST_ALLOCATED; friend class VMWorldIterator; - friend void initNormalWorldClientData(JSC::VM*); public: - WebCoreJSClientData() - { - } + explicit JSVMClientData(JSC::VM&); - virtual ~WebCoreJSClientData() - { - ASSERT(m_worldSet.contains(m_normalWorld.get())); - ASSERT(m_worldSet.size() == 1); - ASSERT(m_normalWorld->hasOneRef()); - m_normalWorld.clear(); - ASSERT(m_worldSet.isEmpty()); - } + virtual ~JSVMClientData(); + + WEBCORE_EXPORT static void initNormalWorld(JSC::VM*); DOMWrapperWorld& normalWorld() { return *m_normalWorld; } - void getAllWorlds(Vector<Ref<DOMWrapperWorld>>& worlds) - { - ASSERT(worlds.isEmpty()); - - worlds.reserveInitialCapacity(m_worldSet.size()); - for (auto it = m_worldSet.begin(), end = m_worldSet.end(); it != end; ++it) - worlds.uncheckedAppend(*(*it)); - } + void getAllWorlds(Vector<Ref<DOMWrapperWorld>>&); void rememberWorld(DOMWrapperWorld& world) { @@ -72,21 +57,28 @@ public: m_worldSet.remove(&world); } - DOMObjectHashTableMap hashTableMap; + WebCoreBuiltinNames& builtinNames() { return m_builtinNames; } + JSBuiltinFunctions& builtinFunctions() { return m_builtinFunctions; } + + JSC::Subspace& outputConstraintSpace() { return m_outputConstraintSpace; } + JSC::Subspace& globalObjectOutputConstraintSpace() { return m_globalObjectOutputConstraintSpace; } + + template<typename Func> + void forEachOutputConstraintSpace(const Func& func) + { + func(m_outputConstraintSpace); + func(m_globalObjectOutputConstraintSpace); + } private: HashSet<DOMWrapperWorld*> m_worldSet; RefPtr<DOMWrapperWorld> m_normalWorld; -}; -inline void initNormalWorldClientData(JSC::VM* vm) -{ - WebCoreJSClientData* webCoreJSClientData = new WebCoreJSClientData; - vm->clientData = webCoreJSClientData; // ~VM deletes this pointer. - webCoreJSClientData->m_normalWorld = DOMWrapperWorld::create(vm, true); - vm->m_typedArrayController = adoptRef(new WebCoreTypedArrayController()); -} + JSBuiltinFunctions m_builtinFunctions; + WebCoreBuiltinNames m_builtinNames; + + JSC::JSDestructibleObjectSubspace m_outputConstraintSpace; + JSC::JSSegmentedVariableObjectSubspace m_globalObjectOutputConstraintSpace; +}; } // namespace WebCore - -#endif // WebCoreJSClientData_h diff --git a/Source/WebCore/bindings/js/WebCoreTypedArrayController.cpp b/Source/WebCore/bindings/js/WebCoreTypedArrayController.cpp index 0db3d5237..a3c938518 100644 --- a/Source/WebCore/bindings/js/WebCoreTypedArrayController.cpp +++ b/Source/WebCore/bindings/js/WebCoreTypedArrayController.cpp @@ -26,11 +26,11 @@ #include "config.h" #include "WebCoreTypedArrayController.h" -#include "JSDOMBinding.h" +#include "JSDOMConvertBufferSource.h" #include "JSDOMGlobalObject.h" #include <runtime/ArrayBuffer.h> #include <runtime/JSArrayBuffer.h> -#include <runtime/Operations.h> +#include <runtime/JSCInlines.h> namespace WebCore { @@ -47,20 +47,26 @@ JSC::JSArrayBuffer* WebCoreTypedArrayController::toJS(JSC::ExecState* state, JSC return JSC::jsCast<JSC::JSArrayBuffer*>(WebCore::toJS(state, JSC::jsCast<JSDOMGlobalObject*>(globalObject), buffer)); } +void WebCoreTypedArrayController::registerWrapper(JSC::JSGlobalObject* globalObject, JSC::ArrayBuffer* native, JSC::JSArrayBuffer* wrapper) +{ + cacheWrapper(JSC::jsCast<JSDOMGlobalObject*>(globalObject)->world(), native, wrapper); +} + +bool WebCoreTypedArrayController::isAtomicsWaitAllowedOnCurrentThread() +{ + return !isMainThread(); +} + bool WebCoreTypedArrayController::JSArrayBufferOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, JSC::SlotVisitor& visitor) { - auto& wrapper = *JSC::jsCast<JSC::JSArrayBuffer*>(handle.get().asCell()); - if (!wrapper.hasCustomProperties()) - return false; + auto& wrapper = *JSC::jsCast<JSC::JSArrayBuffer*>(handle.slot()->asCell()); return visitor.containsOpaqueRoot(wrapper.impl()); } void WebCoreTypedArrayController::JSArrayBufferOwner::finalize(JSC::Handle<JSC::Unknown> handle, void* context) { - auto& wrapper = *static_cast<JSC::JSArrayBuffer*>(handle.get().asCell()); - auto& buffer = *wrapper.impl(); - uncacheWrapper(*static_cast<DOMWrapperWorld*>(context), &buffer, &wrapper); - buffer.deref(); + auto& wrapper = *static_cast<JSC::JSArrayBuffer*>(handle.slot()->asCell()); + uncacheWrapper(*static_cast<DOMWrapperWorld*>(context), wrapper.impl(), &wrapper); } } // namespace WebCore diff --git a/Source/WebCore/bindings/js/WebCoreTypedArrayController.h b/Source/WebCore/bindings/js/WebCoreTypedArrayController.h index 23f3eb0f0..3bb94bc85 100644 --- a/Source/WebCore/bindings/js/WebCoreTypedArrayController.h +++ b/Source/WebCore/bindings/js/WebCoreTypedArrayController.h @@ -23,13 +23,15 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef WebCoreTypedArrayController_h -#define WebCoreTypedArrayController_h +#pragma once -#include <heap/Weak.h> #include <runtime/JSGlobalObject.h> #include <runtime/TypedArrayController.h> +namespace JSC { +class WeakHandleOwner; +} + namespace WebCore { class WebCoreTypedArrayController : public JSC::TypedArrayController { @@ -37,21 +39,20 @@ public: WebCoreTypedArrayController(); virtual ~WebCoreTypedArrayController(); - virtual JSC::JSArrayBuffer* toJS(JSC::ExecState*, JSC::JSGlobalObject*, JSC::ArrayBuffer*) override; - + JSC::JSArrayBuffer* toJS(JSC::ExecState*, JSC::JSGlobalObject*, JSC::ArrayBuffer*) override; + void registerWrapper(JSC::JSGlobalObject*, ArrayBuffer*, JSC::JSArrayBuffer*) override; + bool isAtomicsWaitAllowedOnCurrentThread() override; + JSC::WeakHandleOwner* wrapperOwner() { return &m_owner; } private: class JSArrayBufferOwner : public JSC::WeakHandleOwner { public: - virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&) override; - virtual void finalize(JSC::Handle<JSC::Unknown>, void* context) override; + bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&) override; + void finalize(JSC::Handle<JSC::Unknown>, void* context) override; }; JSArrayBufferOwner m_owner; }; } // namespace WebCore - -#endif // WebCoreTypedArrayController_h - diff --git a/Source/WebCore/bindings/js/WorkerScriptController.cpp b/Source/WebCore/bindings/js/WorkerScriptController.cpp index 579a0b4af..230af90bd 100644 --- a/Source/WebCore/bindings/js/WorkerScriptController.cpp +++ b/Source/WebCore/bindings/js/WorkerScriptController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 2016 Apple Inc. All Rights Reserved. * Copyright (C) 2011, 2012 Google Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without @@ -11,18 +11,17 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" @@ -30,23 +29,18 @@ #include "JSDOMBinding.h" #include "JSDedicatedWorkerGlobalScope.h" +#include "JSEventTarget.h" #include "ScriptSourceCode.h" #include "WebCoreJSClientData.h" +#include "WorkerConsoleClient.h" #include "WorkerGlobalScope.h" -#include "WorkerObjectProxy.h" -#include "WorkerScriptDebugServer.h" -#include "WorkerThread.h" #include <bindings/ScriptValue.h> #include <heap/StrongInlines.h> -#include <interpreter/Interpreter.h> #include <runtime/Completion.h> +#include <runtime/Exception.h> #include <runtime/ExceptionHelpers.h> -#include <runtime/Error.h> #include <runtime/JSLock.h> - -#if ENABLE(SHARED_WORKERS) -#include "JSSharedWorkerGlobalScope.h" -#endif +#include <runtime/Watchdog.h> using namespace JSC; @@ -56,16 +50,21 @@ WorkerScriptController::WorkerScriptController(WorkerGlobalScope* workerGlobalSc : m_vm(VM::create()) , m_workerGlobalScope(workerGlobalScope) , m_workerGlobalScopeWrapper(*m_vm) - , m_executionForbidden(false) { - initNormalWorldClientData(m_vm.get()); + m_vm->heap.acquireAccess(); // It's not clear that we have good discipline for heap access, so turn it on permanently. + m_vm->ensureWatchdog(); + JSVMClientData::initNormalWorld(m_vm.get()); } WorkerScriptController::~WorkerScriptController() { JSLockHolder lock(vm()); + if (m_workerGlobalScopeWrapper) { + m_workerGlobalScopeWrapper->setConsoleClient(nullptr); + m_consoleClient = nullptr; + } m_workerGlobalScopeWrapper.clear(); - m_vm.clear(); + m_vm = nullptr; } void WorkerScriptController::initScript() @@ -77,35 +76,28 @@ 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.) - Structure* workerGlobalScopePrototypeStructure = JSWorkerGlobalScopePrototype::createStructure(*m_vm, 0, jsNull()); - Strong<JSWorkerGlobalScopePrototype> workerGlobalScopePrototype(*m_vm, JSWorkerGlobalScopePrototype::create(*m_vm, 0, workerGlobalScopePrototypeStructure)); - if (m_workerGlobalScope->isDedicatedWorkerGlobalScope()) { - Structure* dedicatedContextPrototypeStructure = JSDedicatedWorkerGlobalScopePrototype::createStructure(*m_vm, 0, workerGlobalScopePrototype.get()); - Strong<JSDedicatedWorkerGlobalScopePrototype> dedicatedContextPrototype(*m_vm, JSDedicatedWorkerGlobalScopePrototype::create(*m_vm, 0, dedicatedContextPrototypeStructure)); - Structure* structure = JSDedicatedWorkerGlobalScope::createStructure(*m_vm, 0, dedicatedContextPrototype.get()); + Structure* dedicatedContextPrototypeStructure = JSDedicatedWorkerGlobalScopePrototype::createStructure(*m_vm, nullptr, jsNull()); + Strong<JSDedicatedWorkerGlobalScopePrototype> dedicatedContextPrototype(*m_vm, JSDedicatedWorkerGlobalScopePrototype::create(*m_vm, nullptr, dedicatedContextPrototypeStructure)); + Structure* structure = JSDedicatedWorkerGlobalScope::createStructure(*m_vm, nullptr, dedicatedContextPrototype.get()); + auto* proxyStructure = JSProxy::createStructure(*m_vm, nullptr, jsNull(), PureForwardingProxyType); + auto* proxy = JSProxy::create(*m_vm, proxyStructure); - m_workerGlobalScopeWrapper.set(*m_vm, JSDedicatedWorkerGlobalScope::create(*m_vm, structure, static_cast<DedicatedWorkerGlobalScope*>(m_workerGlobalScope))); - workerGlobalScopePrototypeStructure->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get()); + m_workerGlobalScopeWrapper.set(*m_vm, JSDedicatedWorkerGlobalScope::create(*m_vm, structure, static_cast<DedicatedWorkerGlobalScope&>(*m_workerGlobalScope), proxy)); dedicatedContextPrototypeStructure->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get()); ASSERT(structure->globalObject() == m_workerGlobalScopeWrapper); ASSERT(m_workerGlobalScopeWrapper->structure()->globalObject() == m_workerGlobalScopeWrapper); - workerGlobalScopePrototype->structure()->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get()); dedicatedContextPrototype->structure()->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get()); -#if ENABLE(SHARED_WORKERS) - } else { - ASSERT(m_workerGlobalScope->isSharedWorkerGlobalScope()); - Structure* sharedContextPrototypeStructure = JSSharedWorkerGlobalScopePrototype::createStructure(*m_vm, 0, workerGlobalScopePrototype.get()); - Strong<JSSharedWorkerGlobalScopePrototype> sharedContextPrototype(*m_vm, JSSharedWorkerGlobalScopePrototype::create(*m_vm, 0, sharedContextPrototypeStructure)); - Structure* structure = JSSharedWorkerGlobalScope::createStructure(*m_vm, 0, sharedContextPrototype.get()); - - m_workerGlobalScopeWrapper.set(*m_vm, JSSharedWorkerGlobalScope::create(*m_vm, structure, static_cast<SharedWorkerGlobalScope*>(m_workerGlobalScope))); - workerGlobalScopePrototype->structure()->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get()); - sharedContextPrototype->structure()->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get()); -#endif + dedicatedContextPrototype->structure()->setPrototypeWithoutTransition(*m_vm, JSWorkerGlobalScope::prototype(*m_vm, m_workerGlobalScopeWrapper.get())); + + proxy->setTarget(*m_vm, m_workerGlobalScopeWrapper.get()); + proxy->structure()->setGlobalObject(*m_vm, m_workerGlobalScopeWrapper.get()); } ASSERT(m_workerGlobalScopeWrapper->globalObject() == m_workerGlobalScopeWrapper); - ASSERT(asObject(m_workerGlobalScopeWrapper->prototype())->globalObject() == m_workerGlobalScopeWrapper); + ASSERT(asObject(m_workerGlobalScopeWrapper->getPrototypeDirect())->globalObject() == m_workerGlobalScopeWrapper); + + m_consoleClient = std::make_unique<WorkerConsoleClient>(*m_workerGlobalScope); + m_workerGlobalScopeWrapper->setConsoleClient(m_consoleClient.get()); } void WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode) @@ -113,15 +105,15 @@ void WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode) if (isExecutionForbidden()) return; - Deprecated::ScriptValue exception; - evaluate(sourceCode, &exception); - if (exception.jsValue()) { + NakedPtr<JSC::Exception> exception; + evaluate(sourceCode, exception); + if (exception) { JSLockHolder lock(vm()); - reportException(m_workerGlobalScopeWrapper->globalExec(), exception.jsValue()); + reportException(m_workerGlobalScopeWrapper->globalExec(), exception); } } -void WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, Deprecated::ScriptValue* exception) +void WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, NakedPtr<JSC::Exception>& returnedException) { if (isExecutionForbidden()) return; @@ -129,47 +121,52 @@ void WorkerScriptController::evaluate(const ScriptSourceCode& sourceCode, Deprec initScriptIfNeeded(); ExecState* exec = m_workerGlobalScopeWrapper->globalExec(); - JSLockHolder lock(exec); + VM& vm = exec->vm(); + JSLockHolder lock(vm); - JSValue evaluationException; - JSC::evaluate(exec, sourceCode.jsSourceCode(), m_workerGlobalScopeWrapper.get(), &evaluationException); + JSC::evaluate(exec, sourceCode.jsSourceCode(), m_workerGlobalScopeWrapper->globalThis(), returnedException); - if ((evaluationException && isTerminatedExecutionException(evaluationException)) || m_workerGlobalScopeWrapper->vm().watchdog.didFire()) { + if ((returnedException && isTerminatedExecutionException(vm, returnedException)) || isTerminatingExecution()) { forbidExecution(); return; } - if (evaluationException) { + if (returnedException) { String errorMessage; int lineNumber = 0; int columnNumber = 0; String sourceURL = sourceCode.url().string(); - if (m_workerGlobalScope->sanitizeScriptError(errorMessage, lineNumber, columnNumber, sourceURL, sourceCode.cachedScript())) - *exception = Deprecated::ScriptValue(*m_vm, exec->vm().throwException(exec, createError(exec, errorMessage.impl()))); - else - *exception = Deprecated::ScriptValue(*m_vm, evaluationException); + JSC::Strong<JSC::Unknown> error; + if (m_workerGlobalScope->sanitizeScriptError(errorMessage, lineNumber, columnNumber, sourceURL, error, sourceCode.cachedScript())) + returnedException = JSC::Exception::create(vm, createError(exec, errorMessage.impl())); } } -void WorkerScriptController::setException(const Deprecated::ScriptValue& exception) +void WorkerScriptController::setException(JSC::Exception* exception) { - m_workerGlobalScopeWrapper->globalExec()->vm().throwException(m_workerGlobalScopeWrapper->globalExec(), exception.jsValue()); + JSC::ExecState* exec = m_workerGlobalScopeWrapper->globalExec(); + VM& vm = exec->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + throwException(exec, scope, exception); } void WorkerScriptController::scheduleExecutionTermination() { // The mutex provides a memory barrier to ensure that once - // termination is scheduled, isExecutionTerminating will + // termination is scheduled, isTerminatingExecution() will // accurately reflect that state when called from another thread. - MutexLocker locker(m_scheduledTerminationMutex); - m_vm->watchdog.fire(); + LockHolder locker(m_scheduledTerminationMutex); + m_isTerminatingExecution = true; + + ASSERT(m_vm->watchdog()); + m_vm->watchdog()->terminateSoon(); } -bool WorkerScriptController::isExecutionTerminating() const +bool WorkerScriptController::isTerminatingExecution() const { // See comments in scheduleExecutionTermination regarding mutex usage. - MutexLocker locker(m_scheduledTerminationMutex); - return m_vm->watchdog.didFire(); + LockHolder locker(m_scheduledTerminationMutex); + return m_isTerminatingExecution; } void WorkerScriptController::forbidExecution() @@ -192,6 +189,16 @@ void WorkerScriptController::disableEval(const String& errorMessage) m_workerGlobalScopeWrapper->setEvalEnabled(false, errorMessage); } +void WorkerScriptController::releaseHeapAccess() +{ + m_vm->heap.releaseAccess(); +} + +void WorkerScriptController::acquireHeapAccess() +{ + m_vm->heap.acquireAccess(); +} + void WorkerScriptController::attachDebugger(JSC::Debugger* debugger) { initScriptIfNeeded(); diff --git a/Source/WebCore/bindings/js/WorkerScriptController.h b/Source/WebCore/bindings/js/WorkerScriptController.h index 025c37d2c..460455208 100644 --- a/Source/WebCore/bindings/js/WorkerScriptController.h +++ b/Source/WebCore/bindings/js/WorkerScriptController.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 2015, 2016 Apple Inc. All Rights Reserved. * Copyright (C) 2012 Google Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without @@ -11,10 +11,10 @@ * 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 COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -22,20 +22,15 @@ * 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 WorkerScriptController_h -#define WorkerScriptController_h +#pragma once #include <debugger/Debugger.h> #include <heap/Strong.h> #include <wtf/Forward.h> -#include <wtf/Threading.h> - -namespace Deprecated { -class ScriptValue; -} +#include <wtf/Lock.h> +#include <wtf/NakedPtr.h> namespace JSC { class VM; @@ -45,6 +40,7 @@ namespace WebCore { class JSWorkerGlobalScope; class ScriptSourceCode; + class WorkerConsoleClient; class WorkerGlobalScope; class WorkerScriptController { @@ -60,9 +56,9 @@ namespace WebCore { } void evaluate(const ScriptSourceCode&); - void evaluate(const ScriptSourceCode&, Deprecated::ScriptValue* exception); + void evaluate(const ScriptSourceCode&, NakedPtr<JSC::Exception>& returnedException); - void setException(const Deprecated::ScriptValue&); + void setException(JSC::Exception*); // Async request to terminate a JS run execution. Eventually causes termination // exception raised during JS execution, if the worker thread happens to run JS. @@ -70,7 +66,7 @@ namespace WebCore { // forbidExecution()/isExecutionForbidden() to guard against reentry into JS. // Can be called from any thread. void scheduleExecutionTermination(); - bool isExecutionTerminating() const; + bool isTerminatingExecution() const; // 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. @@ -79,7 +75,10 @@ namespace WebCore { void disableEval(const String& errorMessage); - JSC::VM* vm() { return m_vm.get(); } + JSC::VM& vm() { return *m_vm; } + + void releaseHeapAccess(); + void acquireHeapAccess(); void attachDebugger(JSC::Debugger*); void detachDebugger(JSC::Debugger*); @@ -95,10 +94,10 @@ namespace WebCore { RefPtr<JSC::VM> m_vm; WorkerGlobalScope* m_workerGlobalScope; JSC::Strong<JSWorkerGlobalScope> m_workerGlobalScopeWrapper; - bool m_executionForbidden; - mutable Mutex m_scheduledTerminationMutex; + std::unique_ptr<WorkerConsoleClient> m_consoleClient; + bool m_executionForbidden { false }; + bool m_isTerminatingExecution { false }; + mutable Lock m_scheduledTerminationMutex; }; } // namespace WebCore - -#endif // WorkerScriptController_h diff --git a/Source/WebCore/bindings/js/WorkerScriptDebugServer.cpp b/Source/WebCore/bindings/js/WorkerScriptDebugServer.cpp deleted file mode 100644 index 76c95eebc..000000000 --- a/Source/WebCore/bindings/js/WorkerScriptDebugServer.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2011 Google Inc. All rights reserved. - * Copyright (c) 2013 Apple Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "WorkerScriptDebugServer.h" - -#include "JSDOMBinding.h" -#include "Timer.h" -#include "WorkerDebuggerAgent.h" -#include "WorkerGlobalScope.h" -#include "WorkerRunLoop.h" -#include "WorkerThread.h" -#include <runtime/VM.h> -#include <wtf/PassOwnPtr.h> - -using namespace Inspector; - -namespace WebCore { - -WorkerScriptDebugServer::WorkerScriptDebugServer(WorkerGlobalScope* context, const String& mode) - : ScriptDebugServer(true) - , m_workerGlobalScope(context) - , m_debuggerTaskMode(mode) -{ -} - -void WorkerScriptDebugServer::addListener(ScriptDebugListener* listener) -{ - if (!listener) - return; - - bool wasEmpty = m_listeners.isEmpty(); - m_listeners.add(listener); - - if (wasEmpty) { - m_workerGlobalScope->script()->attachDebugger(this); - recompileAllJSFunctions(); - } -} - -void WorkerScriptDebugServer::removeListener(ScriptDebugListener* listener, bool skipRecompile) -{ - if (!listener) - return; - - m_listeners.remove(listener); - - if (m_listeners.isEmpty()) { - m_workerGlobalScope->script()->detachDebugger(this); - if (!skipRecompile) - recompileAllJSFunctions(); - } -} - -void WorkerScriptDebugServer::recompileAllJSFunctions() -{ - JSC::VM* vm = m_workerGlobalScope->script()->vm(); - - JSC::JSLockHolder lock(vm); - JSC::Debugger::recompileAllJSFunctions(vm); -} - -void WorkerScriptDebugServer::runEventLoopWhilePaused() -{ - TimerBase::fireTimersInNestedEventLoop(); - - MessageQueueWaitResult result; - do { - result = m_workerGlobalScope->thread()->runLoop().runInMode(m_workerGlobalScope, m_debuggerTaskMode); - // Keep waiting until execution is resumed. - } while (result != MessageQueueTerminated && !m_doneProcessingDebuggerEvents); -} - -void WorkerScriptDebugServer::reportException(JSC::ExecState* exec, JSC::JSValue exception) const -{ - WebCore::reportException(exec, exception); -} - -void WorkerScriptDebugServer::interruptAndRunTask(PassOwnPtr<ScriptDebugServer::Task>) -{ -} - -} // namespace WebCore diff --git a/Source/WebCore/bindings/js/WorkerScriptDebugServer.h b/Source/WebCore/bindings/js/WorkerScriptDebugServer.h deleted file mode 100644 index 78efd0bc7..000000000 --- a/Source/WebCore/bindings/js/WorkerScriptDebugServer.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2011 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WorkerScriptDebugServer_h -#define WorkerScriptDebugServer_h - -#include <inspector/ScriptDebugServer.h> - -namespace WebCore { - -class WorkerGlobalScope; - -class WorkerScriptDebugServer final : public Inspector::ScriptDebugServer { - WTF_MAKE_NONCOPYABLE(WorkerScriptDebugServer); -public: - WorkerScriptDebugServer(WorkerGlobalScope*, const String&); - ~WorkerScriptDebugServer() { } - - virtual void recompileAllJSFunctions() override; - - void addListener(Inspector::ScriptDebugListener*); - void removeListener(Inspector::ScriptDebugListener*, bool skipRecompile); - - void interruptAndRunTask(PassOwnPtr<ScriptDebugServer::Task>); - -private: - virtual ListenerSet* getListenersForGlobalObject(JSC::JSGlobalObject*) override { return &m_listeners; } - virtual void didPause(JSC::JSGlobalObject*) override { } - virtual void didContinue(JSC::JSGlobalObject*) override { } - virtual void runEventLoopWhilePaused() override; - virtual bool isContentScript(JSC::ExecState*) const override { return false; } - virtual void reportException(JSC::ExecState*, JSC::JSValue) const override; - - WorkerGlobalScope* m_workerGlobalScope; - ListenerSet m_listeners; - String m_debuggerTaskMode; -}; - -} // namespace WebCore - -#endif // WorkerScriptDebugServer_h |