/* * Copyright (C) 2016 Charybdis Development Team * Copyright (C) 2016 Jason Volk * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice is present in all copies. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 #define HAVE_IRCD_JS_CONTEXT_H namespace ircd { namespace js { struct context :private custom_ptr { class lock { context *c; public: lock(context &c); // BeginRequest on cx of your choice lock(); // BeginRequest on the thread_local cx ~lock() noexcept; // EndRequest }; struct opts { size_t stack_chunk_size = 8_KiB; bool dtor_gc = true; } opts; // We keep a copy of the given opts here. operator JSContext *() const { return get(); } operator JSContext &() const { return custom_ptr::operator*(); } bool operator!() const { return !custom_ptr::operator bool(); } auto &runtime() const { return our(JS_GetRuntime(get())); } auto &runtime() { return our(JS_GetRuntime(get())); } auto ptr() const { return get(); } auto ptr() { return get(); } context(JSRuntime *const &, const struct opts &); context() = default; context(context &&) noexcept; context(const context &) = delete; context &operator=(context &&) noexcept; context &operator=(const context &) = delete; ~context() noexcept; }; // Current thread_local context. Runtimes/Contexts (soon to be merged in future SpiderMonkey) // are singled-threaded and this points to the context appropos your thread. // Do not construct more than one context on the same thread- this is overwritten. extern __thread context *cx; // A default JSContext instance is provided residing near the main runtime as a convenience // for misc/utility/system purposes if necessary. You should use *cx instead. extern context main_cx; // Get to our `struct context` from any upstream JSContext const context &our(const JSContext *const &); context &our(JSContext *const &); // Get/Set your privdata managed by this object, casting to your expected type. template const T *priv(const context &); template T *priv(context &); void priv(context &, privdata *const &); auto version(const context &c) { return version(JS_GetVersion(c)); } auto running(const context &c) { return JS_IsRunning(c); } auto uncaught_exception(const context &c) { return JS_IsExceptionPending(c); } auto rethrow_exception(context &c) { return JS_ReportPendingException(c); } auto interrupted(const context &c) { return JS_CheckForInterrupt(c); } void out_of_memory(context &c) { JS_ReportOutOfMemory(c); } void allocation_overflow(context &c) { JS_ReportAllocationOverflow(c); } void run_gc(context &c) { JS_MaybeGC(c); } JSObject *current_global(context &c); JS::RootedObject current_global(context &c, rooted_t); // thread_local JSObject *current_global(); JS::RootedObject current_global(rooted_t); inline JS::RootedObject current_global(rooted_t) { return { *cx, current_global(*cx, rooted) }; } inline JSObject * current_global() { return current_global(*cx); } inline JS::RootedObject current_global(context &c, rooted_t) { return { c, current_global(c, rooted) }; } inline JSObject * current_global(context &c) { return JS::CurrentGlobalOrNull(c); } inline void priv(context &c, privdata *const &ptr) { delete priv(c); // Free any existing object to overwrite/null JS_SetSecondContextPrivate(c, ptr); } template T * priv(context &c) { return dynamic_cast(static_cast(JS_GetSecondContextPrivate(c))); } template const T * priv(const context &c) { return dynamic_cast(static_cast(JS_GetSecondContextPrivate(c))); } inline context & our(JSContext *const &c) { return *static_cast(JS_GetContextPrivate(c)); } inline const context & our(const JSContext *const &c) { return *static_cast(JS_GetContextPrivate(const_cast(c))); } } // namespace js } // namespace ircd