mirror of
https://github.com/matrix-construct/construct
synced 2024-06-02 18:18:56 +02:00
ircd::js: Customize GC; emancipation from template types.
This commit is contained in:
parent
d30b7ef1f6
commit
abf1dda3a6
|
@ -30,11 +30,10 @@ struct contract
|
|||
{
|
||||
using closure = std::function<value ()>;
|
||||
|
||||
heap_object future;
|
||||
object future;
|
||||
|
||||
operator const heap_object &() const { return future; }
|
||||
operator heap_object &() { return future; }
|
||||
operator object() const { return future; }
|
||||
operator const object &() const { return future; }
|
||||
operator object &() { return future; }
|
||||
operator value() const { return future; }
|
||||
|
||||
// Enter this closure and return or throw to complete the result contract.
|
||||
|
|
|
@ -30,7 +30,7 @@ struct jserror
|
|||
{
|
||||
IRCD_OVERLOAD(pending)
|
||||
|
||||
root<JS::Value, lifetime::heap> val;
|
||||
root<JS::Value> val;
|
||||
|
||||
void generate_what_js(const JSErrorReport &report);
|
||||
void generate_what_our(const JSErrorReport &report);
|
||||
|
|
|
@ -31,19 +31,15 @@ string name(const JSFunction *const *);
|
|||
uint16_t arity(const JSFunction *const &);
|
||||
bool is_ctor(const JSFunction *const &);
|
||||
|
||||
namespace basic {
|
||||
|
||||
template<lifetime L>
|
||||
struct function
|
||||
:root<JSFunction *, L>
|
||||
:root<JSFunction *>
|
||||
{
|
||||
operator JSObject *() const;
|
||||
explicit operator script<L>() const;
|
||||
explicit operator string<L>() const;
|
||||
explicit operator script() const;
|
||||
explicit operator string() const;
|
||||
|
||||
// js::value/js::object == lifetime::stack
|
||||
value<L> operator()(const js::object::handle &, const vector<js::value>::handle &) const;
|
||||
template<class... args> value<L> operator()(const js::object::handle &, args&&...) const;
|
||||
value operator()(const object::handle &, const vector<value>::handle &) const;
|
||||
template<class... args> value operator()(const object::handle &, args&&...) const;
|
||||
|
||||
// new function
|
||||
template<class string_t>
|
||||
|
@ -53,46 +49,36 @@ struct function
|
|||
const std::vector<string_t> &args,
|
||||
const string_t &src);
|
||||
|
||||
using root<JSFunction *, L>::root;
|
||||
function(const handle<value<L>> &);
|
||||
function(const js::value &);
|
||||
using root<JSFunction *>::root;
|
||||
function(const value::handle &);
|
||||
function(const value &);
|
||||
function(JSFunction *const &);
|
||||
function(JSFunction &);
|
||||
};
|
||||
|
||||
} // namespace basic
|
||||
|
||||
using function = basic::function<lifetime::stack>;
|
||||
using heap_function = basic::function<lifetime::heap>;
|
||||
|
||||
//
|
||||
// Implementation
|
||||
//
|
||||
namespace basic {
|
||||
|
||||
template<lifetime L>
|
||||
function<L>::function(JSFunction &func)
|
||||
:function<L>::root::type{&func}
|
||||
inline
|
||||
function::function(JSFunction &func)
|
||||
:function::root::type{&func}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
function<L>::function(JSFunction *const &func)
|
||||
:function<L>::root::type{func}
|
||||
inline
|
||||
function::function(JSFunction *const &func)
|
||||
:function::root::type{func}
|
||||
{
|
||||
if(unlikely(!this->get()))
|
||||
throw internal_error("NULL function");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
function<L>::function(const js::value &val)
|
||||
:function{static_cast<js::value::handle>(val)}
|
||||
inline
|
||||
function::function(const value &val)
|
||||
:function{static_cast<value::handle>(val)}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
function<L>::function(const handle<value<L>> &val)
|
||||
:function<L>::root::type
|
||||
inline
|
||||
function::function(const value::handle &val)
|
||||
:function::root::type
|
||||
{
|
||||
JS_ValueToFunction(*cx, val)
|
||||
}
|
||||
|
@ -101,14 +87,13 @@ function<L>::function(const handle<value<L>> &val)
|
|||
throw type_error("value is not a function");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
template<class string_t>
|
||||
function<L>::function(JS::AutoObjectVector &stack,
|
||||
function::function(JS::AutoObjectVector &stack,
|
||||
const JS::CompileOptions &opts,
|
||||
const char *const &name,
|
||||
const std::vector<string_t> &args,
|
||||
const string_t &src)
|
||||
:function<L>::root::type{}
|
||||
:function::root::type{}
|
||||
{
|
||||
std::vector<const typename string_t::value_type *> argp(args.size());
|
||||
std::transform(begin(args), end(args), begin(argp), []
|
||||
|
@ -131,46 +116,37 @@ function<L>::function(JS::AutoObjectVector &stack,
|
|||
}
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
template<class... args>
|
||||
value<L>
|
||||
function<L>::operator()(const js::object::handle &that,
|
||||
args&&... a)
|
||||
value
|
||||
function::operator()(const object::handle &that,
|
||||
args&&... a)
|
||||
const
|
||||
{
|
||||
vector<basic::value<lifetime::stack>> argv
|
||||
{{
|
||||
const vector<value> argv
|
||||
{
|
||||
std::forward<args>(a)...
|
||||
}};
|
||||
};
|
||||
|
||||
return call(*this, that, decltype(argv)::handle(argv));
|
||||
const vector<value>::handle handle(argv);
|
||||
return operator()(that, handle);
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>
|
||||
function<L>::operator()(const js::object::handle &that,
|
||||
const vector<js::value>::handle &argv)
|
||||
const
|
||||
{
|
||||
return call(*this, that, argv);
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
function<L>::operator string<L>()
|
||||
inline
|
||||
function::operator string()
|
||||
const
|
||||
{
|
||||
return decompile(*this, true);
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
function<L>::operator script<L>()
|
||||
inline
|
||||
function::operator script()
|
||||
const
|
||||
{
|
||||
return JS_GetFunctionScript(*cx, *this);
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
function<L>::operator JSObject *()
|
||||
inline
|
||||
function::operator JSObject *()
|
||||
const
|
||||
{
|
||||
const auto ret(JS_GetFunctionObject(this->get()));
|
||||
|
@ -180,8 +156,6 @@ const
|
|||
return ret;
|
||||
}
|
||||
|
||||
} // namespace basic
|
||||
|
||||
inline bool
|
||||
is_ctor(const JSFunction *const &f)
|
||||
{
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace ircd {
|
|||
namespace js {
|
||||
|
||||
class function_literal
|
||||
:public root<JSFunction *, lifetime::persist>
|
||||
:public root<JSFunction *>
|
||||
{
|
||||
const char *name;
|
||||
const char *text;
|
||||
|
|
|
@ -27,8 +27,8 @@ namespace js {
|
|||
|
||||
struct generator
|
||||
{
|
||||
heap_object state;
|
||||
heap_object last;
|
||||
object state;
|
||||
object last;
|
||||
|
||||
bool done() const;
|
||||
template<class... args> value next(args&&...);
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace ircd {
|
|||
namespace js {
|
||||
|
||||
class global
|
||||
:public heap_object
|
||||
:public object
|
||||
{
|
||||
static void handle_trace(JSTracer *, JSObject *) noexcept;
|
||||
|
||||
|
|
|
@ -24,124 +24,103 @@
|
|||
|
||||
namespace ircd {
|
||||
namespace js {
|
||||
namespace basic {
|
||||
|
||||
template<lifetime L>
|
||||
struct id
|
||||
:root<jsid, L>
|
||||
:root<jsid>
|
||||
{
|
||||
operator value<L>() const;
|
||||
operator value() const;
|
||||
|
||||
using root<jsid, L>::root;
|
||||
using root<jsid>::root;
|
||||
explicit id(const char *const &); // creates new id
|
||||
explicit id(const std::string &); // creates new id
|
||||
id(const typename string<L>::handle &);
|
||||
id(const typename value<L>::handle &);
|
||||
id(const value<L> &);
|
||||
id(const string<L> &);
|
||||
id(const string::handle &);
|
||||
id(const value::handle &);
|
||||
id(const value &);
|
||||
id(const string &);
|
||||
id(const JSProtoKey &);
|
||||
id(const uint32_t &);
|
||||
id(const jsid &);
|
||||
id();
|
||||
};
|
||||
|
||||
} // namespace basic
|
||||
|
||||
using id = basic::id<lifetime::stack>;
|
||||
using heap_id = basic::id<lifetime::heap>;
|
||||
|
||||
bool operator==(const handle<id> &, const char *const &);
|
||||
bool operator==(const handle<id> &, const std::string &);
|
||||
bool operator==(const char *const &, const handle<id> &);
|
||||
bool operator==(const std::string &, const handle<id> &);
|
||||
|
||||
//
|
||||
// Implementation
|
||||
//
|
||||
namespace basic {
|
||||
|
||||
template<lifetime L>
|
||||
id<L>::id()
|
||||
:id<L>::root::type{}
|
||||
inline
|
||||
id::id()
|
||||
:id::root::type{}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
id<L>::id(const jsid &i)
|
||||
:id<L>::root::type{i}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
id<L>::id(const uint32_t &index)
|
||||
:id<L>::root::type{}
|
||||
inline
|
||||
id::id(const uint32_t &index)
|
||||
:id::root::type{}
|
||||
{
|
||||
if(!JS_IndexToId(*cx, index, &(*this)))
|
||||
throw type_error("Failed to construct id from uint32_t index");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
id<L>::id(const JSProtoKey &key)
|
||||
:id<L>::root::type{}
|
||||
inline
|
||||
id::id(const JSProtoKey &key)
|
||||
:id::root::type{}
|
||||
{
|
||||
JS::ProtoKeyToId(*cx, key, &(*this));
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
id<L>::id(const std::string &str)
|
||||
inline
|
||||
id::id(const std::string &str)
|
||||
:id(str.c_str())
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
id<L>::id(const char *const &str)
|
||||
:id<L>::root::type{jsid()}
|
||||
inline
|
||||
id::id(const char *const &str)
|
||||
:id::root::type{jsid()}
|
||||
{
|
||||
if(!JS::PropertySpecNameToPermanentId(*cx, str, this->address()))
|
||||
if(!JS::PropertySpecNameToPermanentId(*cx, str, const_cast<jsid *>(this->address())))
|
||||
throw type_error("Failed to create id from native string");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
id<L>::id(const string<L> &h)
|
||||
:id<L>::id(typename string<L>::handle(h))
|
||||
inline
|
||||
id::id(const string &h)
|
||||
:id::id(string::handle(h))
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
id<L>::id(const value<L> &h)
|
||||
:id<L>::id(typename value<L>::handle(h))
|
||||
inline
|
||||
id::id(const value &h)
|
||||
:id::id(value::handle(h))
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
id<L>::id(const typename value<L>::handle &h)
|
||||
:id<L>::root::type{}
|
||||
inline
|
||||
id::id(const value::handle &h)
|
||||
:id::root::type{}
|
||||
{
|
||||
if(!JS_ValueToId(*cx, h, &(*this)))
|
||||
throw type_error("Failed to construct id from Value");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
id<L>::id(const typename string<L>::handle &h)
|
||||
:id<L>::root::type{}
|
||||
inline
|
||||
id::id(const string::handle &h)
|
||||
:id::root::type{}
|
||||
{
|
||||
if(!JS_StringToId(*cx, h, &(*this)))
|
||||
throw type_error("Failed to construct id from String");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
id<L>::operator value<L>()
|
||||
inline
|
||||
id::operator value()
|
||||
const
|
||||
{
|
||||
value<L> ret;
|
||||
value ret;
|
||||
if(!JS_IdToValue(*cx, *this, &ret))
|
||||
throw type_error("Failed to construct id from String");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace basic
|
||||
|
||||
inline bool
|
||||
operator==(const std::string &a, const handle<id> &b)
|
||||
{
|
||||
|
|
|
@ -27,10 +27,10 @@ namespace js {
|
|||
namespace json {
|
||||
|
||||
using closure = std::function<bool (const char16_t *, uint32_t)>;
|
||||
void stringify(const value::handle_mutable &, const JS::HandleObject &fmtr, const value::handle &sp, const closure &);
|
||||
void stringify(const value::handle_mutable &, const JS::HandleObject &fmtr, const value &sp, const closure &);
|
||||
void stringify(const value::handle_mutable &, const closure &);
|
||||
|
||||
std::u16string stringify(const value::handle_mutable &, const JS::HandleObject &fmtr, const value::handle &sp);
|
||||
std::u16string stringify(const value::handle_mutable &, const JS::HandleObject &fmtr, const value &sp);
|
||||
std::u16string stringify(const value::handle_mutable &, const bool &pretty = false);
|
||||
std::u16string stringify(value &, const bool &pretty = false);
|
||||
std::u16string stringify(const value &, const bool &pretty = false);
|
||||
|
|
|
@ -42,27 +42,26 @@ uint flags(const JSObject *const &);
|
|||
JSObject *current_global(JSObject *const &);
|
||||
|
||||
// Misc utils
|
||||
bool is_extensible(const object_handle &);
|
||||
bool is_array(const object_handle &);
|
||||
bool is_extensible(const object_handle &);
|
||||
uint32_t size(const object_handle &);
|
||||
bool deep_freeze(const object_handle &);
|
||||
bool freeze(const object_handle &);
|
||||
size_t bytecodes(const object_handle &, uint8_t *const &buf, const size_t &size);
|
||||
|
||||
namespace basic {
|
||||
|
||||
template<lifetime L>
|
||||
struct object
|
||||
:root<JSObject *, L>
|
||||
:root<JSObject *>
|
||||
{
|
||||
IRCD_OVERLOAD(json)
|
||||
IRCD_OVERLOAD(array)
|
||||
IRCD_OVERLOAD(uninitialized)
|
||||
|
||||
using handle = object_handle;
|
||||
using handle_mutable = object_handle_mutable;
|
||||
|
||||
explicit operator JSString *() const;
|
||||
operator JS::Value() const;
|
||||
explicit operator JS::Value() const;
|
||||
operator value() const;
|
||||
|
||||
// for array objects
|
||||
uint32_t size() const;
|
||||
|
@ -82,13 +81,12 @@ struct object
|
|||
object(const JSClass *const &);
|
||||
|
||||
object(const uint8_t *const &bytecode, const size_t &size);
|
||||
template<class T, lifetime LL> object(const root<T, LL> &);
|
||||
using root<JSObject *, L>::root;
|
||||
using root<JSObject *>::root;
|
||||
template<class... args> object(json_t, args&&...);
|
||||
object(array_t, const size_t &length);
|
||||
object(const JS::HandleValueArray &);
|
||||
object(std::initializer_list<std::pair<const char *, value<L>>>);
|
||||
object(const value<L> &);
|
||||
object(std::initializer_list<std::pair<const char *, value>>);
|
||||
object(const value &);
|
||||
object(JSObject *const &);
|
||||
object(JSObject &);
|
||||
object(uninitialized_t);
|
||||
|
@ -97,20 +95,9 @@ struct object
|
|||
static object global(); // current_global(cx)
|
||||
};
|
||||
|
||||
} // namespace basic
|
||||
|
||||
using object = basic::object<lifetime::stack>;
|
||||
using heap_object = basic::object<lifetime::heap>;
|
||||
using persist_object = basic::object<lifetime::persist>;
|
||||
|
||||
//
|
||||
// Implementation
|
||||
//
|
||||
namespace basic {
|
||||
|
||||
template<lifetime L>
|
||||
object<L>::object()
|
||||
:object<L>::root::type
|
||||
inline
|
||||
object::object()
|
||||
:object::root::type
|
||||
{
|
||||
JS_NewPlainObject(*cx)
|
||||
}
|
||||
|
@ -119,39 +106,39 @@ object<L>::object()
|
|||
throw internal_error("NULL object (plain)");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
object<L>::object(uninitialized_t)
|
||||
:object<L>::root::type{}
|
||||
inline
|
||||
object::object(uninitialized_t)
|
||||
:object::root::type{}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
object<L>::object(JSObject &obj)
|
||||
:object<L>::root::type{&obj}
|
||||
inline
|
||||
object::object(JSObject &obj)
|
||||
:object::root::type{&obj}
|
||||
{
|
||||
if(unlikely(!this->get()))
|
||||
throw internal_error("NULL object (ref)");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
object<L>::object(JSObject *const &obj)
|
||||
:object<L>::root::type{obj}
|
||||
inline
|
||||
object::object(JSObject *const &obj)
|
||||
:object::root::type{obj}
|
||||
{
|
||||
if(unlikely(!this->get()))
|
||||
throw internal_error("NULL object");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
object<L>::object(const value<L> &val)
|
||||
:object<L>::root::type{}
|
||||
inline
|
||||
object::object(const value &val)
|
||||
:object::root::type{}
|
||||
{
|
||||
if(!JS_ValueToObject(*cx, val, &(*this)))
|
||||
throw type_error("Value is not an Object");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
object<L>::object(std::initializer_list<std::pair<const char *, value<L>>> list)
|
||||
:object<L>{}
|
||||
inline
|
||||
object::object(std::initializer_list<std::pair<const char *, value>> list)
|
||||
:object{}
|
||||
{
|
||||
for(const auto &pair : list)
|
||||
{
|
||||
|
@ -162,9 +149,9 @@ object<L>::object(std::initializer_list<std::pair<const char *, value<L>>> list)
|
|||
}
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
object<L>::object(const JS::HandleValueArray &values)
|
||||
:object<L>::root::type
|
||||
inline
|
||||
object::object(const JS::HandleValueArray &values)
|
||||
:object::root::type
|
||||
{
|
||||
JS_NewArrayObject(*cx, values)
|
||||
}
|
||||
|
@ -173,10 +160,10 @@ object<L>::object(const JS::HandleValueArray &values)
|
|||
throw internal_error("NULL object (array)");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
object<L>::object(array_t,
|
||||
const size_t &length)
|
||||
:object<L>::root::type
|
||||
inline
|
||||
object::object(array_t,
|
||||
const size_t &length)
|
||||
:object::root::type
|
||||
{
|
||||
JS_NewArrayObject(*cx, length)
|
||||
}
|
||||
|
@ -185,27 +172,16 @@ object<L>::object(array_t,
|
|||
throw internal_error("NULL object (array)");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
template<class... args>
|
||||
object<L>::object(json_t,
|
||||
args&&... a)
|
||||
:object<L>(js::json::parse(std::forward<args>(a)...))
|
||||
object::object(json_t,
|
||||
args&&... a)
|
||||
:object(js::json::parse(std::forward<args>(a)...))
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
template<class T,
|
||||
lifetime LL>
|
||||
object<L>::object(const root<T, LL> &o)
|
||||
:object{o.get()}
|
||||
{
|
||||
if(unlikely(!this->get()))
|
||||
throw internal_error("NULL object (cross-lifetime)");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
object<L>::object(const JSClass *const &clasp)
|
||||
:object<L>::root::type
|
||||
inline
|
||||
object::object(const JSClass *const &clasp)
|
||||
:object::root::type
|
||||
{
|
||||
JS_NewObject(*cx, clasp)
|
||||
}
|
||||
|
@ -214,10 +190,10 @@ object<L>::object(const JSClass *const &clasp)
|
|||
throw internal_error("NULL object (clasp)");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
object<L>::object(const JSClass *const &clasp,
|
||||
const object &proto)
|
||||
:object<L>::root::type
|
||||
inline
|
||||
object::object(const JSClass *const &clasp,
|
||||
const object &proto)
|
||||
:object::root::type
|
||||
{
|
||||
JS_NewObjectWithGivenProto(*cx, clasp, proto)
|
||||
}
|
||||
|
@ -226,10 +202,10 @@ object<L>::object(const JSClass *const &clasp,
|
|||
throw internal_error("NULL object (with given proto)");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
object<L>::object(const JSClass *const &clasp,
|
||||
const JS::CallArgs &args)
|
||||
:object<L>::root::type
|
||||
inline
|
||||
object::object(const JSClass *const &clasp,
|
||||
const JS::CallArgs &args)
|
||||
:object::root::type
|
||||
{
|
||||
JS_NewObjectForConstructor(*cx, clasp, args)
|
||||
}
|
||||
|
@ -238,11 +214,11 @@ object<L>::object(const JSClass *const &clasp,
|
|||
throw internal_error("NULL object (for constructor)");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
object<L>::object(const JSClass *const &clasp,
|
||||
const object::handle &ctor,
|
||||
const JS::HandleValueArray &args)
|
||||
:object<L>::root::type
|
||||
inline
|
||||
object::object(const JSClass *const &clasp,
|
||||
const object::handle &ctor,
|
||||
const JS::HandleValueArray &args)
|
||||
:object::root::type
|
||||
{
|
||||
JS_New(*cx, ctor, args)
|
||||
}
|
||||
|
@ -251,10 +227,10 @@ object<L>::object(const JSClass *const &clasp,
|
|||
throw internal_error("NULL object (new)");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
object<L>::object(const uint8_t *const &bytecode,
|
||||
const size_t &size)
|
||||
:object<L>::root::type
|
||||
inline
|
||||
object::object(const uint8_t *const &bytecode,
|
||||
const size_t &size)
|
||||
:object::root::type
|
||||
{
|
||||
JS_DecodeInterpretedFunction(*cx, bytecode, size)
|
||||
}
|
||||
|
@ -263,32 +239,28 @@ object<L>::object(const uint8_t *const &bytecode,
|
|||
throw jserror(jserror::pending);
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
object<L>
|
||||
object<L>::global()
|
||||
inline object
|
||||
object::global()
|
||||
{
|
||||
return current_global();
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
object<L>
|
||||
object<L>::constructor()
|
||||
inline object
|
||||
object::constructor()
|
||||
const
|
||||
{
|
||||
return JS_GetConstructor(*cx, *this);
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
void
|
||||
object<L>::prototype(object::handle obj)
|
||||
inline void
|
||||
object::prototype(object::handle obj)
|
||||
{
|
||||
if(!JS_SetPrototype(*cx, *this, obj))
|
||||
throw internal_error("Failed to set prototype for object");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
object<L>
|
||||
object<L>::prototype()
|
||||
inline object
|
||||
object::prototype()
|
||||
const
|
||||
{
|
||||
object ret;
|
||||
|
@ -298,39 +270,43 @@ const
|
|||
return ret;
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
void
|
||||
object<L>::resize(const uint32_t &length)
|
||||
inline void
|
||||
object::resize(const uint32_t &length)
|
||||
{
|
||||
if(!JS_SetArrayLength(*cx, *this, length))
|
||||
throw internal_error("Failed to set array object length");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
uint32_t
|
||||
object<L>::size()
|
||||
inline uint32_t
|
||||
object::size()
|
||||
const
|
||||
{
|
||||
return js::size(*this);
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
object<L>::operator JSString *()
|
||||
inline
|
||||
object::operator JSString *()
|
||||
const
|
||||
{
|
||||
assert(this->get());
|
||||
return JS_BasicObjectToString(*cx, *this);
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
object<L>::operator JS::Value()
|
||||
inline
|
||||
object::operator value()
|
||||
const
|
||||
{
|
||||
assert(this->get());
|
||||
return JS::ObjectValue(*this->get());
|
||||
}
|
||||
|
||||
} // namespace basic
|
||||
inline
|
||||
object::operator JS::Value()
|
||||
const
|
||||
{
|
||||
assert(this->get());
|
||||
return JS::ObjectValue(*this->get());
|
||||
}
|
||||
|
||||
inline size_t
|
||||
bytecodes(const object_handle &obj,
|
||||
|
@ -370,6 +346,12 @@ size(const object_handle &obj)
|
|||
return ret;
|
||||
}
|
||||
|
||||
inline bool
|
||||
is_array(const object &obj)
|
||||
{
|
||||
return is_array(object::handle(obj));
|
||||
}
|
||||
|
||||
inline bool
|
||||
is_array(const object_handle &obj)
|
||||
{
|
||||
|
|
|
@ -25,22 +25,6 @@
|
|||
namespace ircd {
|
||||
namespace js {
|
||||
|
||||
enum class lifetime
|
||||
{
|
||||
stack, // entity lives on the stack and the GC uses a cheap forward list between objects
|
||||
heap, // entity lives on the heap with dynamic duration
|
||||
tenured, // long-life-optimized heap entity with special rules (must read jsapi docs)
|
||||
persist, // entity has duration similar to the runtime itself
|
||||
maybe, // template with a boolean switch for GC participation
|
||||
fake, // noop; does not register with GC at all
|
||||
};
|
||||
|
||||
template<class T,
|
||||
lifetime L>
|
||||
struct root
|
||||
{
|
||||
};
|
||||
|
||||
template<class T>
|
||||
using handle = typename T::handle;
|
||||
|
||||
|
@ -79,17 +63,19 @@ operator&(JS::TenuredHeap<T> &h)
|
|||
}
|
||||
|
||||
template<class T>
|
||||
struct root<T, lifetime::stack>
|
||||
:JS::Rooted<T>
|
||||
struct root
|
||||
:JS::Heap<T>
|
||||
{
|
||||
using base_type = JS::Rooted<T>;
|
||||
using type = root<T, lifetime::stack>;
|
||||
using handle_mutable = JS::MutableHandle<T>;
|
||||
using value_type = T;
|
||||
using base_type = JS::Heap<T>;
|
||||
using handle = JS::Handle<T>;
|
||||
using handle_mutable = JS::MutableHandle<T>;
|
||||
using type = root<value_type>;
|
||||
|
||||
operator handle() const
|
||||
{
|
||||
return JS::Handle<T>::fromMarkedLocation(this->address());
|
||||
const auto ptr(this->address());
|
||||
return JS::Handle<T>::fromMarkedLocation(ptr);
|
||||
}
|
||||
|
||||
operator handle_mutable()
|
||||
|
@ -98,73 +84,10 @@ struct root<T, lifetime::stack>
|
|||
return JS::MutableHandle<T>::fromMarkedLocation(ptr);
|
||||
}
|
||||
|
||||
root(const handle &h)
|
||||
:JS::Rooted<T>{*cx, h}
|
||||
{
|
||||
}
|
||||
|
||||
root(const handle_mutable &h)
|
||||
:JS::Rooted<T>{*cx, h}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
root(const root<T, L> &other)
|
||||
:JS::Rooted<T>{*cx, other.get()}
|
||||
{
|
||||
}
|
||||
|
||||
explicit root(const T &t)
|
||||
:JS::Rooted<T>{*cx, t}
|
||||
{
|
||||
}
|
||||
|
||||
root()
|
||||
:JS::Rooted<T>{*cx}
|
||||
{
|
||||
}
|
||||
|
||||
root(root&& other)
|
||||
noexcept
|
||||
:JS::Rooted<T>{*cx, other.get()}
|
||||
{
|
||||
other.set(nullptr);
|
||||
}
|
||||
|
||||
root(const root &other)
|
||||
:JS::Rooted<T>{*cx, other.get()}
|
||||
{
|
||||
}
|
||||
|
||||
root &operator=(root &&other)
|
||||
noexcept
|
||||
{
|
||||
this->set(other.get());
|
||||
other.set(nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
root &operator=(const root &other)
|
||||
{
|
||||
this->set(other.get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
~root() noexcept = default;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct root<T, lifetime::heap>
|
||||
:JS::Heap<T>
|
||||
{
|
||||
using type = root<T, lifetime::heap>;
|
||||
using handle = JS::Handle<T>;
|
||||
using handle_mutable = JS::MutableHandle<T>;
|
||||
|
||||
private:
|
||||
tracing::list::iterator tracing_it;
|
||||
|
||||
tracing::list::iterator add(JS::Heap<T> *const &ptr)
|
||||
tracing::list::iterator add(base_type *const &ptr)
|
||||
{
|
||||
return rt->tracing.heap.emplace(end(rt->tracing.heap), tracing::thing { ptr, js::type<T>() });
|
||||
}
|
||||
|
@ -179,71 +102,53 @@ struct root<T, lifetime::heap>
|
|||
}
|
||||
|
||||
public:
|
||||
operator handle() const
|
||||
{
|
||||
return JS::Handle<T>::fromMarkedLocation(this->address());
|
||||
}
|
||||
|
||||
operator handle_mutable()
|
||||
{
|
||||
const auto ptr(const_cast<T *>(this->address()));
|
||||
return JS::MutableHandle<T>::fromMarkedLocation(ptr);
|
||||
}
|
||||
|
||||
root(const handle &h)
|
||||
:JS::Heap<T>{h}
|
||||
:base_type{h.get()}
|
||||
,tracing_it{add(this)}
|
||||
{
|
||||
}
|
||||
|
||||
root(const handle_mutable &h)
|
||||
:JS::Heap<T>{h}
|
||||
,tracing_it{add(this)}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
root(const root<T, L> &other)
|
||||
:JS::Heap<T>{other}
|
||||
:base_type{h.get()}
|
||||
,tracing_it{add(this)}
|
||||
{
|
||||
}
|
||||
|
||||
explicit root(const T &t)
|
||||
:JS::Heap<T>{t}
|
||||
:base_type{t}
|
||||
,tracing_it{add(this)}
|
||||
{
|
||||
}
|
||||
|
||||
root()
|
||||
:JS::Heap<T>{}
|
||||
:base_type{}
|
||||
,tracing_it{add(this)}
|
||||
{
|
||||
}
|
||||
|
||||
root(root &&other) noexcept
|
||||
:JS::Heap<T>{other.get()}
|
||||
:base_type{other.get()}
|
||||
,tracing_it{std::move(other.tracing_it)}
|
||||
{
|
||||
other.tracing_it = end(rt->tracing.heap);
|
||||
tracing_it->ptr = static_cast<JS::Heap<T> *>(this);
|
||||
tracing_it->ptr = static_cast<base_type *>(this);
|
||||
}
|
||||
|
||||
root(const root &other)
|
||||
:JS::Heap<T>{other}
|
||||
:base_type{other.get()}
|
||||
,tracing_it{add(this)}
|
||||
{
|
||||
}
|
||||
|
||||
root &operator=(root &&other) noexcept
|
||||
{
|
||||
JS::Heap<T>::operator=(std::move(other));
|
||||
base_type::operator=(std::move(other.get()));
|
||||
return *this;
|
||||
}
|
||||
|
||||
root &operator=(const root &other)
|
||||
{
|
||||
JS::Heap<T>::operator=(other);
|
||||
base_type::operator=(other.get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -253,114 +158,5 @@ struct root<T, lifetime::heap>
|
|||
}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct root<T, lifetime::tenured>
|
||||
:JS::TenuredHeap<T>
|
||||
{
|
||||
using type = root<T, lifetime::tenured>;
|
||||
using handle_mutable = JS::MutableHandle<T>;
|
||||
using handle = JS::Handle<T>;
|
||||
|
||||
operator handle() const
|
||||
{
|
||||
return JS::Handle<T>::fromMarkedLocation(this->address());
|
||||
}
|
||||
|
||||
operator handle_mutable()
|
||||
{
|
||||
const auto ptr(const_cast<T *>(this->address()));
|
||||
return JS::MutableHandle<T>::fromMarkedLocation(ptr);
|
||||
}
|
||||
|
||||
auto operator&() const
|
||||
{
|
||||
return static_cast<handle>(*this);
|
||||
}
|
||||
|
||||
auto operator&()
|
||||
{
|
||||
return static_cast<handle_mutable>(*this);
|
||||
}
|
||||
|
||||
root(const handle &h)
|
||||
:JS::TenuredHeap<T>{h}
|
||||
{
|
||||
}
|
||||
|
||||
root(const handle_mutable &h)
|
||||
:JS::TenuredHeap<T>{h}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
root(const root<T, L> &other)
|
||||
:JS::TenuredHeap<T>{other.get()}
|
||||
{
|
||||
}
|
||||
|
||||
explicit root(const T &t)
|
||||
:JS::TenuredHeap<T>{t}
|
||||
{
|
||||
}
|
||||
|
||||
root()
|
||||
:JS::TenuredHeap<T>{}
|
||||
{
|
||||
}
|
||||
|
||||
root(root&&) = default;
|
||||
root(const root &) = default;
|
||||
root &operator=(root &&) = default;
|
||||
root &operator=(const root &) = default;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct root<T, lifetime::persist>
|
||||
:JS::PersistentRooted<T>
|
||||
{
|
||||
using type = root<T, lifetime::persist>;
|
||||
using handle_mutable = JS::MutableHandle<T>;
|
||||
using handle = JS::Handle<T>;
|
||||
|
||||
template<lifetime L>
|
||||
root(const root<T, L> &other)
|
||||
:JS::PersistentRooted<T>{*cx, other.get()}
|
||||
{
|
||||
}
|
||||
|
||||
explicit root(const T &t)
|
||||
:JS::PersistentRooted<T>{*cx, t}
|
||||
{
|
||||
}
|
||||
|
||||
root()
|
||||
:JS::PersistentRooted<T>{*cx}
|
||||
{
|
||||
}
|
||||
|
||||
root(root&& other)
|
||||
noexcept
|
||||
:JS::PersistentRooted<T>{*cx, other.get()}
|
||||
{
|
||||
}
|
||||
|
||||
root(const root &) = delete;
|
||||
root &operator=(const root &) = delete;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct root<T, lifetime::maybe>
|
||||
:public ::js::MaybeRooted<T, ::js::CanGC>
|
||||
{
|
||||
using type = root<T, lifetime::maybe>;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct root<T, lifetime::fake>
|
||||
:public ::js::FakeRooted<T>
|
||||
{
|
||||
using type = root<T, lifetime::fake>;
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
} // namespace ircd
|
||||
|
|
|
@ -31,18 +31,15 @@ size_t bytecodes(const JS::Handle<JSScript *> &, uint8_t *const &buf, const size
|
|||
bool compilable(const char *const &str, const size_t &len, const object &stack = {});
|
||||
bool compilable(const std::string &str, const object &stack = {});
|
||||
|
||||
namespace basic {
|
||||
|
||||
template<lifetime L>
|
||||
struct script
|
||||
:root<JSScript *, L>
|
||||
:root<JSScript *>
|
||||
{
|
||||
IRCD_OVERLOAD(yielding)
|
||||
|
||||
value<lifetime::stack> operator()(JS::AutoObjectVector &stack) const;
|
||||
value<lifetime::stack> operator()() const;
|
||||
value operator()(JS::AutoObjectVector &stack) const;
|
||||
value operator()() const;
|
||||
|
||||
using root<JSScript *, L>::root;
|
||||
using root<JSScript *>::root;
|
||||
script(yielding_t, const JS::ReadOnlyCompileOptions &opts, const std::u16string &src);
|
||||
script(const JS::ReadOnlyCompileOptions &opts, const std::u16string &src);
|
||||
script(const JS::ReadOnlyCompileOptions &opts, const std::string &src);
|
||||
|
@ -51,34 +48,24 @@ struct script
|
|||
script(JSScript &);
|
||||
};
|
||||
|
||||
} // namespace basic
|
||||
|
||||
using script = basic::script<lifetime::stack>;
|
||||
using heap_script = basic::script<lifetime::heap>;
|
||||
|
||||
//
|
||||
// Implementation
|
||||
//
|
||||
namespace basic {
|
||||
|
||||
template<lifetime L>
|
||||
script<L>::script(JSScript &val)
|
||||
:script<L>::root::type{&val}
|
||||
inline
|
||||
script::script(JSScript &val)
|
||||
:script::root::type{&val}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
script<L>::script(JSScript *const &val)
|
||||
:script<L>::root::type{val}
|
||||
inline
|
||||
script::script(JSScript *const &val)
|
||||
:script::root::type{val}
|
||||
{
|
||||
if(unlikely(!this->get()))
|
||||
throw internal_error("NULL script");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
script<L>::script(const uint8_t *const &bytecode,
|
||||
const size_t &size)
|
||||
:script<L>::root::type
|
||||
inline
|
||||
script::script(const uint8_t *const &bytecode,
|
||||
const size_t &size)
|
||||
:script::root::type
|
||||
{
|
||||
JS_DecodeScript(*cx, bytecode, size)
|
||||
}
|
||||
|
@ -87,29 +74,29 @@ script<L>::script(const uint8_t *const &bytecode,
|
|||
throw jserror(jserror::pending);
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
script<L>::script(const JS::ReadOnlyCompileOptions &opts,
|
||||
const std::string &src)
|
||||
:script<L>::root::type{}
|
||||
inline
|
||||
script::script(const JS::ReadOnlyCompileOptions &opts,
|
||||
const std::string &src)
|
||||
:script::root::type{}
|
||||
{
|
||||
if(!JS::Compile(*cx, opts, src.data(), src.size(), &(*this)))
|
||||
throw jserror(jserror::pending);
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
script<L>::script(const JS::ReadOnlyCompileOptions &opts,
|
||||
const std::u16string &src)
|
||||
:script<L>::root::type{}
|
||||
inline
|
||||
script::script(const JS::ReadOnlyCompileOptions &opts,
|
||||
const std::u16string &src)
|
||||
:script::root::type{}
|
||||
{
|
||||
if(!JS::Compile(*cx, opts, src.data(), src.size(), &(*this)))
|
||||
throw jserror(jserror::pending);
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
script<L>::script(yielding_t,
|
||||
const JS::ReadOnlyCompileOptions &opts,
|
||||
const std::u16string &src)
|
||||
:script<L>::root::type{[&opts, &src]
|
||||
inline
|
||||
script::script(yielding_t,
|
||||
const JS::ReadOnlyCompileOptions &opts,
|
||||
const std::u16string &src)
|
||||
:script::root::type{[&opts, &src]
|
||||
{
|
||||
// This constructor compiles the script concurrently by yielding this ircd::ctx.
|
||||
// The compilation occurs on another thread entirely, so other ircd contexts will
|
||||
|
@ -124,30 +111,27 @@ script<L>::script(yielding_t,
|
|||
throw jserror(jserror::pending);
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<lifetime::stack>
|
||||
script<L>::operator()()
|
||||
inline value
|
||||
script::operator()()
|
||||
const
|
||||
{
|
||||
value<lifetime::stack> ret;
|
||||
value ret;
|
||||
if(!JS_ExecuteScript(*cx, *this, &ret))
|
||||
throw jserror(jserror::pending);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<lifetime::stack>
|
||||
script<L>::operator()(JS::AutoObjectVector &stack)
|
||||
inline value
|
||||
script::operator()(JS::AutoObjectVector &stack)
|
||||
const
|
||||
{
|
||||
value<lifetime::stack> ret;
|
||||
value ret;
|
||||
if(!JS_ExecuteScript(*cx, stack, *this, &ret))
|
||||
throw jserror(jserror::pending);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace basic
|
||||
} // namespace js
|
||||
} // namespace ircd
|
||||
|
|
|
@ -43,11 +43,8 @@ const size_t CSTR_BUFS = 8;
|
|||
const size_t CSTR_BUFSIZE = 1024;
|
||||
char *c_str(const JSString *const &);
|
||||
|
||||
namespace basic {
|
||||
|
||||
template<lifetime L>
|
||||
struct string
|
||||
:root<JSString *, L>
|
||||
:root<JSString *>
|
||||
{
|
||||
IRCD_OVERLOAD(pinned)
|
||||
IRCD_OVERLOAD(literal)
|
||||
|
@ -60,9 +57,9 @@ struct string
|
|||
|
||||
operator std::string() const;
|
||||
operator std::u16string() const;
|
||||
operator JS::Value() const;
|
||||
operator value() const;
|
||||
|
||||
using root<JSString *, L>::root;
|
||||
using root<JSString *>::root;
|
||||
string(pinned_t, const char16_t *const &);
|
||||
string(pinned_t, const char *const &);
|
||||
string(pinned_t, const string &);
|
||||
|
@ -73,7 +70,7 @@ struct string
|
|||
string(const char *const &, const size_t &len);
|
||||
string(const std::string &);
|
||||
string(const char *const &);
|
||||
string(const value<L> &);
|
||||
string(const value &);
|
||||
string(JSString *const &);
|
||||
string(JSString &);
|
||||
string();
|
||||
|
@ -81,7 +78,6 @@ struct string
|
|||
struct less
|
||||
{
|
||||
using is_transparent = std::true_type;
|
||||
|
||||
template<class A, class B> bool operator()(const A &, const B &) const;
|
||||
};
|
||||
};
|
||||
|
@ -89,15 +85,15 @@ struct string
|
|||
template<class T> constexpr bool is_string();
|
||||
template<class A, class B> constexpr bool string_argument();
|
||||
|
||||
template<lifetime L> auto hash(const string<L> &s);
|
||||
auto hash(const string &s);
|
||||
|
||||
template<lifetime A, lifetime B> int cmp(const string<A> &a, const string<B> &b);
|
||||
template<lifetime L> int cmp(const char *const &a, const string<L> &b);
|
||||
template<lifetime L> int cmp(const string<L> &a, const char *const &b);
|
||||
template<lifetime L> int cmp(const string<L> &a, const std::string &b);
|
||||
template<lifetime L> int cmp(const std::string &a, const string<L> &b);
|
||||
template<lifetime L> bool operator==(const string<L> &a, const char *const &b);
|
||||
template<lifetime L> bool operator==(const char *const &a, const string<L> &b);
|
||||
int cmp(const string &a, const string &b);
|
||||
int cmp(const char *const &a, const string &b);
|
||||
int cmp(const string &a, const char *const &b);
|
||||
int cmp(const string &a, const std::string &b);
|
||||
int cmp(const std::string &a, const string &b);
|
||||
bool operator==(const string &a, const char *const &b);
|
||||
bool operator==(const char *const &a, const string &b);
|
||||
|
||||
template<class A,
|
||||
class B>
|
||||
|
@ -111,80 +107,66 @@ template<class A, class B> string_comparison<A, B> operator<=(const A &a, const
|
|||
template<class A, class B> string_comparison<A, B> operator==(const A &a, const B &b);
|
||||
template<class A, class B> string_comparison<A, B> operator!=(const A &a, const B &b);
|
||||
|
||||
template<lifetime L>
|
||||
using string_pair = std::pair<string<L>, string<L>>;
|
||||
template<lifetime L> string_pair<L> split(const string<L> &s, const char &c);
|
||||
template<lifetime L> string_pair<L> split(const string<L> &s, const char16_t &c);
|
||||
template<lifetime L> string<L> substr(const string<L> &s, const size_t &pos, const size_t &len);
|
||||
template<lifetime L> string<L> operator+(const string<L> &left, const string<L> &right);
|
||||
using string_pair = std::pair<string, string>;
|
||||
string_pair split(const string &s, const char &c);
|
||||
string_pair split(const string &s, const char16_t &c);
|
||||
string substr(const string &s, const size_t &pos, const size_t &len);
|
||||
string operator+(const string &left, const string &right);
|
||||
|
||||
template<class string> using string_closure = std::function<void (const string &)>;
|
||||
template<lifetime L> void tokens(const string<L> &, const char &sep, const string_closure<string<L>> &);
|
||||
void tokens(const string &, const char &sep, const string_closure<string> &);
|
||||
|
||||
template<lifetime L> std::ostream & operator<<(std::ostream &os, const string<L> &s);
|
||||
std::ostream & operator<<(std::ostream &os, const string &s);
|
||||
|
||||
} // namespace basic
|
||||
|
||||
using string = basic::string<lifetime::stack>;
|
||||
using heap_string = basic::string<lifetime::heap>;
|
||||
using persist_string = basic::string<lifetime::persist>;
|
||||
|
||||
using basic::hash;
|
||||
|
||||
//
|
||||
// Implementation
|
||||
//
|
||||
namespace basic {
|
||||
|
||||
template<lifetime L>
|
||||
string<L>::string()
|
||||
:string<L>::root::type
|
||||
inline
|
||||
string::string()
|
||||
:string::root::type
|
||||
{
|
||||
JS_GetEmptyString(*rt)
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
string<L>::string(JSString &val)
|
||||
:string<L>::root::type{&val}
|
||||
inline
|
||||
string::string(JSString &val)
|
||||
:string::root::type{&val}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
string<L>::string(JSString *const &val)
|
||||
:string<L>::root::type
|
||||
inline
|
||||
string::string(JSString *const &val)
|
||||
:string::root::type
|
||||
{
|
||||
likely(val)? val : throw internal_error("NULL string")
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
string<L>::string(const value<L> &val)
|
||||
:string<L>::root::type
|
||||
inline
|
||||
string::string(const value &val)
|
||||
:string::root::type
|
||||
{
|
||||
JS::ToString(*cx, val)?: throw type_error("Failed to convert value to string")
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
string<L>::string(const std::string &s)
|
||||
inline
|
||||
string::string(const std::string &s)
|
||||
:string(s.data(), s.size())
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
string<L>::string(const char *const &s)
|
||||
inline
|
||||
string::string(const char *const &s)
|
||||
:string(s, strlen(s))
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
string<L>::string(const char *const &s,
|
||||
const size_t &len)
|
||||
:string<L>::root::type{[&s, &len]
|
||||
inline
|
||||
string::string(const char *const &s,
|
||||
const size_t &len)
|
||||
:string::root::type{[&s, &len]
|
||||
{
|
||||
if(!s || !*s)
|
||||
return JS_GetEmptyString(*rt);
|
||||
|
@ -197,22 +179,22 @@ string<L>::string(const char *const &s,
|
|||
throw type_error("Failed to construct string from character array");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
string<L>::string(const std::u16string &s)
|
||||
inline
|
||||
string::string(const std::u16string &s)
|
||||
:string(s.data(), s.size())
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
string<L>::string(const char16_t *const &s)
|
||||
inline
|
||||
string::string(const char16_t *const &s)
|
||||
:string(s, std::char_traits<char16_t>::length(s))
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
string<L>::string(const char16_t *const &s,
|
||||
const size_t &len)
|
||||
:string<L>::root::type{[&s, &len]
|
||||
inline
|
||||
string::string(const char16_t *const &s,
|
||||
const size_t &len)
|
||||
:string::root::type{[&s, &len]
|
||||
{
|
||||
if(!s || !*s)
|
||||
return JS_GetEmptyString(*rt);
|
||||
|
@ -229,10 +211,10 @@ string<L>::string(const char16_t *const &s,
|
|||
throw type_error("Failed to construct string from character array");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
string<L>::string(literal_t,
|
||||
const char16_t *const &s)
|
||||
:string<L>::root::type
|
||||
inline
|
||||
string::string(literal_t,
|
||||
const char16_t *const &s)
|
||||
:string::root::type
|
||||
{
|
||||
s && *s?
|
||||
JS_NewExternalString(*cx, s, std::char_traits<char16_t>::length(s), &native_external_static):
|
||||
|
@ -243,10 +225,10 @@ string<L>::string(literal_t,
|
|||
throw type_error("Failed to construct string from wide character literal");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
string<L>::string(pinned_t,
|
||||
const string &s)
|
||||
:string<L>::root::type
|
||||
inline
|
||||
string::string(pinned_t,
|
||||
const string &s)
|
||||
:string::root::type
|
||||
{
|
||||
JS_AtomizeAndPinJSString(*cx, s)
|
||||
}
|
||||
|
@ -255,10 +237,10 @@ string<L>::string(pinned_t,
|
|||
throw type_error("Failed to intern JSString");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
string<L>::string(pinned_t,
|
||||
const char *const &s)
|
||||
:string<L>::root::type
|
||||
inline
|
||||
string::string(pinned_t,
|
||||
const char *const &s)
|
||||
:string::root::type
|
||||
{
|
||||
JS_AtomizeAndPinStringN(*cx, s, strlen(s))
|
||||
}
|
||||
|
@ -267,10 +249,10 @@ string<L>::string(pinned_t,
|
|||
throw type_error("Failed to construct pinned string from character array");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
string<L>::string(pinned_t,
|
||||
const char16_t *const &s)
|
||||
:string<L>::root::type
|
||||
inline
|
||||
string::string(pinned_t,
|
||||
const char16_t *const &s)
|
||||
:string::root::type
|
||||
{
|
||||
JS_AtomizeAndPinUCStringN(*cx, s, std::char_traits<char16_t>::length(s))
|
||||
}
|
||||
|
@ -279,90 +261,83 @@ string<L>::string(pinned_t,
|
|||
throw type_error("Failed to construct pinned string from wide character array");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
char16_t
|
||||
string<L>::operator[](const size_t &pos)
|
||||
inline char16_t
|
||||
string::operator[](const size_t &pos)
|
||||
const
|
||||
{
|
||||
return at(this->get(), pos);
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
string<L>::operator JS::Value()
|
||||
inline
|
||||
string::operator value()
|
||||
const
|
||||
{
|
||||
return JS::StringValue(this->get());
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
string<L>::operator std::string()
|
||||
inline
|
||||
string::operator std::string()
|
||||
const
|
||||
{
|
||||
return native(this->get());
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
string<L>::operator std::u16string()
|
||||
inline
|
||||
string::operator std::u16string()
|
||||
const
|
||||
{
|
||||
return locale::char16::conv(native(this->get()));
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
inline
|
||||
char *
|
||||
string<L>::c_str()
|
||||
string::c_str()
|
||||
const
|
||||
{
|
||||
return js::c_str(this->get());
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
bool
|
||||
string<L>::empty()
|
||||
inline bool
|
||||
string::empty()
|
||||
const
|
||||
{
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
size_t
|
||||
string<L>::size()
|
||||
inline size_t
|
||||
string::size()
|
||||
const
|
||||
{
|
||||
return js::size(this->get());
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
size_t
|
||||
string<L>::native_size()
|
||||
inline size_t
|
||||
string::native_size()
|
||||
const
|
||||
{
|
||||
return js::native_size(this->get());
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
template<class A,
|
||||
class B>
|
||||
bool
|
||||
string<L>::less::operator()(const A &a, const B &b)
|
||||
string::less::operator()(const A &a, const B &b)
|
||||
const
|
||||
{
|
||||
return cmp(a, b) < 0;
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const string<L> &s)
|
||||
inline std::ostream &
|
||||
operator<<(std::ostream &os, const string &s)
|
||||
{
|
||||
os << std::string(s);
|
||||
return os;
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
void
|
||||
tokens(const string<L> &str,
|
||||
inline void
|
||||
tokens(const string &str,
|
||||
const char &sep,
|
||||
const string_closure<string<L>> &closure)
|
||||
const string_closure<string> &closure)
|
||||
{
|
||||
for(auto pair(split(str, sep));; pair = split(pair.second, sep))
|
||||
{
|
||||
|
@ -372,17 +347,15 @@ tokens(const string<L> &str,
|
|||
}
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
std::pair<string<L>, string<L>>
|
||||
split(const string<L> &s,
|
||||
inline std::pair<string, string>
|
||||
split(const string &s,
|
||||
const char &c)
|
||||
{
|
||||
return split(s, char16_t(c));
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
std::pair<string<L>, string<L>>
|
||||
split(const string<L> &s,
|
||||
inline std::pair<string, string>
|
||||
split(const string &s,
|
||||
const char16_t &c)
|
||||
{
|
||||
size_t i(0);
|
||||
|
@ -390,13 +363,12 @@ split(const string<L> &s,
|
|||
return
|
||||
{
|
||||
substr(s, 0, i),
|
||||
i < size(s)? substr(s, i + 1, size(s) - i) : string<L>()
|
||||
i < size(s)? substr(s, i + 1, size(s) - i) : string()
|
||||
};
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
string<L>
|
||||
substr(const string<L> &s,
|
||||
inline string
|
||||
substr(const string &s,
|
||||
const size_t &pos,
|
||||
const size_t &len)
|
||||
{
|
||||
|
@ -408,10 +380,9 @@ substr(const string<L> &s,
|
|||
return ret;
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
string<L>
|
||||
operator+(const string<L> &left,
|
||||
const string<L> &right)
|
||||
inline string
|
||||
operator+(const string &left,
|
||||
const string &right)
|
||||
{
|
||||
return JS_ConcatStrings(*cx, left, right);
|
||||
}
|
||||
|
@ -464,9 +435,8 @@ operator!=(const A &a, const B &b)
|
|||
return !(operator==(a, b));
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
bool
|
||||
operator==(const string<L> &a, const char *const &b)
|
||||
inline bool
|
||||
operator==(const string &a, const char *const &b)
|
||||
{
|
||||
bool ret;
|
||||
if(unlikely(!JS_StringEqualsAscii(*cx, a, b, &ret)))
|
||||
|
@ -475,9 +445,8 @@ operator==(const string<L> &a, const char *const &b)
|
|||
return ret;
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
bool
|
||||
operator==(const char *const &a, const string<L> &b)
|
||||
inline bool
|
||||
operator==(const char *const &a, const string &b)
|
||||
{
|
||||
bool ret;
|
||||
if(unlikely(!JS_StringEqualsAscii(*cx, b, a, &ret)))
|
||||
|
@ -486,43 +455,37 @@ operator==(const char *const &a, const string<L> &b)
|
|||
return ret;
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
int
|
||||
cmp(const string<L> &a,
|
||||
inline int
|
||||
cmp(const string &a,
|
||||
const std::string &b)
|
||||
{
|
||||
return cmp(a, b.c_str());
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
int
|
||||
inline int
|
||||
cmp(const std::string &a,
|
||||
const string<L> &b)
|
||||
const string &b)
|
||||
{
|
||||
return cmp(a.c_str(), b);
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
int
|
||||
cmp(const string<L> &a,
|
||||
inline int
|
||||
cmp(const string &a,
|
||||
const char *const &b)
|
||||
{
|
||||
return cmp(a, string<L>(b));
|
||||
return cmp(a, string(b));
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
int
|
||||
inline int
|
||||
cmp(const char *const &a,
|
||||
const string<L> &b)
|
||||
const string &b)
|
||||
{
|
||||
return cmp(string<L>(a), b);
|
||||
return cmp(string(a), b);
|
||||
}
|
||||
|
||||
template<lifetime A,
|
||||
lifetime B>
|
||||
int
|
||||
cmp(const string<A> &a,
|
||||
const string<B> &b)
|
||||
inline int
|
||||
cmp(const string &a,
|
||||
const string &b)
|
||||
{
|
||||
int32_t ret;
|
||||
if(unlikely(!JS_CompareStrings(*cx, a, b, &ret)))
|
||||
|
@ -531,9 +494,8 @@ cmp(const string<A> &a,
|
|||
return ret;
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
auto
|
||||
hash(const string<L> &s)
|
||||
inline auto
|
||||
hash(const string &s)
|
||||
{
|
||||
//TODO: optimize
|
||||
return ircd::util::hash(std::u16string(s));
|
||||
|
@ -551,12 +513,9 @@ template<class T>
|
|||
constexpr bool
|
||||
is_string()
|
||||
{
|
||||
return std::is_base_of<string<lifetime::stack>, T>() ||
|
||||
std::is_base_of<string<lifetime::heap>, T>();
|
||||
return std::is_base_of<string, T>();
|
||||
}
|
||||
|
||||
} // namespace basic
|
||||
|
||||
inline void
|
||||
observe(const JSString *const &str,
|
||||
const std::pair<string8_closure, string16_closure> &closure)
|
||||
|
|
|
@ -30,11 +30,11 @@ struct task
|
|||
{
|
||||
uint64_t pid; // unique process ID
|
||||
uint64_t yid; // ID of current yield attempting unification
|
||||
std::map<uint64_t, heap_object> complete; // futures waiting for yield unification
|
||||
std::map<uint64_t, heap_object> pending; // pending futures awaiting results
|
||||
std::map<uint64_t, object> complete; // futures waiting for yield unification
|
||||
std::map<uint64_t, object> pending; // pending futures awaiting results
|
||||
std::shared_ptr<task> work; // references self when there is unfinished work
|
||||
struct global global; // global / this / root scope object
|
||||
heap_script main; // main generator wrapper script
|
||||
script main; // main generator wrapper script
|
||||
struct generator generator; // generator state
|
||||
|
||||
private:
|
||||
|
@ -43,7 +43,7 @@ struct task
|
|||
bool tasks_remove();
|
||||
|
||||
public:
|
||||
bool pending_add(const uint64_t &id, heap_object);
|
||||
bool pending_add(const uint64_t &id, object);
|
||||
bool pending_del(const uint64_t &id);
|
||||
|
||||
task(const std::u16string &source);
|
||||
|
|
|
@ -30,11 +30,8 @@ template<class T> T *pointer_value(const JS::Value &);
|
|||
JS::Value pointer_value(const void *const &);
|
||||
JS::Value pointer_value(void *const &);
|
||||
|
||||
namespace basic {
|
||||
|
||||
template<lifetime L = lifetime::stack>
|
||||
struct value
|
||||
:root<JS::Value, L>
|
||||
:root<JS::Value>
|
||||
{
|
||||
IRCD_OVERLOAD(pointer)
|
||||
|
||||
|
@ -47,7 +44,6 @@ struct value
|
|||
explicit operator uint16_t() const;
|
||||
explicit operator bool() const;
|
||||
|
||||
template<class T, lifetime LL> value(const root<T, LL> &r);
|
||||
template<class T> value(const JS::MutableHandle<T> &h);
|
||||
template<class T> value(const JS::Handle<T> &h);
|
||||
value(pointer_t, void *const &);
|
||||
|
@ -67,152 +63,112 @@ struct value
|
|||
value(JS::Symbol *const &);
|
||||
value(const JS::Value &);
|
||||
value();
|
||||
value(const value &);
|
||||
};
|
||||
|
||||
template<lifetime L>
|
||||
JSType
|
||||
type(const value<L> &val)
|
||||
{
|
||||
return JS_TypeOfValue(*cx, val);
|
||||
}
|
||||
JSType type(const handle<value> &val);
|
||||
JSType type(const value &val);
|
||||
bool undefined(const handle<value> &val);
|
||||
bool undefined(const value &val);
|
||||
bool is_array(const handle<value> &val);
|
||||
bool is_array(const value &val);
|
||||
|
||||
inline JSType
|
||||
type(const handle<value<>> &val)
|
||||
{
|
||||
return JS_TypeOfValue(*cx, val);
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
bool
|
||||
undefined(const value<L> &val)
|
||||
{
|
||||
return type(val) == JSTYPE_VOID;
|
||||
}
|
||||
|
||||
inline bool
|
||||
undefined(const JS::Handle<JS::Value> &val)
|
||||
{
|
||||
return type(val) == JSTYPE_VOID;
|
||||
}
|
||||
|
||||
} // namespace basic
|
||||
|
||||
using value = basic::value<lifetime::stack>;
|
||||
using heap_value = basic::value<lifetime::heap>;
|
||||
|
||||
using basic::type;
|
||||
using basic::undefined;
|
||||
template<class value> bool is_array(const value &val);
|
||||
|
||||
//
|
||||
// Implementation
|
||||
//
|
||||
namespace basic {
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::value()
|
||||
:value<L>::root::type{JS::UndefinedValue()}
|
||||
inline
|
||||
value::value()
|
||||
:value::root::type{JS::UndefinedValue()}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::value(const value &other)
|
||||
:value<L>::root::type{other.get()}
|
||||
inline
|
||||
value::value(const JS::Value &val)
|
||||
:value::root::type{val}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::value(const JS::Value &val)
|
||||
:value<L>::root::type{val}
|
||||
inline
|
||||
value::value(JS::Symbol *const &val)
|
||||
:value::root::type{JS::SymbolValue(val)}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::value(JS::Symbol *const &val)
|
||||
:value<L>::root::type{JS::SymbolValue(val)}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::value(JSObject *const &val)
|
||||
:value<L>::root::type
|
||||
inline
|
||||
value::value(JSObject *const &val)
|
||||
:value::root::type
|
||||
{
|
||||
val? JS::ObjectValue(*val) : throw internal_error("NULL JSObject")
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::value(JSObject &val)
|
||||
:value<L>::root::type{JS::ObjectValue(val)}
|
||||
inline
|
||||
value::value(JSObject &val)
|
||||
:value::root::type{JS::ObjectValue(val)}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::value(JSString *const &val)
|
||||
:value<L>::root::type{JS::StringValue(val)}
|
||||
inline
|
||||
value::value(JSString *const &val)
|
||||
:value::root::type{JS::StringValue(val)}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::value(JSFunction *const &val)
|
||||
:value<L>::root::type{}
|
||||
inline
|
||||
value::value(JSFunction *const &val)
|
||||
:value::root::type{}
|
||||
{
|
||||
auto *const obj(JS_GetFunctionObject(val));
|
||||
if(unlikely(!obj))
|
||||
throw type_error("Function cannot convert to Object");
|
||||
|
||||
this->set(JS::ObjectValue(*obj));
|
||||
(*this) = JS::ObjectValue(*obj);
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::value(const jsid &val)
|
||||
:value<L>::root::type{}
|
||||
inline
|
||||
value::value(const jsid &val)
|
||||
:value::root::type{}
|
||||
{
|
||||
if(!JS_IdToValue(*cx, val, &(*this)))
|
||||
throw type_error("Failed to construct value from Id");
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::value(const bool &b)
|
||||
:value<L>::root::type{JS::BooleanValue(b)}
|
||||
inline
|
||||
value::value(const bool &b)
|
||||
:value::root::type{JS::BooleanValue(b)}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::value(const int32_t &val)
|
||||
:value<L>::root::type{JS::Int32Value(val)}
|
||||
inline
|
||||
value::value(const int32_t &val)
|
||||
:value::root::type{JS::Int32Value(val)}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::value(const uint64_t &val)
|
||||
:value<L>::root::type{JS::DoubleValue(val)}
|
||||
inline
|
||||
value::value(const uint64_t &val)
|
||||
:value::root::type{JS::DoubleValue(val)}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::value(const float &val)
|
||||
:value<L>::root::type{JS::Float32Value(val)}
|
||||
inline
|
||||
value::value(const float &val)
|
||||
:value::root::type{JS::Float32Value(val)}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::value(const double &val)
|
||||
:value<L>::root::type{JS::DoubleValue(val)}
|
||||
inline
|
||||
value::value(const double &val)
|
||||
:value::root::type{JS::DoubleValue(val)}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::value(const nullptr_t &)
|
||||
:value<L>::root::type{JS::NullValue()}
|
||||
inline
|
||||
value::value(const nullptr_t &)
|
||||
:value::root::type{JS::NullValue()}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::value(const std::string &s)
|
||||
:value<L>::root::type{[&s]
|
||||
inline
|
||||
value::value(const std::string &s)
|
||||
:value::root::type{[&s]
|
||||
{
|
||||
if(s.empty())
|
||||
return JS::StringValue(JS_GetEmptyString(*rt));
|
||||
|
@ -225,9 +181,9 @@ value<L>::value(const std::string &s)
|
|||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::value(const char *const &s)
|
||||
:value<L>::root::type{[&s]
|
||||
inline
|
||||
value::value(const char *const &s)
|
||||
:value::root::type{[&s]
|
||||
{
|
||||
if(!s || !*s)
|
||||
return JS::StringValue(JS_GetEmptyString(*rt));
|
||||
|
@ -241,44 +197,34 @@ value<L>::value(const char *const &s)
|
|||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::value(pointer_t,
|
||||
inline
|
||||
value::value(pointer_t,
|
||||
void *const &ptr)
|
||||
:value<L>::root::type{pointer_value(ptr)}
|
||||
:value::root::type{pointer_value(ptr)}
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
template<class T>
|
||||
value<L>::value(const JS::Handle<T> &h)
|
||||
value::value(const JS::Handle<T> &h)
|
||||
:value(h.get())
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
template<class T>
|
||||
value<L>::value(const JS::MutableHandle<T> &h)
|
||||
value::value(const JS::MutableHandle<T> &h)
|
||||
:value(h.get())
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
template<class T,
|
||||
lifetime LL>
|
||||
value<L>::value(const root<T, LL> &r):
|
||||
value(r.get())
|
||||
{
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::operator bool()
|
||||
inline
|
||||
value::operator bool()
|
||||
const
|
||||
{
|
||||
return JS::ToBoolean(*this);
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::operator uint16_t()
|
||||
inline
|
||||
value::operator uint16_t()
|
||||
const
|
||||
{
|
||||
uint16_t ret;
|
||||
|
@ -288,8 +234,8 @@ const
|
|||
return ret;
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::operator int32_t()
|
||||
inline
|
||||
value::operator int32_t()
|
||||
const
|
||||
{
|
||||
int32_t ret;
|
||||
|
@ -299,8 +245,8 @@ const
|
|||
return ret;
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::operator uint32_t()
|
||||
inline
|
||||
value::operator uint32_t()
|
||||
const
|
||||
{
|
||||
uint32_t ret;
|
||||
|
@ -310,8 +256,8 @@ const
|
|||
return ret;
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::operator int64_t()
|
||||
inline
|
||||
value::operator int64_t()
|
||||
const
|
||||
{
|
||||
int64_t ret;
|
||||
|
@ -321,8 +267,8 @@ const
|
|||
return ret;
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::operator uint64_t()
|
||||
inline
|
||||
value::operator uint64_t()
|
||||
const
|
||||
{
|
||||
uint64_t ret;
|
||||
|
@ -332,8 +278,8 @@ const
|
|||
return ret;
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::operator double()
|
||||
inline
|
||||
value::operator double()
|
||||
const
|
||||
{
|
||||
double ret;
|
||||
|
@ -343,19 +289,22 @@ const
|
|||
return ret;
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
value<L>::operator std::string()
|
||||
inline
|
||||
value::operator std::string()
|
||||
const
|
||||
{
|
||||
const auto s(JS::ToString(*cx, *this));
|
||||
return s? native(s) : throw type_error("Failed to cast to string");
|
||||
}
|
||||
|
||||
} // namespace basic
|
||||
|
||||
template<class value>
|
||||
bool
|
||||
inline bool
|
||||
is_array(const value &val)
|
||||
{
|
||||
return is_array(handle<value>(val));
|
||||
}
|
||||
|
||||
inline bool
|
||||
is_array(const handle<value> &val)
|
||||
{
|
||||
bool ret;
|
||||
if(!JS_IsArrayObject(*cx, val, &ret))
|
||||
|
@ -363,14 +312,31 @@ is_array(const value &val)
|
|||
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
template<class value>
|
||||
bool
|
||||
|
||||
inline bool
|
||||
undefined(const value &val)
|
||||
{
|
||||
return basic::type(val) == JSTYPE_VOID;
|
||||
return type(val) == JSTYPE_VOID;
|
||||
}
|
||||
*/
|
||||
|
||||
inline bool
|
||||
undefined(const handle<value> &val)
|
||||
{
|
||||
return type(val) == JSTYPE_VOID;
|
||||
}
|
||||
|
||||
inline JSType
|
||||
type(const value &val)
|
||||
{
|
||||
return JS_TypeOfValue(*cx, val);
|
||||
}
|
||||
|
||||
inline JSType
|
||||
type(const handle<value> &val)
|
||||
{
|
||||
return JS_TypeOfValue(*cx, val);
|
||||
}
|
||||
|
||||
inline JS::Value
|
||||
pointer_value(const void *const &ptr)
|
||||
{
|
||||
|
|
|
@ -83,7 +83,7 @@ struct vector<value>
|
|||
// Construct from initializer list of our `struct value` wrapper
|
||||
// ex: value a(1); vector foo {{ a, a, ... }};
|
||||
|
||||
vector(const std::initializer_list<heap_value> &list)
|
||||
vector(const std::initializer_list<value> &list)
|
||||
:JS::AutoVectorRooter<jsapi_type>{*cx}
|
||||
{
|
||||
reserve(list.size());
|
||||
|
@ -103,8 +103,7 @@ struct vector<value>
|
|||
infallibleAppend(value(t));
|
||||
}
|
||||
*/
|
||||
template<lifetime L>
|
||||
vector(const basic::object<L> &obj)
|
||||
vector(const object &obj)
|
||||
:JS::AutoVectorRooter<jsapi_type>{*cx}
|
||||
{
|
||||
if(!is_array(obj))
|
||||
|
@ -116,9 +115,8 @@ struct vector<value>
|
|||
infallibleAppend(get(obj, i));
|
||||
}
|
||||
|
||||
template<lifetime L>
|
||||
vector(const basic::value<L> &val)
|
||||
:vector(basic::object<L>(val))
|
||||
vector(const value &val)
|
||||
:vector(object(val))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
128
ircd/js.cc
128
ircd/js.cc
|
@ -208,7 +208,7 @@ noexcept try
|
|||
}
|
||||
catch(const std::exception &e)
|
||||
{
|
||||
set(future, "error", string(e.what()));
|
||||
set(future, "error", e.what());
|
||||
}
|
||||
|
||||
assert(cx->star);
|
||||
|
@ -260,20 +260,22 @@ try
|
|||
return global;
|
||||
}()}
|
||||
,main{[this, &source]
|
||||
() -> script
|
||||
{
|
||||
// A compartment for the global must be entered to compile in this scope
|
||||
const compartment c(this->global);
|
||||
|
||||
// TODO: options
|
||||
JS::CompileOptions opts(*cx);
|
||||
//opts.setIntroductionType("GeneratorFunction");
|
||||
//opts.forceAsync = true;
|
||||
|
||||
// The function must be compiled in this scope and returned as a heap_function
|
||||
// before the compartment destructs. The compilation is also conducted asynchronously:
|
||||
// it will yield the current ircd::ctx until it is complete.
|
||||
return heap_script { heap_script::yielding, opts, source };
|
||||
// The compilation is also conducted asynchronously: it will yield the current
|
||||
// ircd::ctx until it is complete.
|
||||
return { script::yielding, opts, source };
|
||||
}()}
|
||||
,generator{[this]
|
||||
() -> struct generator
|
||||
{
|
||||
// A compartment for the global must be entered to run the generator wrapper.
|
||||
const compartment c(this->global);
|
||||
|
@ -282,14 +284,11 @@ try
|
|||
// The run() closure provides safety for entering the JS engine.
|
||||
value state(js::run([this]
|
||||
{
|
||||
return this->main();
|
||||
return value{};
|
||||
//return this->main();
|
||||
}));
|
||||
|
||||
// Construct the generator object here on the stack while in a compartment. The
|
||||
// instance then contains returnable heap objects.
|
||||
struct generator ret(state);
|
||||
|
||||
return ret;
|
||||
return { state };
|
||||
}()}
|
||||
{
|
||||
}
|
||||
|
@ -352,7 +351,7 @@ ircd::js::task::pending_del(const uint64_t &id)
|
|||
|
||||
bool
|
||||
ircd::js::task::pending_add(const uint64_t &id,
|
||||
heap_object obj)
|
||||
object obj)
|
||||
{
|
||||
const auto iit(pending.emplace(id, std::move(obj)));
|
||||
if(!iit.second)
|
||||
|
@ -403,12 +402,10 @@ ircd::js::task::tasks_next_pid()
|
|||
ircd::js::object
|
||||
ircd::js::reflect(const task &task)
|
||||
{
|
||||
object ret;
|
||||
const object global(task.global);
|
||||
const object reflect(get(global, "Reflect"));
|
||||
const function parse(get(reflect, "parse"));
|
||||
ret = parse(global, decompile(task));
|
||||
return ret;
|
||||
return parse(global, decompile(task));
|
||||
}
|
||||
|
||||
ircd::js::string
|
||||
|
@ -426,7 +423,7 @@ ircd::js::decompile(const task &task,
|
|||
ircd::js::global::global(trap &trap,
|
||||
JSPrincipals *const &principals,
|
||||
JS::CompartmentOptions opts)
|
||||
:heap_object{[&trap, &principals, &opts]
|
||||
:object{[&trap, &principals, &opts]
|
||||
{
|
||||
opts.setTrace(handle_trace);
|
||||
return JS_NewGlobalObject(*cx, &trap.jsclass(), principals, JS::DontFireOnNewGlobalHook, opts);
|
||||
|
@ -924,7 +921,7 @@ ircd::js::trap::find(const std::string &path)
|
|||
throw error("Failed to find trap tree root");
|
||||
|
||||
trap *ret(tree);
|
||||
const auto parts(tokens(path, "."));
|
||||
const auto parts(ircd::tokens(path, "."));
|
||||
for(const auto &part : parts)
|
||||
ret = &ret->child(part);
|
||||
|
||||
|
@ -938,7 +935,7 @@ ircd::js::trap::find(const string::handle &path)
|
|||
throw error("Failed to find trap tree root");
|
||||
|
||||
trap *ret(tree);
|
||||
tokens(string(path), '.', basic::string_closure<string>([&ret]
|
||||
tokens(string(path), '.', string_closure<string>([&ret]
|
||||
(const string &part)
|
||||
{
|
||||
ret = &ret->child(part);
|
||||
|
@ -1018,7 +1015,7 @@ noexcept try
|
|||
|
||||
object ret(JS_NewObjectWithGivenProto(*cx, &trap.jsclass(), that));
|
||||
trap.on_new(that, ret, args);
|
||||
args.rval().set(std::move(ret));
|
||||
args.rval().set(JS::Value(ret));
|
||||
return true;
|
||||
}
|
||||
catch(const jserror &e)
|
||||
|
@ -1154,14 +1151,6 @@ catch(const std::exception &e)
|
|||
return false;
|
||||
}
|
||||
|
||||
namespace ircd {
|
||||
namespace js {
|
||||
|
||||
std::map<std::string, heap_value> tempo;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::js::trap::handle_getter(JSContext *const c,
|
||||
unsigned argc,
|
||||
|
@ -1171,24 +1160,16 @@ noexcept try
|
|||
using js::function;
|
||||
|
||||
const struct args args(argc, argv);
|
||||
object that(args.computeThis(c));
|
||||
function func(args.callee());
|
||||
const object that(args.computeThis(c));
|
||||
const function func(args.callee());
|
||||
const string name(js::name(func));
|
||||
|
||||
auto &trap(from(that));
|
||||
trap.debug(that.get(), "get '%s' (getter)",
|
||||
name.c_str());
|
||||
|
||||
const auto it(tempo.find(name));
|
||||
if(it == end(tempo))
|
||||
{
|
||||
//throw reference_error("%s", name.c_str());
|
||||
args.rval().set(value{});
|
||||
return true;
|
||||
}
|
||||
|
||||
heap_value &val(it->second);
|
||||
args.rval().set(val);
|
||||
//value &val(it->second);
|
||||
//args.rval().set(val);
|
||||
return true;
|
||||
}
|
||||
catch(const jserror &e)
|
||||
|
@ -1198,8 +1179,8 @@ catch(const jserror &e)
|
|||
}
|
||||
catch(const std::exception &e)
|
||||
{
|
||||
auto ca(JS::CallArgsFromVp(argc, argv));
|
||||
object that(ca.computeThis(c));
|
||||
const auto ca(JS::CallArgsFromVp(argc, argv));
|
||||
const object that(ca.computeThis(c));
|
||||
auto &trap(from(that));
|
||||
trap.host_exception(that.get(), "getter: %s", e.what());
|
||||
return false;
|
||||
|
@ -1214,11 +1195,11 @@ noexcept try
|
|||
using js::function;
|
||||
|
||||
const struct args args(argc, argv);
|
||||
object that(args.computeThis(c));
|
||||
function func(args.callee());
|
||||
const object that(args.computeThis(c));
|
||||
const function func(args.callee());
|
||||
|
||||
value val(args[0]);
|
||||
const auto type(basic::type(val));
|
||||
const value val(args[0]);
|
||||
const auto type(js::type(val));
|
||||
const string name(js::name(func));
|
||||
|
||||
auto &trap(from(that));
|
||||
|
@ -1226,22 +1207,17 @@ noexcept try
|
|||
name.c_str(),
|
||||
reflect(type));
|
||||
|
||||
auto it(tempo.lower_bound(name));
|
||||
assert(it != end(tempo));
|
||||
heap_value &hval(it->second);
|
||||
switch(js::type(type))
|
||||
{
|
||||
case jstype::OBJECT:
|
||||
{
|
||||
//const auto flags(JSPROP_SHARED);
|
||||
//object ret(JS_DefineObject(*cx, object(val), "", &trap.jsclass(), flags));
|
||||
//tempo.emplace(name, heap_value(ret));
|
||||
//args.rval().set(ret);
|
||||
//return true;
|
||||
}
|
||||
|
||||
default:
|
||||
hval = val;
|
||||
args.rval().set(val);
|
||||
return true;
|
||||
}
|
||||
|
@ -1253,8 +1229,8 @@ catch(const jserror &e)
|
|||
}
|
||||
catch(const std::exception &e)
|
||||
{
|
||||
auto ca(JS::CallArgsFromVp(argc, argv));
|
||||
object that(ca.computeThis(c));
|
||||
const auto ca(JS::CallArgsFromVp(argc, argv));
|
||||
const object that(ca.computeThis(c));
|
||||
auto &trap(from(that));
|
||||
trap.host_exception(that.get(), "setter: %s", e.what());
|
||||
return false;
|
||||
|
@ -1338,7 +1314,7 @@ noexcept try
|
|||
const string name(id);
|
||||
trap.debug(obj.get(), "add '%s' %s @%p",
|
||||
name.c_str(),
|
||||
reflect(basic::type(val)),
|
||||
reflect(type(val)),
|
||||
(const void *)val.address());
|
||||
|
||||
trap.on_add(obj, id, val);
|
||||
|
@ -1680,7 +1656,7 @@ noexcept
|
|||
ircd::js::function_literal::function_literal(const char *const &name,
|
||||
const std::initializer_list<const char *> &prototype,
|
||||
const char *const &text)
|
||||
:root<JSFunction *, lifetime::persist>{}
|
||||
:root<JSFunction *>{}
|
||||
,name{name}
|
||||
,text{text}
|
||||
,prototype{prototype}
|
||||
|
@ -1703,7 +1679,7 @@ ircd::js::function_literal::function_literal(const char *const &name,
|
|||
|
||||
ircd::js::function_literal::function_literal(function_literal &&other)
|
||||
noexcept
|
||||
:root<JSFunction *, lifetime::persist>
|
||||
:root<JSFunction *>
|
||||
{
|
||||
std::move(other)
|
||||
}
|
||||
|
@ -1718,6 +1694,14 @@ noexcept
|
|||
// ircd/js/function.h
|
||||
//
|
||||
|
||||
ircd::js::value
|
||||
ircd::js::function::operator()(const object::handle &that,
|
||||
const vector<value>::handle &argv)
|
||||
const
|
||||
{
|
||||
return call(*this, that, argv);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ircd/js/for_each.h
|
||||
|
@ -1736,10 +1720,9 @@ ircd::js::for_each(object::handle obj,
|
|||
const each_key_val &closure)
|
||||
{
|
||||
for_each(obj, flags, each_id([&obj, &closure]
|
||||
(const id &hid)
|
||||
(const id &key)
|
||||
{
|
||||
const value val(get(obj, hid));
|
||||
const value key(hid);
|
||||
const value val(get(obj, key));
|
||||
closure(key, val);
|
||||
}));
|
||||
}
|
||||
|
@ -1759,8 +1742,7 @@ ircd::js::for_each(object::handle obj,
|
|||
for_each(obj, flags, each_id([&obj, &closure]
|
||||
(const id &id)
|
||||
{
|
||||
const value key(id);
|
||||
closure(key);
|
||||
closure(id);
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -1843,7 +1825,7 @@ ircd::js::del(const object::handle &src,
|
|||
value val;
|
||||
object obj(src);
|
||||
const char *fail(nullptr);
|
||||
tokens(path, ".", [&path, &val, &obj, &fail]
|
||||
ircd::tokens(path, ".", [&path, &val, &obj, &fail]
|
||||
(char *const &part)
|
||||
{
|
||||
if(fail)
|
||||
|
@ -1920,7 +1902,7 @@ ircd::js::set(const object::handle &src,
|
|||
object obj(src);
|
||||
char buffer[strlen(path) + 1];
|
||||
const char *fail(nullptr), *key(nullptr);
|
||||
tokens(path, ".", buffer, sizeof(buffer), [&path, &tmp, &obj, &fail, &key]
|
||||
ircd::tokens(path, ".", buffer, sizeof(buffer), [&path, &tmp, &obj, &fail, &key]
|
||||
(const char *const &part)
|
||||
{
|
||||
if(fail)
|
||||
|
@ -2011,7 +1993,7 @@ ircd::js::get(const object::handle &src,
|
|||
value ret;
|
||||
object obj(src);
|
||||
const char *fail(nullptr);
|
||||
tokens(path, ".", [&obj, &path, &ret, &fail]
|
||||
ircd::tokens(path, ".", [&obj, &path, &ret, &fail]
|
||||
(const char *const &part)
|
||||
{
|
||||
if(fail)
|
||||
|
@ -2075,7 +2057,7 @@ ircd::js::has(const object::handle &src,
|
|||
bool ret(true);
|
||||
object obj(src);
|
||||
const char *fail(nullptr);
|
||||
tokens(path, ".", [&obj, &path, &ret, &fail]
|
||||
ircd::tokens(path, ".", [&obj, &path, &ret, &fail]
|
||||
(const char *const &part)
|
||||
{
|
||||
if(fail)
|
||||
|
@ -2257,16 +2239,16 @@ ircd::js::json::stringify(const value::handle_mutable &val,
|
|||
{
|
||||
const object fmtr;
|
||||
const string sp(string::literal, pretty? u"\t" : u"");
|
||||
return stringify(val, fmtr, value(sp));
|
||||
return stringify(val, fmtr, sp);
|
||||
}
|
||||
|
||||
std::u16string
|
||||
ircd::js::json::stringify(const value::handle_mutable &value,
|
||||
ircd::js::json::stringify(const value::handle_mutable &val,
|
||||
const JS::HandleObject &fmtr,
|
||||
const value::handle &sp)
|
||||
const value &sp)
|
||||
{
|
||||
std::u16string ret;
|
||||
stringify(value, fmtr, sp, [&ret]
|
||||
stringify(val, fmtr, sp, [&ret]
|
||||
(const char16_t *const &ptr, const uint &len)
|
||||
{
|
||||
ret.assign(ptr, len);
|
||||
|
@ -2286,12 +2268,12 @@ ircd::js::json::stringify(const value::handle_mutable &val,
|
|||
}
|
||||
|
||||
void
|
||||
ircd::js::json::stringify(const value::handle_mutable &value,
|
||||
ircd::js::json::stringify(const value::handle_mutable &val,
|
||||
const JS::HandleObject &fmtr,
|
||||
const value::handle &sp,
|
||||
const value &sp,
|
||||
const closure &cont)
|
||||
{
|
||||
if(!JS_Stringify(*cx, value, fmtr, sp, write_callback, const_cast<closure *>(&cont)))
|
||||
if(!JS_Stringify(*cx, val, fmtr, sp, write_callback, const_cast<closure *>(&cont)))
|
||||
throw jserror(jserror::pending);
|
||||
}
|
||||
|
||||
|
@ -3978,6 +3960,10 @@ ircd::js::trace_heap(JSTracer *const &tracer,
|
|||
|
||||
case jstype::SYMBOL:
|
||||
{
|
||||
const auto ptr(reinterpret_cast<JS::Heap<JS::Symbol *> *>(thing.ptr));
|
||||
if(!ptr->get())
|
||||
break;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue