0
0
Fork 0
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:
Jason Volk 2016-11-25 00:15:27 -08:00
parent d30b7ef1f6
commit abf1dda3a6
16 changed files with 505 additions and 882 deletions

View file

@ -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.

View file

@ -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);

View file

@ -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)
{

View file

@ -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;

View file

@ -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&&...);

View file

@ -26,7 +26,7 @@ namespace ircd {
namespace js {
class global
:public heap_object
:public object
{
static void handle_trace(JSTracer *, JSObject *) noexcept;

View file

@ -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)
{

View file

@ -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);

View file

@ -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)
{

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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);

View file

@ -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)
{

View file

@ -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))
{
}

View file

@ -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;
}