michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef nsXBLMaybeCompiled_h__ michael@0: #define nsXBLMaybeCompiled_h__ michael@0: michael@0: #include "js/GCAPI.h" michael@0: michael@0: /* michael@0: * A union containing either a pointer representing uncompiled source or a michael@0: * JSObject* representing the compiled result. The class is templated on the michael@0: * source object type. michael@0: * michael@0: * The purpose of abstracting this as a separate class is to allow it to be michael@0: * wrapped in a JS::Heap to correctly handle post-barriering of the JSObject michael@0: * pointer, when present. michael@0: */ michael@0: template michael@0: class nsXBLMaybeCompiled michael@0: { michael@0: public: michael@0: nsXBLMaybeCompiled() : mUncompiled(BIT_UNCOMPILED) {} michael@0: michael@0: nsXBLMaybeCompiled(UncompiledT* uncompiled) michael@0: : mUncompiled(reinterpret_cast(uncompiled) | BIT_UNCOMPILED) {} michael@0: michael@0: nsXBLMaybeCompiled(JSObject* compiled) : mCompiled(compiled) {} michael@0: michael@0: bool IsCompiled() const michael@0: { michael@0: return !(mUncompiled & BIT_UNCOMPILED); michael@0: } michael@0: michael@0: UncompiledT* GetUncompiled() const michael@0: { michael@0: MOZ_ASSERT(!IsCompiled(), "Attempt to get compiled function as uncompiled"); michael@0: uintptr_t unmasked = mUncompiled & ~BIT_UNCOMPILED; michael@0: return reinterpret_cast(unmasked); michael@0: } michael@0: michael@0: JSObject* GetJSFunction() const michael@0: { michael@0: MOZ_ASSERT(IsCompiled(), "Attempt to get uncompiled function as compiled"); michael@0: if (mCompiled) { michael@0: JS::ExposeObjectToActiveJS(mCompiled); michael@0: } michael@0: return mCompiled; michael@0: } michael@0: michael@0: // This is appropriate for use in tracing methods, etc. michael@0: JSObject* GetJSFunctionPreserveColor() const michael@0: { michael@0: MOZ_ASSERT(IsCompiled(), "Attempt to get uncompiled function as compiled"); michael@0: return mCompiled; michael@0: } michael@0: michael@0: private: michael@0: JSObject*& UnsafeGetJSFunction() michael@0: { michael@0: MOZ_ASSERT(IsCompiled(), "Attempt to get uncompiled function as compiled"); michael@0: return mCompiled; michael@0: } michael@0: michael@0: enum { BIT_UNCOMPILED = 1 << 0 }; michael@0: michael@0: union michael@0: { michael@0: // An pointer that represents the function before being compiled, with michael@0: // BIT_UNCOMPILED set. michael@0: uintptr_t mUncompiled; michael@0: michael@0: // The JS object for the compiled result. michael@0: JSObject* mCompiled; michael@0: }; michael@0: michael@0: friend class js::GCMethods >; michael@0: }; michael@0: michael@0: /* Add support for JS::Heap. */ michael@0: namespace js { michael@0: michael@0: template michael@0: struct GCMethods > : public GCMethods michael@0: { michael@0: typedef struct GCMethods Base; michael@0: michael@0: static nsXBLMaybeCompiled initial() { return nsXBLMaybeCompiled(); } michael@0: michael@0: static bool poisoned(nsXBLMaybeCompiled function) michael@0: { michael@0: return function.IsCompiled() && Base::poisoned(function.GetJSFunction()); michael@0: } michael@0: michael@0: static bool needsPostBarrier(nsXBLMaybeCompiled function) michael@0: { michael@0: return function.IsCompiled() && Base::needsPostBarrier(function.GetJSFunction()); michael@0: } michael@0: michael@0: #ifdef JSGC_GENERATIONAL michael@0: static void postBarrier(nsXBLMaybeCompiled* functionp) michael@0: { michael@0: Base::postBarrier(&functionp->UnsafeGetJSFunction()); michael@0: } michael@0: michael@0: static void relocate(nsXBLMaybeCompiled* functionp) michael@0: { michael@0: Base::relocate(&functionp->UnsafeGetJSFunction()); michael@0: } michael@0: #endif michael@0: }; michael@0: michael@0: template michael@0: class HeapBase > michael@0: { michael@0: const JS::Heap >& wrapper() const { michael@0: return *static_cast >*>(this); michael@0: } michael@0: michael@0: JS::Heap >& wrapper() { michael@0: return *static_cast >*>(this); michael@0: } michael@0: michael@0: const nsXBLMaybeCompiled* extract() const { michael@0: return wrapper().address(); michael@0: } michael@0: michael@0: nsXBLMaybeCompiled* extract() { michael@0: return wrapper().unsafeGet(); michael@0: } michael@0: michael@0: public: michael@0: bool IsCompiled() const { return extract()->IsCompiled(); } michael@0: UncompiledT* GetUncompiled() const { return extract()->GetUncompiled(); } michael@0: JSObject* GetJSFunction() const { return extract()->GetJSFunction(); } michael@0: JSObject* GetJSFunctionPreserveColor() const { return extract()->GetJSFunctionPreserveColor(); } michael@0: michael@0: void SetUncompiled(UncompiledT* source) { michael@0: wrapper().set(nsXBLMaybeCompiled(source)); michael@0: } michael@0: michael@0: void SetJSFunction(JSObject* function) { michael@0: wrapper().set(nsXBLMaybeCompiled(function)); michael@0: } michael@0: michael@0: JS::Heap& AsHeapObject() michael@0: { michael@0: MOZ_ASSERT(extract()->IsCompiled()); michael@0: return *reinterpret_cast*>(this); michael@0: } michael@0: }; michael@0: michael@0: } /* namespace js */ michael@0: michael@0: #endif // nsXBLMaybeCompiled_h__