/* -*- 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__