mirror of
https://github.com/matrix-construct/construct
synced 2024-11-25 08:12:37 +01:00
ircd::js: Moz people recommend thread_local JSRuntime/JSContext;
There is no reason to clutter most arguments with contexts. Additionally these will be merged in the future SpiderMonkey. There is only one JSRuntime/JSContext per thread and it must be locked when in use.
This commit is contained in:
parent
6db6b2a975
commit
0e2b8600e5
11 changed files with 218 additions and 178 deletions
|
@ -27,19 +27,16 @@ namespace js {
|
|||
|
||||
class compartment_guard
|
||||
{
|
||||
JSContext *cx;
|
||||
JSCompartment *cp;
|
||||
|
||||
public:
|
||||
compartment_guard(JSContext &, JSObject &);
|
||||
compartment_guard(JSObject &);
|
||||
~compartment_guard() noexcept;
|
||||
};
|
||||
|
||||
inline
|
||||
compartment_guard::compartment_guard(JSContext &cx,
|
||||
JSObject &obj)
|
||||
:cx{&cx}
|
||||
,cp{JS_EnterCompartment(&cx, &obj)}
|
||||
compartment_guard::compartment_guard(JSObject &obj)
|
||||
:cp{JS_EnterCompartment(*cx, &obj)}
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -47,7 +44,7 @@ inline
|
|||
compartment_guard::~compartment_guard()
|
||||
noexcept
|
||||
{
|
||||
JS_LeaveCompartment(cx, cp);
|
||||
JS_LeaveCompartment(*cx, cp);
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
|
|
@ -28,6 +28,16 @@ namespace js {
|
|||
struct context
|
||||
:private custom_ptr<JSContext>
|
||||
{
|
||||
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;
|
||||
|
@ -49,11 +59,17 @@ struct context
|
|||
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.
|
||||
extern context mc;
|
||||
// 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 &);
|
||||
|
@ -72,18 +88,36 @@ 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_p(context &c);
|
||||
JS::RootedObject current_global(context &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(context &c)
|
||||
current_global(rooted_t)
|
||||
{
|
||||
return { c, current_global_p(c) };
|
||||
return { *cx, current_global(*cx, rooted) };
|
||||
}
|
||||
|
||||
inline JSObject *
|
||||
current_global_p(context &c)
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -29,46 +29,43 @@ using closure_id = std::function<void (const JS::HandleId &)>;
|
|||
using closure_key_val = std::function<void (JS::HandleValue, JS::HandleValue)>;
|
||||
using closure_mutable_key_val = std::function<void (JS::HandleValue, JS::MutableHandleValue)>;
|
||||
|
||||
void for_each(context &, const JS::HandleObject &, const closure_id &);
|
||||
void for_each(context &, const JS::HandleObject &, const closure_key_val &);
|
||||
void for_each(context &, const JS::MutableHandleObject &, const closure_mutable_key_val &);
|
||||
void for_each(const JS::HandleObject &, const closure_id &);
|
||||
void for_each(const JS::HandleObject &, const closure_key_val &);
|
||||
void for_each(const JS::MutableHandleObject &, const closure_mutable_key_val &);
|
||||
|
||||
|
||||
inline void
|
||||
for_each(context &c,
|
||||
const JS::MutableHandleObject &obj,
|
||||
for_each(const JS::MutableHandleObject &obj,
|
||||
const closure_mutable_key_val &closure)
|
||||
{
|
||||
for_each(c, obj, [&c, &obj, &closure]
|
||||
for_each(obj, [&obj, &closure]
|
||||
(const JS::HandleId &hid)
|
||||
{
|
||||
JS::RootedValue key(c, id(c, hid)), val(c);
|
||||
JS_GetPropertyById(c, obj, hid, &val);
|
||||
JS::RootedValue key(*cx, id(hid)), val(*cx);
|
||||
JS_GetPropertyById(*cx, obj, hid, &val);
|
||||
closure(key, &val);
|
||||
});
|
||||
}
|
||||
|
||||
inline void
|
||||
for_each(context &c,
|
||||
const JS::HandleObject &obj,
|
||||
for_each(const JS::HandleObject &obj,
|
||||
const closure_key_val &closure)
|
||||
{
|
||||
for_each(c, obj, [&c, &obj, &closure]
|
||||
for_each(obj, [&obj, &closure]
|
||||
(const JS::HandleId &hid)
|
||||
{
|
||||
JS::RootedValue key(c, id(c, hid)), val(c);
|
||||
JS_GetPropertyById(c, obj, hid, &val);
|
||||
JS::RootedValue key(*cx, id(hid)), val(*cx);
|
||||
JS_GetPropertyById(*cx, obj, hid, &val);
|
||||
closure(key, val);
|
||||
});
|
||||
}
|
||||
|
||||
inline void
|
||||
for_each(context &c,
|
||||
const JS::HandleObject &obj,
|
||||
for_each(const JS::HandleObject &obj,
|
||||
const closure_id &closure)
|
||||
{
|
||||
JS::Rooted<JS::IdVector> props(c, JS::IdVector(c.ptr()));
|
||||
if(JS_Enumerate(c, obj, &props))
|
||||
JS::Rooted<JS::IdVector> props(*cx, JS::IdVector(cx->ptr()));
|
||||
if(JS_Enumerate(*cx, obj, &props))
|
||||
for(size_t i(0); i < props.length(); ++i)
|
||||
closure(props[i]);
|
||||
}
|
||||
|
|
|
@ -25,64 +25,59 @@
|
|||
namespace ircd {
|
||||
namespace js {
|
||||
|
||||
JS::RootedValue id(context &, const jsid &);
|
||||
const jsid &id(context &, const JSProtoKey &);
|
||||
const jsid &id(context &, const uint32_t &);
|
||||
const jsid &id(context &, const JS::HandleString &);
|
||||
const jsid &id(context &, const JS::HandleValue &);
|
||||
JS::RootedValue id(const jsid &);
|
||||
const jsid &id(const JSProtoKey &);
|
||||
const jsid &id(const uint32_t &);
|
||||
const jsid &id(const JS::HandleString &);
|
||||
const jsid &id(const JS::HandleValue &);
|
||||
|
||||
|
||||
inline const jsid &
|
||||
id(context &c,
|
||||
const JS::HandleValue &h)
|
||||
id(const JS::HandleValue &h)
|
||||
{
|
||||
JS::RootedId ret(c);
|
||||
if(!JS_ValueToId(c, h, &ret))
|
||||
JS::RootedId ret(*cx);
|
||||
if(!JS_ValueToId(*cx, h, &ret))
|
||||
std::terminate(); //TODO: exception
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline const jsid &
|
||||
id(context &c,
|
||||
const JS::HandleString &h)
|
||||
id(const JS::HandleString &h)
|
||||
{
|
||||
JS::RootedId ret(c);
|
||||
if(!JS_StringToId(c, h, &ret))
|
||||
JS::RootedId ret(*cx);
|
||||
if(!JS_StringToId(*cx, h, &ret))
|
||||
std::terminate(); //TODO: exception
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline const jsid &
|
||||
id(context &c,
|
||||
const uint32_t &index)
|
||||
id(const uint32_t &index)
|
||||
{
|
||||
JS::RootedId ret(c);
|
||||
if(!JS_IndexToId(c, index, &ret))
|
||||
JS::RootedId ret(*cx);
|
||||
if(!JS_IndexToId(*cx, index, &ret))
|
||||
std::terminate(); //TODO: exception
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline const jsid &
|
||||
id(context &c,
|
||||
const JSProtoKey &key)
|
||||
id(const JSProtoKey &key)
|
||||
{
|
||||
JS::RootedId ret(c);
|
||||
JS::ProtoKeyToId(c, key, &ret);
|
||||
JS::RootedId ret(*cx);
|
||||
JS::ProtoKeyToId(*cx, key, &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline JS::RootedValue
|
||||
id(context &c,
|
||||
const jsid &h)
|
||||
id(const jsid &h)
|
||||
{
|
||||
JS::RootedValue ret(c);
|
||||
if(!JS_IdToValue(c, h, &ret))
|
||||
JS::RootedValue ret(*cx);
|
||||
if(!JS_IdToValue(*cx, h, &ret))
|
||||
std::terminate(); //TODO: exception
|
||||
|
||||
return { c, ret };
|
||||
return { *cx, ret };
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
|
|
@ -61,7 +61,6 @@ JSVersion version(const char *const &v) { return JS_StringToVersion(v);
|
|||
|
||||
#include "runtime.h"
|
||||
#include "context.h"
|
||||
#include "request_guard.h"
|
||||
#include "compartment_guard.h"
|
||||
#include "id.h"
|
||||
#include "string.h"
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Charybdis Development Team
|
||||
* Copyright (C) 2016 Jason Volk <jason@zemos.net>
|
||||
*
|
||||
* 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_REQUEST_GUARD_H
|
||||
|
||||
namespace ircd {
|
||||
namespace js {
|
||||
|
||||
class request_guard
|
||||
{
|
||||
JSContext *c;
|
||||
|
||||
public:
|
||||
request_guard(JSContext &);
|
||||
~request_guard() noexcept;
|
||||
};
|
||||
|
||||
inline
|
||||
request_guard::request_guard(JSContext &c)
|
||||
:c(&c)
|
||||
{
|
||||
JS_BeginRequest(&c);
|
||||
}
|
||||
|
||||
inline
|
||||
request_guard::~request_guard()
|
||||
noexcept
|
||||
{
|
||||
JS_EndRequest(c);
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
} // namespace ircd
|
|
@ -61,12 +61,18 @@ class runtime
|
|||
runtime(const runtime &) = delete;
|
||||
runtime &operator=(runtime &&) noexcept;
|
||||
runtime &operator=(const runtime &) = delete;
|
||||
~runtime() noexcept;
|
||||
|
||||
friend void interrupt(runtime &);
|
||||
};
|
||||
|
||||
// Main JSRuntime instance. This should be passable in any argument requiring a
|
||||
// JSRuntime pointer. It is only valid while the js::init object is held by ircd::main().
|
||||
// Current thread_local runtime. Runtimes/Contexts are single-threaded and we maintain
|
||||
// one per thread (or only one will be relevant on the given thread you are on).
|
||||
// Do not construct more than one runtime on the same thread- this is overwritten.
|
||||
extern __thread runtime *rt;
|
||||
|
||||
// Main JSRuntime instance. It is only valid while the js::init object is held by ircd::main().
|
||||
// This is available to always find main for whatever reason, but use *rt instead.
|
||||
extern runtime main;
|
||||
|
||||
// Get to our `struct runtime` from any upstream JSRuntime
|
||||
|
|
|
@ -27,12 +27,12 @@ namespace js {
|
|||
|
||||
struct script
|
||||
{
|
||||
script(JSContext &);
|
||||
script();
|
||||
~script() noexcept;
|
||||
};
|
||||
|
||||
inline
|
||||
script::script(JSContext &c)
|
||||
script::script()
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -26,60 +26,54 @@ namespace ircd {
|
|||
namespace js {
|
||||
|
||||
// C++ --> JS
|
||||
JSString &string(context &, const std::string &);
|
||||
JS::RootedString string(context &, const std::string &, rooted_t);
|
||||
JSString &string(const std::string &);
|
||||
JS::RootedString string(const std::string &, rooted_t);
|
||||
|
||||
// JS --> C++
|
||||
std::string string(context &, const JSString &);
|
||||
std::string string(context &, const JSString *const &);
|
||||
std::string string(const JSString &);
|
||||
std::string string(const JSString *const &);
|
||||
|
||||
std::string string(context &, const JS::Value &);
|
||||
std::string string(context &, const jsid &);
|
||||
std::string string(const JS::Value &);
|
||||
std::string string(const jsid &);
|
||||
|
||||
|
||||
inline std::string
|
||||
string(context &c,
|
||||
const jsid &hid)
|
||||
string(const jsid &hid)
|
||||
{
|
||||
return string(c, id(c, hid));
|
||||
return string(id(hid));
|
||||
}
|
||||
|
||||
inline std::string
|
||||
string(context &c,
|
||||
const JS::Value &s)
|
||||
string(const JS::Value &s)
|
||||
{
|
||||
return s.isString()? string(c, s.toString()) : std::string{};
|
||||
return s.isString()? string(s.toString()) : std::string{};
|
||||
}
|
||||
|
||||
inline std::string
|
||||
string(context &c,
|
||||
const JSString *const &s)
|
||||
string(const JSString *const &s)
|
||||
{
|
||||
return s? string(c, *s) : std::string{};
|
||||
return s? string(*s) : std::string{};
|
||||
}
|
||||
|
||||
inline std::string
|
||||
string(context &c,
|
||||
const JSString &s)
|
||||
string(const JSString &s)
|
||||
{
|
||||
std::string ret(JS_GetStringEncodingLength(c, const_cast<JSString *>(&s)), char());
|
||||
JS_EncodeStringToBuffer(c, const_cast<JSString *>(&s), &ret.front(), ret.size());
|
||||
std::string ret(JS_GetStringEncodingLength(*cx, const_cast<JSString *>(&s)), char());
|
||||
JS_EncodeStringToBuffer(*cx, const_cast<JSString *>(&s), &ret.front(), ret.size());
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline JS::RootedString
|
||||
string(context &c,
|
||||
const std::string &s,
|
||||
string(const std::string &s,
|
||||
rooted_t)
|
||||
{
|
||||
return { c, &string(c, s) };
|
||||
return { *cx, &string(s) };
|
||||
}
|
||||
|
||||
inline JSString &
|
||||
string(context &c,
|
||||
const std::string &s)
|
||||
string(const std::string &s)
|
||||
{
|
||||
const auto ret(JS_NewStringCopyN(c, s.data(), s.size()));
|
||||
const auto ret(JS_NewStringCopyN(*cx, s.data(), s.size()));
|
||||
if(unlikely(!ret))
|
||||
std::terminate(); //TODO: exception
|
||||
|
||||
|
|
|
@ -31,14 +31,14 @@ class trap
|
|||
const JSClass _class;
|
||||
|
||||
// Override these to define JS objects in C
|
||||
virtual bool on_add(context &, const JSObject &, const jsid &, const JS::Value &);
|
||||
virtual bool on_set(context &, const JSObject &, const jsid &, JS::MutableHandleValue);
|
||||
virtual bool on_get(context &, const JSObject &, const jsid &, JS::MutableHandleValue);
|
||||
virtual bool on_del(context &, const JSObject &, const jsid &);
|
||||
virtual bool on_res(context &, const JSObject &, const jsid &, bool &resolved);
|
||||
virtual bool on_enu(context &, const JSObject &);
|
||||
virtual bool on_call(context &, const unsigned &argc, JS::Value &argv);
|
||||
virtual bool on_ctor(context &, const unsigned &argc, JS::Value &argv);
|
||||
virtual bool on_add(const JSObject &, const jsid &, const JS::Value &);
|
||||
virtual bool on_set(const JSObject &, const jsid &, JS::MutableHandleValue);
|
||||
virtual bool on_get(const JSObject &, const jsid &, JS::MutableHandleValue);
|
||||
virtual bool on_del(const JSObject &, const jsid &);
|
||||
virtual bool on_res(const JSObject &, const jsid &, bool &resolved);
|
||||
virtual bool on_enu(const JSObject &);
|
||||
virtual bool on_call(const unsigned &argc, JS::Value &argv);
|
||||
virtual bool on_ctor(const unsigned &argc, JS::Value &argv);
|
||||
|
||||
private:
|
||||
static trap &from(const JSObject &);
|
||||
|
@ -61,8 +61,8 @@ class trap
|
|||
auto &name() const { return _name; }
|
||||
auto &jsclass() const { return _class; }
|
||||
|
||||
JSObject *operator()(context &, JS::HandleObject proto);
|
||||
JSObject *operator()(context &);
|
||||
JSObject *operator()(JS::HandleObject proto);
|
||||
JSObject *operator()();
|
||||
|
||||
trap(std::string name, const uint32_t &flags = 0);
|
||||
trap(trap &&) = delete;
|
||||
|
|
128
ircd/js.cc
128
ircd/js.cc
|
@ -27,6 +27,11 @@
|
|||
namespace ircd {
|
||||
namespace js {
|
||||
|
||||
// Location of the thread_local runtext. externs exist in js/runtime.h and js/context.h.
|
||||
// If these are null, js is not available on your thread.
|
||||
__thread runtime *rt;
|
||||
__thread context *cx;
|
||||
|
||||
// Location of the main JSRuntime instance. An extern reference to this exists in js/runtime.h.
|
||||
// It is null until js::init manually constructs (and later destructs) it.
|
||||
runtime main;
|
||||
|
@ -135,16 +140,15 @@ noexcept
|
|||
}
|
||||
|
||||
JSObject *
|
||||
ircd::js::trap::operator()(context &c)
|
||||
ircd::js::trap::operator()()
|
||||
{
|
||||
return JS_NewObject(c, &_class);
|
||||
return JS_NewObject(*cx, &_class);
|
||||
}
|
||||
|
||||
JSObject *
|
||||
ircd::js::trap::operator()(context &c,
|
||||
JS::HandleObject proto)
|
||||
ircd::js::trap::operator()(JS::HandleObject proto)
|
||||
{
|
||||
return JS_NewObjectWithGivenProto(c, &_class, proto);
|
||||
return JS_NewObjectWithGivenProto(*cx, &_class, proto);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -158,6 +162,8 @@ ircd::js::trap::handle_ctor(JSContext *const c,
|
|||
unsigned argc,
|
||||
JS::Value *const argv)
|
||||
{
|
||||
assert(&our(c) == cx);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -166,6 +172,8 @@ ircd::js::trap::handle_call(JSContext *const c,
|
|||
unsigned argc,
|
||||
JS::Value *const argv)
|
||||
{
|
||||
assert(&our(c) == cx);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -173,8 +181,10 @@ bool
|
|||
ircd::js::trap::handle_enu(JSContext *const c,
|
||||
JS::HandleObject obj)
|
||||
{
|
||||
assert(&our(c) == cx);
|
||||
|
||||
auto &trap(from(obj));
|
||||
return trap.on_enu(our(c), *obj.get());
|
||||
return trap.on_enu(*obj.get());
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -183,8 +193,10 @@ ircd::js::trap::handle_res(JSContext *const c,
|
|||
JS::HandleId id,
|
||||
bool *const resolved)
|
||||
{
|
||||
assert(&our(c) == cx);
|
||||
|
||||
auto &trap(from(obj));
|
||||
return trap.on_res(our(c), *obj.get(), id.get(), *resolved);
|
||||
return trap.on_res(*obj.get(), id.get(), *resolved);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -193,8 +205,10 @@ ircd::js::trap::handle_del(JSContext *const c,
|
|||
JS::HandleId id,
|
||||
JS::ObjectOpResult &res)
|
||||
{
|
||||
assert(&our(c) == cx);
|
||||
|
||||
auto &trap(from(obj));
|
||||
if(!trap.on_del(our(c), *obj.get(), id.get()))
|
||||
if(!trap.on_del(*obj.get(), id.get()))
|
||||
return false;
|
||||
|
||||
res.succeed();
|
||||
|
@ -207,8 +221,10 @@ ircd::js::trap::handle_get(JSContext *const c,
|
|||
JS::HandleId id,
|
||||
JS::MutableHandleValue val)
|
||||
{
|
||||
assert(&our(c) == cx);
|
||||
|
||||
auto &trap(from(obj));
|
||||
return trap.on_get(our(c), *obj.get(), id.get(), val);
|
||||
return trap.on_get(*obj.get(), id.get(), val);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -218,8 +234,10 @@ ircd::js::trap::handle_set(JSContext *const c,
|
|||
JS::MutableHandleValue val,
|
||||
JS::ObjectOpResult &res)
|
||||
{
|
||||
assert(&our(c) == cx);
|
||||
|
||||
auto &trap(from(obj));
|
||||
return trap.on_get(our(c), *obj.get(), id.get(), val);
|
||||
return trap.on_get(*obj.get(), id.get(), val);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -228,8 +246,10 @@ ircd::js::trap::handle_add(JSContext *const c,
|
|||
JS::HandleId id,
|
||||
JS::HandleValue val)
|
||||
{
|
||||
assert(&our(c) == cx);
|
||||
|
||||
auto &trap(from(obj));
|
||||
return trap.on_add(our(c), *obj.get(), id.get(), val.get());
|
||||
return trap.on_add(*obj.get(), id.get(), val.get());
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -238,6 +258,8 @@ ircd::js::trap::handle_inst(JSContext *const c,
|
|||
JS::MutableHandleValue val,
|
||||
bool *const has_instance)
|
||||
{
|
||||
assert(&our(c) == cx);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -267,31 +289,27 @@ ircd::js::trap::from(const JSObject &o)
|
|||
}
|
||||
|
||||
bool
|
||||
ircd::js::trap::on_ctor(context &c,
|
||||
const unsigned &argc,
|
||||
ircd::js::trap::on_ctor(const unsigned &argc,
|
||||
JS::Value &argv)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::js::trap::on_call(context &c,
|
||||
const unsigned &argc,
|
||||
ircd::js::trap::on_call(const unsigned &argc,
|
||||
JS::Value &argv)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::js::trap::on_enu(context &c,
|
||||
const JSObject &obj)
|
||||
ircd::js::trap::on_enu(const JSObject &obj)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::js::trap::on_res(context &c,
|
||||
const JSObject &obj,
|
||||
ircd::js::trap::on_res(const JSObject &obj,
|
||||
const jsid &id,
|
||||
bool &resolved)
|
||||
{
|
||||
|
@ -299,16 +317,14 @@ ircd::js::trap::on_res(context &c,
|
|||
}
|
||||
|
||||
bool
|
||||
ircd::js::trap::on_del(context &c,
|
||||
const JSObject &obj,
|
||||
ircd::js::trap::on_del(const JSObject &obj,
|
||||
const jsid &id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::js::trap::on_get(context &c,
|
||||
const JSObject &obj,
|
||||
ircd::js::trap::on_get(const JSObject &obj,
|
||||
const jsid &id,
|
||||
JS::MutableHandleValue val)
|
||||
{
|
||||
|
@ -316,8 +332,7 @@ ircd::js::trap::on_get(context &c,
|
|||
}
|
||||
|
||||
bool
|
||||
ircd::js::trap::on_set(context &c,
|
||||
const JSObject &obj,
|
||||
ircd::js::trap::on_set(const JSObject &obj,
|
||||
const jsid &id,
|
||||
JS::MutableHandleValue val)
|
||||
{
|
||||
|
@ -325,8 +340,7 @@ ircd::js::trap::on_set(context &c,
|
|||
}
|
||||
|
||||
bool
|
||||
ircd::js::trap::on_add(context &c,
|
||||
const JSObject &obj,
|
||||
ircd::js::trap::on_add(const JSObject &obj,
|
||||
const jsid &id,
|
||||
const JS::Value &val)
|
||||
{
|
||||
|
@ -499,7 +513,15 @@ ircd::js::context::context(JSRuntime *const &runtime,
|
|||
}
|
||||
,opts{opts}
|
||||
{
|
||||
assert(&our(runtime) == rt); // Trying to construct on thread without runtime thread_local
|
||||
|
||||
// Use their privdata pointer to point to our instance. We can then use our(JSContext*)
|
||||
// to get back to `this` instance. Remember the pointer must change when this class is
|
||||
// std::move()'ed etc via the move constructor/assignment.
|
||||
JS_SetContextPrivate(get(), this);
|
||||
|
||||
// Assign the thread_local here.
|
||||
cx = this;
|
||||
}
|
||||
|
||||
ircd::js::context::context(context &&other)
|
||||
|
@ -510,6 +532,9 @@ noexcept
|
|||
// Branch not taken for null/defaulted instance of JSContext smart ptr
|
||||
if(!!*this)
|
||||
JS_SetContextPrivate(get(), this);
|
||||
|
||||
// Ensure the thread_local points here now.
|
||||
cx = this;
|
||||
}
|
||||
|
||||
ircd::js::context &
|
||||
|
@ -517,16 +542,43 @@ ircd::js::context::operator=(context &&other)
|
|||
noexcept
|
||||
{
|
||||
static_cast<custom_ptr<JSContext> &>(*this) = std::move(other);
|
||||
|
||||
opts = std::move(other.opts);
|
||||
|
||||
// Branch not taken for null/defaulted instance of JSContext smart ptr
|
||||
if(!!*this)
|
||||
JS_SetContextPrivate(get(), this);
|
||||
|
||||
// Ensure the thread_local points here now.
|
||||
cx = this;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ircd::js::context::~context()
|
||||
noexcept
|
||||
{
|
||||
// Branch not taken on std::move()
|
||||
if(!!*this)
|
||||
cx = nullptr;
|
||||
}
|
||||
|
||||
ircd::js::context::lock::lock()
|
||||
:lock{*cx}
|
||||
{
|
||||
}
|
||||
|
||||
ircd::js::context::lock::lock(context &c)
|
||||
:c{&c}
|
||||
{
|
||||
JS_BeginRequest(c);
|
||||
}
|
||||
|
||||
ircd::js::context::lock::~lock()
|
||||
noexcept
|
||||
{
|
||||
JS_EndRequest(*c);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ircd/js/runtime.h
|
||||
|
@ -540,8 +592,13 @@ ircd::js::runtime::runtime(const struct opts &opts)
|
|||
}
|
||||
,opts(opts)
|
||||
{
|
||||
// We use their privdata to find `this` via our(JSRuntime*) function.
|
||||
// Any additional user privdata will have to ride a member in this class itself.
|
||||
JS_SetRuntimePrivate(get(), this);
|
||||
|
||||
// Assign the thread_local runtime pointer here.
|
||||
rt = this;
|
||||
|
||||
JS_SetErrorReporter(get(), handle_error);
|
||||
JS::SetOutOfMemoryCallback(get(), handle_out_of_memory, nullptr);
|
||||
JS::SetLargeAllocationFailureCallback(get(), handle_large_allocation_failure, nullptr);
|
||||
|
@ -562,6 +619,9 @@ noexcept
|
|||
// Branch not taken for null/defaulted instance of JSRuntime smart ptr
|
||||
if(!!*this)
|
||||
JS_SetRuntimePrivate(get(), this);
|
||||
|
||||
// Ensure the thread_local runtime always points here
|
||||
rt = this;
|
||||
}
|
||||
|
||||
ircd::js::runtime &
|
||||
|
@ -569,16 +629,26 @@ ircd::js::runtime::operator=(runtime &&other)
|
|||
noexcept
|
||||
{
|
||||
static_cast<custom_ptr<JSRuntime> &>(*this) = std::move(other);
|
||||
|
||||
opts = std::move(other.opts);
|
||||
|
||||
// Branch not taken for null/defaulted instance of JSRuntime smart ptr
|
||||
if(!!*this)
|
||||
JS_SetRuntimePrivate(get(), this);
|
||||
|
||||
// Ensure the thread_local runtime always points here
|
||||
rt = this;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ircd::js::runtime::~runtime()
|
||||
noexcept
|
||||
{
|
||||
// Branch not taken on std::move()
|
||||
if(!!*this)
|
||||
rt = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::js::runtime::handle_interrupt(JSContext *const ctx)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue