summaryrefslogtreecommitdiffstats
path: root/dom/xbl/nsXBLMaybeCompiled.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/xbl/nsXBLMaybeCompiled.h')
-rw-r--r--dom/xbl/nsXBLMaybeCompiled.h172
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__