diff options
Diffstat (limited to 'dom/xbl/nsXBLMaybeCompiled.h')
-rw-r--r-- | dom/xbl/nsXBLMaybeCompiled.h | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/dom/xbl/nsXBLMaybeCompiled.h b/dom/xbl/nsXBLMaybeCompiled.h new file mode 100644 index 000000000..d4b366b0e --- /dev/null +++ b/dom/xbl/nsXBLMaybeCompiled.h @@ -0,0 +1,172 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsXBLMaybeCompiled_h__ +#define nsXBLMaybeCompiled_h__ + +#include "js/GCAPI.h" + +/* + * A union containing either a pointer representing uncompiled source or a + * JSObject* representing the compiled result. The class is templated on the + * source object type. + * + * The purpose of abstracting this as a separate class is to allow it to be + * wrapped in a JS::Heap<T> to correctly handle post-barriering of the JSObject + * pointer, when present. + * + * No implementation of rootKind() is provided, which prevents + * Root<nsXBLMaybeCompiled<UncompiledT>> from being used. + */ +template <class UncompiledT> +class nsXBLMaybeCompiled +{ +public: + nsXBLMaybeCompiled() : mUncompiled(BIT_UNCOMPILED) {} + + explicit nsXBLMaybeCompiled(UncompiledT* uncompiled) + : mUncompiled(reinterpret_cast<uintptr_t>(uncompiled) | BIT_UNCOMPILED) {} + + explicit nsXBLMaybeCompiled(JSObject* compiled) : mCompiled(compiled) {} + + bool IsCompiled() const + { + return !(mUncompiled & BIT_UNCOMPILED); + } + + UncompiledT* GetUncompiled() const + { + MOZ_ASSERT(!IsCompiled(), "Attempt to get compiled function as uncompiled"); + uintptr_t unmasked = mUncompiled & ~BIT_UNCOMPILED; + return reinterpret_cast<UncompiledT*>(unmasked); + } + + JSObject* GetJSFunction() const + { + MOZ_ASSERT(IsCompiled(), "Attempt to get uncompiled function as compiled"); + if (mCompiled) { + JS::ExposeObjectToActiveJS(mCompiled); + } + return mCompiled; + } + + // This is appropriate for use in tracing methods, etc. + JSObject* GetJSFunctionPreserveColor() const + { + MOZ_ASSERT(IsCompiled(), "Attempt to get uncompiled function as compiled"); + return mCompiled; + } + +private: + JSObject*& UnsafeGetJSFunction() + { + MOZ_ASSERT(IsCompiled(), "Attempt to get uncompiled function as compiled"); + return mCompiled; + } + + enum { BIT_UNCOMPILED = 1 << 0 }; + + union + { + // An pointer that represents the function before being compiled, with + // BIT_UNCOMPILED set. + uintptr_t mUncompiled; + + // The JS object for the compiled result. + JSObject* mCompiled; + }; + + friend struct js::BarrierMethods<nsXBLMaybeCompiled<UncompiledT>>; +}; + +/* Add support for JS::Heap<nsXBLMaybeCompiled>. */ +namespace JS { + +template <class UncompiledT> +struct GCPolicy<nsXBLMaybeCompiled<UncompiledT>> +{ + static nsXBLMaybeCompiled<UncompiledT> initial() { return nsXBLMaybeCompiled<UncompiledT>(); } +}; + +} // namespace JS + +namespace js { + +template <class UncompiledT> +struct BarrierMethods<nsXBLMaybeCompiled<UncompiledT>> +{ + typedef struct BarrierMethods<JSObject *> Base; + + static void postBarrier(nsXBLMaybeCompiled<UncompiledT>* functionp, + nsXBLMaybeCompiled<UncompiledT> prev, + nsXBLMaybeCompiled<UncompiledT> next) + { + if (next.IsCompiled()) { + Base::postBarrier(&functionp->UnsafeGetJSFunction(), + prev.IsCompiled() ? prev.UnsafeGetJSFunction() : nullptr, + next.UnsafeGetJSFunction()); + } else if (prev.IsCompiled()) { + Base::postBarrier(&prev.UnsafeGetJSFunction(), + prev.UnsafeGetJSFunction(), + nullptr); + } + } + static void exposeToJS(nsXBLMaybeCompiled<UncompiledT> fun) { + if (fun.IsCompiled()) { + JS::ExposeObjectToActiveJS(fun.UnsafeGetJSFunction()); + } + } +}; + +template <class T> +struct IsHeapConstructibleType<nsXBLMaybeCompiled<T>> +{ // Yes, this is the exception to the rule. Sorry. + static constexpr bool value = true; +}; + +template <class UncompiledT> +class HeapBase<nsXBLMaybeCompiled<UncompiledT>> +{ + const JS::Heap<nsXBLMaybeCompiled<UncompiledT>>& wrapper() const { + return *static_cast<const JS::Heap<nsXBLMaybeCompiled<UncompiledT>>*>(this); + } + + JS::Heap<nsXBLMaybeCompiled<UncompiledT>>& wrapper() { + return *static_cast<JS::Heap<nsXBLMaybeCompiled<UncompiledT>>*>(this); + } + + const nsXBLMaybeCompiled<UncompiledT>* extract() const { + return wrapper().address(); + } + + nsXBLMaybeCompiled<UncompiledT>* extract() { + return wrapper().unsafeGet(); + } + +public: + bool IsCompiled() const { return extract()->IsCompiled(); } + UncompiledT* GetUncompiled() const { return extract()->GetUncompiled(); } + JSObject* GetJSFunction() const { return extract()->GetJSFunction(); } + JSObject* GetJSFunctionPreserveColor() const { return extract()->GetJSFunctionPreserveColor(); } + + void SetUncompiled(UncompiledT* source) { + wrapper() = nsXBLMaybeCompiled<UncompiledT>(source); + } + + void SetJSFunction(JSObject* function) { + wrapper() = nsXBLMaybeCompiled<UncompiledT>(function); + } + + JS::Heap<JSObject*>& AsHeapObject() + { + MOZ_ASSERT(extract()->IsCompiled()); + return *reinterpret_cast<JS::Heap<JSObject*>*>(this); + } +}; + +} /* namespace js */ + +#endif // nsXBLMaybeCompiled_h__ |