0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-06-17 17:38:22 +02:00

ircd::js: Upgrade SpiderMonkey to esr52 from esr45.

This commit is contained in:
Jason Volk 2017-08-23 15:25:22 -06:00
parent 1f4b21458f
commit 4d4a56fe9c
32 changed files with 2700 additions and 2010 deletions

7
.gitmodules vendored
View file

@ -1,6 +1,3 @@
[submodule "boost"]
path = boost
url = https://github.com/boostorg/boost.git
[submodule "rocksdb"] [submodule "rocksdb"]
path = rocksdb path = rocksdb
url = https://github.com/facebook/rocksdb.git url = https://github.com/facebook/rocksdb.git
@ -8,3 +5,7 @@
path = gecko-dev path = gecko-dev
url = https://github.com/mozilla/gecko-dev.git url = https://github.com/mozilla/gecko-dev.git
branch = esr45 branch = esr45
[submodule "boost"]
path = boost
url = https://github.com/boostorg/boost.git
branch = boost-1.64.0

View file

@ -733,34 +733,36 @@ AC_HELP_STRING([--with-included-js[[[=shared]]]], [Use the JS engine (SpiderMonk
JS_LDFLAGS+=" -L$PWD/gecko-dev/js/src/build_OPT.OBJ/js/src" JS_LDFLAGS+=" -L$PWD/gecko-dev/js/src/build_OPT.OBJ/js/src"
AC_SUBST(JS_LIBS) AC_SUBST(JS_LIBS)
JS_LIBS+=" -lmozjs-45" JS_LIBS+=" -lmozjs-52"
#JS_LIBS+=" -lmozglue" JS_LIBS+=" -lmozglue"
dnl !!!! dnl !!!!
dnl HACK BUG-WORKAROUND - Mozilla forgot to include this in their lib? dnl HACK BUG-WORKAROUND - Mozilla forgot to include this in their lib?
dnl Runtime segfault (unresolved dynamic function address) if this is not specified dnl Runtime segfault (unresolved dynamic function address) if this is not specified
JS_LIBS+=" $PWD/gecko-dev/js/src/build_OPT.OBJ/mfbt/Unified_cpp_mfbt0.o" #JS_LIBS+=" $PWD/gecko-dev/js/src/build_OPT.OBJ/mfbt/Unified_cpp_mfbt0.o"
#JS_LIBS+=" $PWD/gecko-dev/js/src/build_OPT.OBJ/mfbt/Unified_cpp_mfbt1.o"
JS_LIBS+=" $PWD/gecko-dev/js/src/build_OPT.OBJ/mozglue/misc/TimeStamp.o"
AC_MSG_CHECKING([whether to use shared JS engine]) AC_MSG_CHECKING([whether to use shared JS engine])
if [[ $withval = "shared" ]]; then if [[ $withval = "shared" ]]; then
AC_MSG_RESULT([yes]) AC_MSG_RESULT([yes])
AC_MSG_NOTICE([Shared SpiderMonkey linkage requires running charybdis with an intact build directory]) AC_MSG_NOTICE([Shared SpiderMonkey linkage requires running charybdis with an intact build directory])
js_linkage="shared" js_linkage="shared"
JS_LDFLAGS+=" -Wl,-rpath -Wl,$PWD/gecko-dev/js/src/build_OPT.OBJ/dist/sdk/lib" JS_LDFLAGS+=" -Wl,-rpath=$PWD/gecko-dev/js/src/build_OPT.OBJ/dist/sdk/lib"
JS_LDFLAGS+=" -Wl,-rpath -Wl,$PWD/gecko-dev/js/src/build_OPT.OBJ/intl/icu/target/lib" JS_LDFLAGS+=" -Wl,-rpath=$PWD/gecko-dev/js/src/build_OPT.OBJ/intl/icu/target/lib"
else else
AC_MSG_RESULT([no]) AC_MSG_RESULT([no])
js_linkage="static" js_linkage="static"
JS_LIBS+=" -ljs_static" JS_LIBS+=" -ljs_static"
fi fi
js_branch="esr45" js_branch="esr52"
js_jobs="4" js_jobs="4"
if [[ $DEBUG ]]; then if [[ $DEBUG ]]; then
js_options="--disable-optimize --enable-debug" js_options="--disable-optimize --enable-debug --disable-js-shell"
else else
js_options="--enable-optimize" js_options="--enable-optimize --disable-js-shell"
fi fi
bash tools/buildjs.sh "$js_branch" "$js_options" "$js_jobs" bash tools/buildjs.sh "$js_branch" "$js_options" "$js_jobs"
@ -774,17 +776,17 @@ AC_HELP_STRING([--with-included-js[[[=shared]]]], [Use the JS engine (SpiderMonk
with_included_js="no" with_included_js="no"
dnl TODO mumble mumble dnl TODO mumble mumble
AC_CHECK_LIB(mozjs-45, _Z11JS_ShutDownv, AC_CHECK_LIB(mozjs-52, _Z11JS_ShutDownv,
[ [
], [ ], [
AC_MSG_WARN([Unable to find JS engine (SpiderMonkey 45) package. Try apt-get install libmozjs-dev]) AC_MSG_WARN([Unable to find JS engine (SpiderMonkey 52) package. Try apt-get install libmozjs-dev])
]) ])
dnl TODO dnl TODO
dnl AC_SUBST(JS_CPPFLAGS, ["-I/usr/include/mozjs-45"]) dnl AC_SUBST(JS_CPPFLAGS, ["-I/usr/include/mozjs-52"])
dnl AC_SUBST(JS_LDFLAGS, []) dnl AC_SUBST(JS_LDFLAGS, [])
dnl AC_SUBST(JS_LIBS, ["-lmozjs-45"]) dnl AC_SUBST(JS_LIBS, ["-lmozjs-52"])
]) ])
dnl TODO use an $enable_js var dnl TODO use an $enable_js var

@ -1 +1 @@
Subproject commit 37540f992d9a461d759fd0284515d39da103bea5 Subproject commit 090fadc2ca44cd8e2d057cb90cd648cf60587c2e

View file

@ -31,7 +31,7 @@ struct compartment
using closure = std::function<void (JSCompartment *)>; using closure = std::function<void (JSCompartment *)>;
private: private:
static void handle_iterate(JSRuntime *, void *, JSCompartment *) noexcept; static void handle_iterate(JSContext *, void *, JSCompartment *) noexcept;
context *c; context *c;
JSCompartment *prev; JSCompartment *prev;
@ -62,9 +62,11 @@ struct compartment
static compartment &get(); static compartment &get();
}; };
// Get our structure from JSCompartment. Returns null when not ours.
const compartment *our(const JSCompartment *const &); const compartment *our(const JSCompartment *const &);
compartment *our(JSCompartment *const &); compartment *our(JSCompartment *const &);
// Compartment iterations
void for_each_compartment_our(const compartment::closure_our &); // iterate our compartments only void for_each_compartment_our(const compartment::closure_our &); // iterate our compartments only
void for_each_compartment(const compartment::closure &); // iterate all compartments void for_each_compartment(const compartment::closure &); // iterate all compartments

View file

@ -29,7 +29,7 @@ namespace js {
enum class phase enum class phase
:uint8_t :uint8_t
{ {
ACCEPT, // JS is not running. LEAVE, // JS is not running.
ENTER, // JS is currently executing or is committed to being entered. ENTER, // JS is currently executing or is committed to being entered.
INTR, // An interrupt request has or is committed to being sent. INTR, // An interrupt request has or is committed to being sent.
}; };
@ -45,44 +45,61 @@ enum class irq
TERMINATE, // The javascript should be terminated. TERMINATE, // The javascript should be terminated.
}; };
struct context class context
:private custom_ptr<JSContext> :custom_ptr<JSContext>
{ {
// Context options // JS engine callback surface.
struct opts static void handle_error(JSContext *, JSErrorReport *) noexcept;
{ static bool handle_interrupt(JSContext *) noexcept;
size_t stack_chunk_size = 8_KiB; static void handle_timeout(JSContext *) noexcept;
microseconds timer_limit = 10s; static void handle_telemetry(int id, uint32_t sample, const char *key) noexcept;
} static bool handle_get_performance_groups(JSContext *, ::js::PerformanceGroupVector &, void *) noexcept;
opts; static bool handle_stopwatch_commit(uint64_t, ::js::PerformanceGroupVector &, void *) noexcept;
static bool handle_stopwatch_start(uint64_t, void *) noexcept;
static void handle_out_of_memory(JSContext *, void *) noexcept;
static void handle_large_allocation_failure(void *) noexcept;
static void handle_trace_gray(JSTracer *, void *) noexcept;
static void handle_trace_extra(JSTracer *, void *) noexcept;
static void handle_weak_pointer_zone(JSContext *, void *) noexcept;
static void handle_weak_pointer_compartment(JSContext *, JSCompartment *, void *) noexcept;
static void handle_zone_sweep(JS::Zone *) noexcept;
static void handle_zone_destroy(JS::Zone *) noexcept;
static void handle_compartment_name(JSContext *, JSCompartment *, char *buf, size_t) noexcept;
static void handle_compartment_destroy(JSFreeOp *, JSCompartment *) noexcept;
static void handle_finalize(JSFreeOp *, JSFinalizeStatus, bool is_compartment, void *) noexcept;
static void handle_objects_tenured(JSContext *, void *) noexcept;
static void handle_slice(JSContext *, JS::GCProgress, const JS::GCDescription &) noexcept;
static void handle_gc(JSContext *, JSGCStatus, void *) noexcept;
static bool handle_preserve_wrapper(JSContext *, JSObject *) noexcept;
static void handle_activity(void *priv, bool active) noexcept;
static bool handle_promise_enqueue_job(JSContext *, JS::HandleObject, JS::HandleObject, JS::HandleObject, void *) noexcept;
static void handle_promise_rejection_tracker(JSContext *, JS::HandleObject, PromiseRejectionHandlingState, void *) noexcept;
static bool handle_start_async_task(JSContext *, JS::AsyncTask *) noexcept;
static bool handle_finish_async_task(JS::AsyncTask *) noexcept;
static JSObject *handle_get_incumbent_global(JSContext *) noexcept;
// Exception state public:
JSExceptionState *except; // Use save_exception()/restore_exception() struct opts;
// Interruption state
struct alignas(8) state struct alignas(8) state
{ {
uint32_t sem; uint32_t sem;
enum phase phase; enum phase phase;
enum irq irq; enum irq irq;
}; };
std::unique_ptr<struct opts> opts; // Options for the context.
std::thread::id tid; // This is recorded for assertions/logging.
struct tracing tracing; // State for garbage collection / tracing.
JSExceptionState *except; // Use save_exception()/restore_exception()
std::atomic<struct state> state; // Atomic state of execution std::atomic<struct state> state; // Atomic state of execution
std::function<int (const irq &)> on_intr; // User interrupt hook (ret -1 to not interfere) std::function<int (const irq &)> on_intr; // User interrupt hook (ret -1 to not interfere)
bool handle_interrupt(); // Called by runtime on interrupt struct timer timer; // Preemption timer
struct star *star; // System target
// Execution timer
void handle_timeout() noexcept; // Called by timer after requested time
struct timer timer;
// System target
struct star *star; // Registered by kernel
// JSContext // JSContext
operator JSContext *() const { return get(); } operator JSContext *() const { return get(); }
operator JSContext &() const { return custom_ptr<JSContext>::operator*(); } operator JSContext &() const { return custom_ptr<JSContext>::operator*(); }
bool operator!() const { return !custom_ptr<JSContext>::operator bool(); } bool operator!() const { return !custom_ptr<JSContext>::operator bool(); }
auto &runtime() const { return our(JS_GetRuntime(get())); }
auto &runtime() { return our(JS_GetRuntime(get())); }
auto ptr() const { return get(); } auto ptr() const { return get(); }
auto ptr() { return get(); } auto ptr() { return get(); }
@ -90,19 +107,37 @@ struct context
void lock() { JS_BeginRequest(get()); } void lock() { JS_BeginRequest(get()); }
void unlock() { JS_EndRequest(get()); } void unlock() { JS_EndRequest(get()); }
context(struct runtime &, const struct opts &); context(std::unique_ptr<struct opts> opts, JSContext *const &parent = nullptr);
context(const struct opts &); context(const struct opts &, JSContext *const &parent = nullptr);
context() = default; context() = default;
context(context &&) = delete; context(context &&) = delete;
context(const context &) = delete; context(const context &) = delete;
~context() noexcept; ~context() noexcept;
}; };
// Options for the context. Most of these values will never change from what
// the user initially specified, but this is not held as const by the context to
// allow for JS code itself to change its own options if possible.
struct context::opts
{
size_t max_bytes = 64_MiB;
size_t max_nursery_bytes = 16_MiB;
size_t code_stack_max = 0;
size_t trusted_stack_max = 0;
size_t untrusted_stack_max = 0;
size_t stack_chunk_size = 8_KiB;
microseconds timer_limit = 10s; //TODO: Temp
bool concurrent_parsing = true;
bool concurrent_jit = true;
uint8_t gc_zeal_mode = 0; // normal
uint32_t gc_zeal_freq = JS_DEFAULT_ZEAL_FREQ; // 100
};
// Current thread_local context. This value affects contextual data for almost every function // Current thread_local context. This value affects contextual data for almost every function
// in this entire subsystem (ircd::js). Located in ircd/js.cc // in this entire subsystem (ircd::js). Located in ircd/js.cc.
extern __thread context *cx; extern __thread context *cx;
// Get to our `struct context` from any upstream JSContext // Get to our own `struct context` from any upstream JSContext*
const context &our(const JSContext *const &); const context &our(const JSContext *const &);
context &our(JSContext *const &); context &our(JSContext *const &);
@ -110,7 +145,7 @@ context &our(JSContext *const &);
inline auto running(const context &c) { return JS_IsRunning(c); } inline auto running(const context &c) { return JS_IsRunning(c); }
inline auto version(const context &c) { return version(JS_GetVersion(c)); } inline auto version(const context &c) { return version(JS_GetVersion(c)); }
// Current stack // Current
JS::Zone *current_zone(context & = *cx); JS::Zone *current_zone(context & = *cx);
JSObject *current_global(context & = *cx); JSObject *current_global(context & = *cx);
JSCompartment *current_compartment(context & = *cx); JSCompartment *current_compartment(context & = *cx);
@ -120,27 +155,25 @@ void set(context &c, const JSGCParamKey &, const uint32_t &val);
uint32_t get(context &c, const JSGCParamKey &); uint32_t get(context &c, const JSGCParamKey &);
void out_of_memory(context &c); void out_of_memory(context &c);
void allocation_overflow(context &c); void allocation_overflow(context &c);
bool maybe_gc(context &c) noexcept;
bool run_gc(context &c) noexcept; bool run_gc(context &c) noexcept;
// Exception // Exception
bool pending_exception(const context &c); bool pending_exception(const context &c);
void save_exception(context &c);
void clear_exception(context &c); void clear_exception(context &c);
void save_exception(context &c);
bool restore_exception(context &c); bool restore_exception(context &c);
bool report_exception(context &c);
// Interruption // Interruption
bool interrupt(context &, const irq &); bool interrupt(context &, const irq &);
bool interrupt_poll(const context &c); bool interrupt_poll(const context &c);
// Execution // Execution
void restore_frame_chain(context &);
void save_frame_chain(context &);
void enter(context &); // throws if can't enter void enter(context &); // throws if can't enter
void leave(context &); // must be called if enter() succeeds void leave(context &); // must be called if enter() succeeds
// Enter JS within this closure. Most likely your function will return a `struct value` // (Convenience) enter JS within this closure. Most likely your function
// or JS::Value returned by most calls into JS. // will return a `struct value` or JS::Value returned by most calls into JS.
template<class F> auto run(F&& function); template<class F> auto run(F&& function);
@ -159,24 +192,6 @@ run(F&& function)
return function(); return function();
} }
inline void
save_frame_chain(context &c)
{
JS_SaveFrameChain(c);
}
inline void
restore_frame_chain(context &c)
{
JS_RestoreFrameChain(c);
}
inline bool
report_exception(context &c)
{
return JS_ReportPendingException(c);
}
inline void inline void
clear_exception(context &c) clear_exception(context &c)
{ {

View file

@ -1,65 +0,0 @@
/*
* Copyright (C) 2016 Charybdis Development Team
* Copyright (C) 2016 Jason Volk <jason@zemos.net>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice is present in all copies.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#define HAVE_IRCD_JS_CONTRACT_H
namespace ircd {
namespace js {
// contract is a promise from C to a future in JS. When a task has no more pending contracts,
// it ceases to exist.
//
// * The promise is the `struct contract` instantiated in C.
// * The future is returned into JS as an object trapped by "future" (future.so)
// * C unconditionally enters the closure to report result.
// * * if the C closure returns a `value` the "value" field is set in JS
// * * if the C closure throws an exception the "error" field conveys the exception in JS
// *
// * "id": uint
// * "value": object [optional]
// * "error": exception object [optional]
//
struct contract
:std::weak_ptr<struct task>
{
using closure = std::function<value ()>;
object 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.
void operator()(const closure &) noexcept;
// The future object is constructed using the "future" trap.
// The task is automatically found with task::get() in the overload without a task argument.
contract(struct task &, object::handle future);
contract(object::handle future);
contract(contract &&) = default;
contract(const contract &) = default;
~contract() noexcept;
};
} // namespace js
} // namespace ircd

View file

@ -26,6 +26,7 @@ namespace ircd {
namespace js { namespace js {
// Returns static string // Returns static string
const char *reflect(const jstype &);
const char *reflect(const JSType &); const char *reflect(const JSType &);
const char *reflect(const JSExnType &); const char *reflect(const JSExnType &);
const char *reflect(const JSGCMode &); const char *reflect(const JSGCMode &);
@ -33,10 +34,10 @@ const char *reflect(const JSGCStatus &);
const char *reflect(const JS::GCProgress &); const char *reflect(const JS::GCProgress &);
const char *reflect(const JSGCParamKey &); const char *reflect(const JSGCParamKey &);
const char *reflect(const JSFinalizeStatus &); const char *reflect(const JSFinalizeStatus &);
const char *reflect(const JSContextOp &); const char *reflect(const JS::PromiseState &);
const char *reflect(const PromiseRejectionHandlingState &);
const char *reflect_prop(const uint &flag); const char *reflect_prop(const uint &flag);
const char *reflect_telemetry(const int &id); const char *reflect_telemetry(const int &id);
const char *reflect(const jstype &);
// Returns single-line string // Returns single-line string
std::string debug(const JS::Value &); std::string debug(const JS::Value &);
@ -54,6 +55,7 @@ void dump(const JSContext *v);
void dump(const JSScript *const &v); void dump(const JSScript *const &v);
void dump(const char16_t *const &v, const size_t &len); void dump(const char16_t *const &v, const size_t &len);
void dump(const ::js::InterpreterFrame *v); void dump(const ::js::InterpreterFrame *v);
void dump_promise(const JS::HandleObject &promise);
void backtrace(); void backtrace();
// writes lines to ircd::js::log // writes lines to ircd::js::log

View file

@ -35,6 +35,9 @@ object enclosing_scope(JSFunction *const &);
struct function struct function
:root<JSFunction *> :root<JSFunction *>
{ {
struct native; // Use this instead to specify a function in C
struct literal; // Use this instead to supply the JS as a C string literal.
IRCD_OVERLOAD(outermost_enclosing) IRCD_OVERLOAD(outermost_enclosing)
operator JSObject *() const; operator JSObject *() const;
@ -104,10 +107,10 @@ function::function(outermost_enclosing_t)
template<class string_t> template<class string_t>
function::function(JS::AutoObjectVector &stack, function::function(JS::AutoObjectVector &stack,
const JS::CompileOptions &opts, const JS::CompileOptions &opts,
const char *const &name, const char *const &name,
const std::vector<string_t> &args, const std::vector<string_t> &args,
const string_t &src) const string_t &src)
:function::root::type{} :function::root::type{}
{ {
std::vector<const typename string_t::value_type *> argp(args.size()); std::vector<const typename string_t::value_type *> argp(args.size());
@ -174,7 +177,7 @@ const
inline object inline object
enclosing_scope(JSFunction *const &f) enclosing_scope(JSFunction *const &f)
{ {
return ::js::GetNearestEnclosingWithScopeObjectForFunction(f); return ::js::GetNearestEnclosingWithEnvironmentObjectForFunction(f);
} }
inline bool inline bool

View file

@ -25,7 +25,7 @@
namespace ircd { namespace ircd {
namespace js { namespace js {
class function_literal class function::literal
:public root<JSFunction *> :public root<JSFunction *>
{ {
const char *name; const char *name;
@ -33,19 +33,16 @@ class function_literal
std::vector<const char *> prototype; std::vector<const char *> prototype;
public: public:
function_literal(const char *const &name, literal(const char *const &name,
const std::initializer_list<const char *> &prototype, const std::initializer_list<const char *> &prototype,
const char *const &text); const char *const &text);
function_literal(function_literal &&) noexcept; literal(literal &&) noexcept;
function_literal(const function_literal &) = delete; literal(const literal &) = delete;
}; };
inline function_literal // Compile a C++ string literal as an actual JavaScript function.
operator ""_function(const char *const text, const size_t len) function::literal operator ""_function(const char *const text, const size_t len);
{
return { "<literal>", {}, text };
}
} // namespace js } // namespace js
} // namespace ircd } // namespace ircd

View file

@ -0,0 +1,78 @@
/*
* Copyright (C) 2016 Charybdis Development Team
* Copyright (C) 2016 Jason Volk <jason@zemos.net>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice is present in all copies.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#define HAVE_IRCD_JS_FUNCTION_NATIVE
namespace ircd {
namespace js {
struct function::native
:root<JSFunction *>
{
using closure = std::function<value (object::handle, value::handle, const args &)>;
const char *_name;
closure lambda;
protected:
virtual value on_call(object::handle callee, value::handle that, const args &);
virtual value on_new(object::handle callee, const args &);
private:
static function::native &from(JSObject *const &);
static bool handle_call(JSContext *, unsigned, JS::Value *) noexcept;
public:
uint16_t arity() const;
string display_name() const;
string name() const;
value operator()(const object::handle &, const vector<value>::handle &) const;
template<class... args> value operator()(const object::handle &, args&&...) const;
native(const char *const &name = "<native>",
const uint &flags = 0,
const uint &arity = 0,
const closure & = {});
native(native &&) = delete;
native(const native &) = delete;
virtual ~native() noexcept;
};
template<class... args>
value
function::native::operator()(const object::handle &that,
args&&... a)
const
{
const vector<value> argv
{
std::forward<args>(a)...
};
const vector<value>::handle handle(argv);
return operator()(that, handle);
}
} // namespace js
} // namespace ircd

View file

@ -30,10 +30,15 @@ class global
{ {
static void handle_trace(JSTracer *, JSObject *) noexcept; static void handle_trace(JSTracer *, JSObject *) noexcept;
std::map<std::string, module *> imports;
object import(module &importer, const string &requesting, const object &that);
std::unique_ptr<function::native> module_resolve_hook;
public: public:
global(trap &, global(trap &,
JSPrincipals *const & = nullptr, JSPrincipals *const & = nullptr,
JS::CompartmentOptions = JS::CompartmentOptions()); JS::CompartmentCreationOptions = {},
JS::CompartmentBehaviors = {});
global(global &&) = default; global(global &&) = default;
global(const global &) = delete; global(const global &) = delete;

View file

@ -39,7 +39,7 @@
// From a completely clean build, configuring IRCd with --enable-debug should compile SpiderMonkey // From a completely clean build, configuring IRCd with --enable-debug should compile SpiderMonkey
// in debug as well. // in debug as well.
#ifdef RB_DEBUG #ifdef RB_DEBUG
// #define DEBUG #define DEBUG
#endif #endif
// SpiderMonkey headers require an include basis e.g. -I/usr/include/mozjs-XX as their // SpiderMonkey headers require an include basis e.g. -I/usr/include/mozjs-XX as their
@ -66,13 +66,12 @@ using ircd::operator<<;
#include "version.h" #include "version.h"
#include "type.h" #include "type.h"
#include "debug.h"
#include "tracing.h" #include "tracing.h"
#include "runtime.h"
#include "timer.h" #include "timer.h"
#include "context.h" #include "context.h"
#include "priv.h" #include "priv.h"
#include "compartment.h" #include "compartment.h"
#include "debug.h"
#include "root.h" #include "root.h"
#include "error.h" #include "error.h"
#include "native.h" #include "native.h"
@ -86,21 +85,21 @@ using ircd::operator<<;
#include "set.h" #include "set.h"
#include "del.h" #include "del.h"
#include "vector.h" #include "vector.h"
#include "for_each.h"
#include "xdr.h" #include "xdr.h"
#include "script.h" #include "script.h"
#include "module.h"
#include "args.h"
#include "function.h" #include "function.h"
#include "function_literal.h" #include "function_literal.h"
#include "function_native.h"
#include "call.h" #include "call.h"
#include "for_each.h" #include "for_each.h"
#include "args.h"
#include "trap.h" #include "trap.h"
#include "trap_function.h" #include "trap_function.h"
#include "trap_property.h" #include "trap_property.h"
#include "ctor.h" #include "ctor.h"
#include "generator.h"
#include "global.h" #include "global.h"
#include "contract.h"
#include "star.h"
#include "task.h" #include "task.h"
#endif // defined(RB_ENABLE_JS) #endif // defined(RB_ENABLE_JS)

147
include/ircd/js/module.h Normal file
View file

@ -0,0 +1,147 @@
/*
* Copyright (C) 2016 Charybdis Development Team
* Copyright (C) 2016 Jason Volk <jason@zemos.net>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice is present in all copies.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#define HAVE_IRCD_JS_MODULE_H
namespace ircd {
namespace js {
struct module
:object
,script
{
IRCD_OVERLOAD(yielding)
struct trap *trap;
object requested() const; // GetRequestedModules()
void instantiate(); // ModuleDeclarationInstantiation()
void operator()() const; // ModuleEvaluation()
module(yielding_t, const JS::ReadOnlyCompileOptions &, const std::u16string &src, struct trap *const & = nullptr, const bool &instantiate = true);
module(const JS::ReadOnlyCompileOptions &, const std::u16string &src, struct trap *const & = nullptr, const bool &instantiate = true);
static module &our(const object &module); // Get this structure from the record object
};
inline
module::module(const JS::ReadOnlyCompileOptions &opts,
const std::u16string &src,
struct trap *const &trap,
const bool &instantiate)
:object{[this, &opts, &src, &instantiate]
() -> object
{
static const auto ownership(JS::SourceBufferHolder::NoOwnership);
object ret(object::uninitialized);
JS::SourceBufferHolder buf(src.data(), src.size(), ownership);
if(!JS::CompileModule(*cx, opts, buf, &ret))
throw jserror(jserror::pending);
if(unlikely(!ret.get()))
throw jserror(jserror::pending);
JS::SetModuleHostDefinedField(ret, value(value::pointer, this));
return ret;
}()}
,script
{
JS::GetModuleScript(*cx, static_cast<object &>(*this))
}
,trap{trap}
{
if(instantiate)
this->instantiate();
}
// This constructor compiles the module concurrently by yielding this ircd::ctx.
// See the yielding_t overload in script.h for details.
inline
module::module(yielding_t,
const JS::ReadOnlyCompileOptions &opts,
const std::u16string &src,
struct trap *const &trap,
const bool &instantiate)
:object{[this, &opts, &src]
() -> object
{
static const auto ownership(JS::SourceBufferHolder::NoOwnership);
auto future(compile_async(opts, src, true));
void *const token(future.get());
object ret(object::uninitialized);
if(!token)
{
JS::SourceBufferHolder buf(src.data(), src.size(), ownership);
if(!JS::CompileModule(*cx, opts, buf, &ret))
throw jserror(jserror::pending);
}
else ret = JS::FinishOffThreadModule(*cx, token);
if(unlikely(!ret.get()))
throw jserror(jserror::pending);
JS::SetModuleHostDefinedField(ret, pointer_value(this));
return ret;
}()}
,script
{
JS::GetModuleScript(*cx, static_cast<object &>(*this))
}
,trap{trap}
{
if(instantiate)
this->instantiate();
}
inline void
module::instantiate()
{
if(!JS::ModuleDeclarationInstantiation(*cx, static_cast<object &>(*this)))
throw jserror(jserror::pending);
}
inline void
module::operator()()
const
{
if(!JS::ModuleEvaluation(*cx, static_cast<const object &>(*this)))
throw jserror(jserror::pending);
}
inline object
module::requested()
const
{
return JS::GetRequestedModules(*cx, static_cast<const object &>(*this));
}
inline module &
module::our(const object &module)
{
const value priv(JS::GetModuleHostDefinedField(module));
return *pointer_value<struct module>(priv);
}
} // namespace js
} // namespace ircd

View file

@ -19,6 +19,11 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
//
// TODO: This file will be merged with string.h.
// Don't confuse it with SpiderMonkey terminology for "JSNative" functions
//
#pragma once #pragma once
#define HAVE_IRCD_JS_NATIVE_H #define HAVE_IRCD_JS_NATIVE_H

View file

@ -88,6 +88,7 @@ struct object
object(const value &); object(const value &);
object(JSObject *const &); object(JSObject *const &);
object(JSObject &); object(JSObject &);
object(nullptr_t);
object(uninitialized_t); object(uninitialized_t);
object(); object();
@ -111,6 +112,12 @@ object::object(uninitialized_t)
{ {
} }
inline
object::object(nullptr_t)
:object{value{nullptr}}
{
}
inline inline
object::object(JSObject &obj) object::object(JSObject &obj)
:object::root::type{&obj} :object::root::type{&obj}
@ -231,7 +238,7 @@ object::object(const uint8_t *const &bytecode,
const size_t &size) const size_t &size)
:object::root::type :object::root::type
{ {
JS_DecodeInterpretedFunction(*cx, bytecode, size) //JS_DecodeInterpretedFunction(*cx, bytecode, size)
} }
{ {
if(unlikely(!this->get())) if(unlikely(!this->get()))
@ -297,20 +304,11 @@ const
return ret; return ret;
} }
inline
object::operator JSString *()
const
{
assert(this->get());
return JS_BasicObjectToString(*cx, *this);
}
inline inline
object::operator value() object::operator value()
const const
{ {
assert(this->get()); return static_cast<JS::Value>(*this);
return JS::ObjectValue(*this->get());
} }
inline inline
@ -321,6 +319,14 @@ const
return JS::ObjectValue(*this->get()); return JS::ObjectValue(*this->get());
} }
inline
object::operator JSString *()
const
{
assert(this->get());
return JS_BasicObjectToString(*cx, *this);
}
inline size_t inline size_t
bytecodes(const object_handle &obj, bytecodes(const object_handle &obj,
uint8_t *const &buf, uint8_t *const &buf,
@ -329,7 +335,7 @@ bytecodes(const object_handle &obj,
uint32_t ret; uint32_t ret;
const custom_ptr<void> ptr const custom_ptr<void> ptr
{ {
JS_EncodeInterpretedFunction(*cx, obj, &ret), js_free //JS_EncodeInterpretedFunction(*cx, obj, &ret), js_free
}; };
const auto cpsz(std::min(size_t(ret), size)); const auto cpsz(std::min(size_t(ret), size));

View file

@ -89,15 +89,15 @@ struct root
tracing::list::iterator add(base_type *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>() }); return cx->tracing.heap.emplace(end(cx->tracing.heap), tracing::thing { ptr, js::type<T>() });
} }
void del(const tracing::list::iterator &tracing_it) void del(const tracing::list::iterator &tracing_it)
{ {
if(tracing_it != end(rt->tracing.heap)) if(tracing_it != end(cx->tracing.heap))
{ {
const void *ptr = tracing_it->ptr; const void *ptr = tracing_it->ptr;
rt->tracing.heap.erase(tracing_it); cx->tracing.heap.erase(tracing_it);
} }
} }
@ -130,7 +130,7 @@ struct root
:base_type{other.get()} :base_type{other.get()}
,tracing_it{std::move(other.tracing_it)} ,tracing_it{std::move(other.tracing_it)}
{ {
other.tracing_it = end(rt->tracing.heap); other.tracing_it = end(cx->tracing.heap);
tracing_it->ptr = static_cast<base_type *>(this); tracing_it->ptr = static_cast<base_type *>(this);
} }

View file

@ -1,154 +0,0 @@
/*
* Copyright (C) 2016 Charybdis Development Team
* Copyright (C) 2016 Jason Volk <jason@zemos.net>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice is present in all copies.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#define HAVE_IRCD_JS_RUNTIME_H
namespace ircd {
namespace js {
class runtime
{
static void handle_error(JSContext *, const char *msg, JSErrorReport *) noexcept;
static void handle_out_of_memory(JSContext *, void *) noexcept;
static void handle_large_allocation_failure(void *) noexcept;
static void handle_telemetry(int id, uint32_t sample, const char *key) noexcept;
static void handle_finalize(JSFreeOp *, JSFinalizeStatus, bool is_compartment, void *) noexcept;
static void handle_trace_gray(JSTracer *, void *) noexcept;
static void handle_trace_extra(JSTracer *, void *) noexcept;
static void handle_weak_pointer_zone(JSRuntime *, void *) noexcept;
static void handle_weak_pointer_compartment(JSRuntime *, JSCompartment *, void *) noexcept;
static void handle_slice(JSRuntime *, JS::GCProgress, const JS::GCDescription &) noexcept;
static void handle_zone_sweep(JS::Zone *) noexcept;
static void handle_zone_destroy(JS::Zone *) noexcept;
static void handle_compartment_name(JSRuntime *, JSCompartment *, char *buf, size_t) noexcept;
static void handle_compartment_destroy(JSFreeOp *, JSCompartment *) noexcept;
static void handle_gc(JSRuntime *, JSGCStatus, void *) noexcept;
static bool handle_preserve_wrapper(JSContext *, JSObject *) noexcept;
static bool handle_context(JSContext *, uint op, void *) noexcept;
static void handle_activity(void *priv, bool active) noexcept;
static bool handle_interrupt(JSContext *) noexcept;
public:
struct opts
{
size_t max_bytes = 64_MiB;
size_t max_nursery_bytes = 16_MiB;
size_t code_stack_max = 0;
size_t trusted_stack_max = 0;
size_t untrusted_stack_max = 0;
};
struct opts opts; // We keep a copy of the given opts here
std::thread::id tid; // This is recorded for assertions/logging.
struct tracing tracing; // State for garbage collection / tracing.
custom_ptr<JSRuntime> _ptr;
operator JSRuntime *() const { return _ptr.get(); }
operator JSRuntime &() const { return *_ptr; }
bool operator!() const { return !_ptr; }
auto get() const { return _ptr.get(); }
auto get() { return _ptr.get(); }
runtime(const struct opts &, runtime *const &parent = nullptr);
runtime() = default;
runtime(runtime &&) noexcept;
runtime(const runtime &) = delete;
runtime &operator=(runtime &&) noexcept;
runtime &operator=(const runtime &) = delete;
~runtime() noexcept;
friend void interrupt(runtime &);
};
// Current thread_local runtime. This value affects contextual data for almost every function
// in this entire subsystem (ircd::js). Located in ircd/js.cc
extern __thread runtime *rt;
// Get to our `struct runtime` from any upstream JSRuntime
const runtime &our(const JSRuntime *const &);
runtime &our(JSRuntime *const &);
// Get to our runtime from any JSObject
const runtime &our_runtime(const JSObject &);
runtime &our_runtime(JSObject &);
// Get to our runtime from any JSFreeOp
JSFreeOp *default_freeop(runtime &);
const runtime &our_runtime(const JSFreeOp &);
runtime &our_runtime(JSFreeOp &);
// Do not call interrupt() unless you know what you're doing; see context.h.
void interrupt(runtime &r);
bool run_gc(runtime &r) noexcept;
inline void
interrupt(runtime &r)
{
JS_RequestInterruptCallback(r);
}
inline runtime &
our_runtime(JSFreeOp &o)
{
return our(o.runtime());
}
inline const runtime &
our_runtime(const JSFreeOp &o)
{
return our(o.runtime());
}
inline JSFreeOp *
default_freeop(runtime &r)
{
return JS_GetDefaultFreeOp(r);
}
inline runtime &
our_runtime(JSObject &o)
{
return our(JS_GetObjectRuntime(&o));
}
inline const runtime &
our_runtime(const JSObject &o)
{
return our(JS_GetObjectRuntime(const_cast<JSObject *>(&o)));
}
inline runtime &
our(JSRuntime *const &c)
{
return *static_cast<runtime *>(JS_GetRuntimePrivate(c));
}
inline const runtime &
our(const JSRuntime *const &c)
{
return *static_cast<const runtime *>(JS_GetRuntimePrivate(const_cast<JSRuntime *>(c)));
}
} // namespace js
} // namespace ircd

View file

@ -25,7 +25,7 @@
namespace ircd { namespace ircd {
namespace js { namespace js {
ctx::future<void *> compile_async(const JS::ReadOnlyCompileOptions &, const std::u16string &); ctx::future<void *> compile_async(const JS::ReadOnlyCompileOptions &, const std::u16string &, const bool &module = false);
string decompile(const JS::Handle<JSScript *> &, const char *const &name, const bool &pretty = false); string decompile(const JS::Handle<JSScript *> &, const char *const &name, const bool &pretty = false);
size_t bytecodes(const JS::Handle<JSScript *> &, uint8_t *const &buf, const size_t &max); size_t bytecodes(const JS::Handle<JSScript *> &, uint8_t *const &buf, const size_t &max);
bool compilable(const char *const &str, const size_t &len, const object &stack = {}); bool compilable(const char *const &str, const size_t &len, const object &stack = {});
@ -36,7 +36,8 @@ struct script
{ {
IRCD_OVERLOAD(yielding) IRCD_OVERLOAD(yielding)
value operator()(JS::AutoObjectVector &stack) const; value operator()(JS::AutoObjectVector &environment) const;
value operator()(const object &environment) const;
value operator()() const; value operator()() const;
using root<JSScript *>::root; using root<JSScript *>::root;
@ -67,7 +68,7 @@ script::script(const uint8_t *const &bytecode,
const size_t &size) const size_t &size)
:script::root::type :script::root::type
{ {
JS_DecodeScript(*cx, bytecode, size) //JS_DecodeScript(*cx, bytecode, size)
} }
{ {
if(unlikely(!this->get())) if(unlikely(!this->get()))
@ -92,18 +93,19 @@ script::script(const JS::ReadOnlyCompileOptions &opts,
throw jserror(jserror::pending); throw jserror(jserror::pending);
} }
// This constructor compiles the script concurrently by yielding this ircd::ctx.
// The compilation occurs on another thread entirely, so other ircd contexts will
// still be able to run, but this ircd context will block until the script is
// compiled at which point this constructor will complete.
inline inline
script::script(yielding_t, script::script(yielding_t,
const JS::ReadOnlyCompileOptions &opts, const JS::ReadOnlyCompileOptions &opts,
const std::u16string &src) const std::u16string &src)
:script::root::type{[&opts, &src] :script::root::type{[this, &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
// still be able to run.
auto future(compile_async(opts, src)); auto future(compile_async(opts, src));
void *const token(future.get()); void *const token(future.get());
return token? JS::FinishOffThreadScript(*cx, *rt, token): return token? JS::FinishOffThreadScript(*cx, token):
script(opts, src).get(); script(opts, src).get();
}()} }()}
{ {
@ -123,11 +125,20 @@ const
} }
inline value inline value
script::operator()(JS::AutoObjectVector &stack) script::operator()(const object &environment)
const
{
JS::AutoObjectVector env(*cx);
env.append(object());
return operator()(env);
}
inline value
script::operator()(JS::AutoObjectVector &environment)
const const
{ {
value ret; value ret;
if(!JS_ExecuteScript(*cx, stack, *this, &ret)) if(!JS_ExecuteScript(*cx, environment, *this, &ret))
throw jserror(jserror::pending); throw jserror(jserror::pending);
return ret; return ret;

View file

@ -1,43 +0,0 @@
/*
* Copyright (C) 2016 Charybdis Development Team
* Copyright (C) 2016 Jason Volk <jason@zemos.net>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice is present in all copies.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#define HAVE_IRCD_JS_STAR_H
namespace ircd {
namespace js {
struct star
{
// Active processes by PID. This is managed by the actual task structure itself.
// A task pointer in the map will always be valid. When the last shared_ptr to a task is
// destroyed the task removes itself and weak references to the task are invalidated.
std::map<uint64_t, task *> tasks;
// Modules conducting some asynchronous operation on behalf of a task maintain state with
// a `struct contract` object. When the result is ready and the contract is fulfilled
// the contract object inserts itself into this queue (the user does not do this).
// The kernel is listening on the other end of this queue.
ctx::queue<contract> completion;
};
} // namespace js
} // namespace ircd

View file

@ -57,6 +57,7 @@ struct string
operator std::string() const; operator std::string() const;
operator std::u16string() const; operator std::u16string() const;
operator JS::Value() const;
operator value() const; operator value() const;
using root<JSString *>::root; using root<JSString *>::root;
@ -110,10 +111,13 @@ 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);
using string_pair = std::pair<string, string>; using string_pair = std::pair<string, string>;
string_pair splita(const string &s, const char16_t &c);
string_pair splita(const string &s, const char &c); // split() but skips multiple contiguous c
string_pair split(const string &s, const char16_t &c); // split on first position of c
string_pair split(const string &s, const char &c); 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 substr(const string &s, const size_t &pos, const size_t &len);
string operator+(const string &left, const string &right); string operator+(const string &left, const string &right);
string &operator+=(string &left, const string &right);
using string_closure = std::function<void (const string &)>; using string_closure = std::function<void (const string &)>;
void tokens(const string &, const char &sep, const string_closure &); void tokens(const string &, const char &sep, const string_closure &);
@ -122,7 +126,7 @@ inline
string::string() string::string()
:string::root::type :string::root::type
{ {
JS_GetEmptyString(*rt) JS_GetEmptyString(*cx)
} }
{ {
} }
@ -169,7 +173,7 @@ string::string(const char *const &s,
:string::root::type{[&s, &len] :string::root::type{[&s, &len]
{ {
if(!s || !*s) if(!s || !*s)
return JS_GetEmptyString(*rt); return JS_GetEmptyString(*cx);
auto buf(native_external_copy(s, len)); auto buf(native_external_copy(s, len));
return JS_NewExternalString(*cx, buf.release(), len, &native_external_delete); return JS_NewExternalString(*cx, buf.release(), len, &native_external_delete);
@ -197,7 +201,7 @@ string::string(const char16_t *const &s,
:string::root::type{[&s, &len] :string::root::type{[&s, &len]
{ {
if(!s || !*s) if(!s || !*s)
return JS_GetEmptyString(*rt); return JS_GetEmptyString(*cx);
// JS_NewExternalString does not require a null terminated buffer, but we are going // JS_NewExternalString does not require a null terminated buffer, but we are going
// to terminate anyway in case the deleter ever wants to iterate a canonical vector. // to terminate anyway in case the deleter ever wants to iterate a canonical vector.
@ -218,7 +222,7 @@ string::string(literal_t,
{ {
s && *s? s && *s?
JS_NewExternalString(*cx, s, std::char_traits<char16_t>::length(s), &native_external_static): JS_NewExternalString(*cx, s, std::char_traits<char16_t>::length(s), &native_external_static):
JS_GetEmptyString(*rt) JS_GetEmptyString(*cx)
} }
{ {
if(unlikely(!this->get())) if(unlikely(!this->get()))
@ -271,6 +275,13 @@ const
inline inline
string::operator value() string::operator value()
const const
{
return static_cast<JS::Value>(*this);
}
inline
string::operator JS::Value()
const
{ {
return JS::StringValue(this->get()); return JS::StringValue(this->get());
} }
@ -339,7 +350,7 @@ tokens(const string &str,
const char &sep, const char &sep,
const string_closure &closure) const string_closure &closure)
{ {
for(auto pair(split(str, sep));; pair = split(pair.second, sep)) for(auto pair(splita(str, sep));; pair = splita(pair.second, sep))
{ {
closure(pair.first); closure(pair.first);
if(pair.second.empty()) if(pair.second.empty())
@ -354,16 +365,41 @@ split(const string &s,
return split(s, char16_t(c)); return split(s, char16_t(c));
} }
inline std::pair<string, string>
splita(const string &s,
const char &c)
{
return splita(s, char16_t(c));
}
inline std::pair<string, string> inline std::pair<string, string>
split(const string &s, split(const string &s,
const char16_t &c) const char16_t &c)
{ {
size_t i(0); size_t a(0);
for(; i < size(s) && at(s, i) != c; ++i); for(; a < size(s) && at(s, a) != c; ++a);
return return
{ {
substr(s, 0, i), substr(s, 0, a),
i < size(s)? substr(s, i + 1, size(s) - i) : string() a + 1 < size(s)? substr(s, a + 1, size(s) - a) : string()
};
}
inline std::pair<string, string>
splita(const string &s,
const char16_t &c)
{
size_t a(0);
for(; a < size(s) && at(s, a) != c; ++a);
size_t b(a);
for(; b < size(s) && at(s, b) == c; ++b);
return
{
substr(s, 0, a),
b < size(s)? substr(s, b, size(s) - b) : string()
}; };
} }
@ -380,6 +416,14 @@ substr(const string &s,
return ret; return ret;
} }
inline string &
operator+=(string &left,
const string &right)
{
left = operator+(left, right);
return left;
}
inline string inline string
operator+(const string &left, operator+(const string &left,
const string &right) const string &right)

View file

@ -29,24 +29,10 @@ struct task
:std::enable_shared_from_this<task> :std::enable_shared_from_this<task>
{ {
uint64_t pid; // unique process ID uint64_t pid; // unique process ID
uint64_t yid; // ID of current yield attempting unification
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 struct global global; // global / this / root scope object
script main; // main generator wrapper script struct module main; // main module script
struct generator generator; // generator state
bool canceling = false;
private:
static uint64_t tasks_next_pid();
uint64_t tasks_insert();
bool tasks_remove();
public: public:
bool pending_add(const uint64_t &id, object);
bool pending_del(const uint64_t &id);
task(const std::u16string &source); task(const std::u16string &source);
task(const std::string &source); task(const std::string &source);
task(task &&) = delete; task(task &&) = delete;

View file

@ -27,26 +27,20 @@ namespace js {
struct trap struct trap
{ {
struct property; struct property; // Properties (trap_property.h)
struct function; struct function; // Functions (trap_function.h)
struct constint; // Constant integers (trap_constint.h)
trap *parent; std::string name; // classp name
const std::string _name; // don't touch trap *prototrap; // Parent trap
std::map<std::string, property *> member;
std::map<std::string, function *> memfun;
std::map<std::string, trap *> children;
std::array<JSConstIntegerSpec, 32> cis; // static const integer spec // Static specifications
std::array<JSConstDoubleSpec, 32> cds; // static const double spec std::map<std::string, property *> sprop;
std::array<JSPropertySpec, 32> sps; // static property spec std::map<std::string, function *> sfunc;
std::array<JSFunctionSpec, 32> sfs; // static function spec
std::array<JSPropertySpec, 32> ps; // property spec
std::array<JSFunctionSpec, 32> fs; // function spec
std::unique_ptr<JSClass> _class; // class spec
trap *prototrap; // pointer to __proto__ trap
static trap &from(const JSObject &); // Member specifications
static trap &from(const JSObject *const &); std::map<std::string, property *> memprop;
std::map<std::string, function *> memfunc;
protected: protected:
void debug(const void *const &that, const char *fmt, ...) const AFP(3, 4); void debug(const void *const &that, const char *fmt, ...) const AFP(3, 4);
@ -64,8 +58,6 @@ struct trap
virtual void on_gc(JSObject *const &); virtual void on_gc(JSObject *const &);
private: protected: private: protected:
void add_this();
void del_this();
void host_exception(const void *const &that, const char *fmt, ...) const AFP(3, 4); void host_exception(const void *const &that, const char *fmt, ...) const AFP(3, 4);
// Internal callback interface // Internal callback interface
@ -83,18 +75,17 @@ struct trap
static bool handle_ctor(JSContext *, unsigned argc, JS::Value *argv) noexcept; static bool handle_ctor(JSContext *, unsigned argc, JS::Value *argv) noexcept;
static void handle_dtor(JSFreeOp *, JSObject *) noexcept; static void handle_dtor(JSFreeOp *, JSObject *) noexcept;
// Aggregate structure specifying internal callback surface
static const JSClassOps cops; // Used for regular objects
static const JSClassOps gcops; // Used for global objects
const JSClass classp; // Instance uses one of the above JSClassOps
public: public:
auto &name() const { return _name; } static trap &from(const JSObject *const &);
auto &jsclass() const { return *_class; } static trap &from(const JSObject &);
auto &jsclass() { return *_class; }
// Get child by name (NOT PATH) auto &jsclass() const { return classp; }
const trap &child(const std::string &name) const; auto &jsclass() { return classp; }
trap &child(const std::string &name);
// Path is absolute to root
static trap &find(const string::handle &path);
static trap &find(const std::string &path);
operator const JSClass &() const { return jsclass(); } operator const JSClass &() const { return jsclass(); }
operator const JSClass *() const { return &jsclass(); } operator const JSClass *() const { return &jsclass(); }
@ -104,15 +95,12 @@ struct trap
object construct(const vector<value>::handle &argv = {}); object construct(const vector<value>::handle &argv = {});
template<class... args> object operator()(args&&...); template<class... args> object operator()(args&&...);
trap(trap &parent, const std::string &name, const uint &flags = 0, const uint &prop_flags = 0);
trap(const std::string &name, const uint &flags = 0, const uint &prop_flags = 0); trap(const std::string &name, const uint &flags = 0, const uint &prop_flags = 0);
trap(trap &&) = delete; trap(trap &&) = delete;
trap(const trap &) = delete; trap(const trap &) = delete;
virtual ~trap() noexcept; virtual ~trap() noexcept;
}; };
extern __thread trap *tree;
} // namespace js } // namespace js
} // namespace ircd } // namespace ircd
@ -120,6 +108,10 @@ template<class... args>
ircd::js::object ircd::js::object
ircd::js::trap::operator()(args&&... a) ircd::js::trap::operator()(args&&... a)
{ {
vector<value> argv{std::forward<args>(a)...}; const vector<value> argv
{
std::forward<args>(a)...
};
return construct(argv); return construct(argv);
} }

View file

@ -27,13 +27,13 @@ namespace js {
struct trap::function struct trap::function
{ {
friend struct trap;
using closure = std::function<value (object::handle, value::handle, const args &)>; using closure = std::function<value (object::handle, value::handle, const args &)>;
trap *member; struct trap *trap;
const std::string name; std::string name;
const uint flags;
const uint arity;
closure lambda; closure lambda;
JSFunctionSpec spec;
protected: protected:
virtual value on_call(object::handle callee, value::handle that, const args &); virtual value on_call(object::handle callee, value::handle that, const args &);
@ -41,15 +41,16 @@ struct trap::function
private: private:
static function &from(JSObject *const &); static function &from(JSObject *const &);
static bool handle_call(JSContext *, unsigned, JS::Value *) noexcept; static bool handle_call(JSContext *, unsigned, JS::Value *) noexcept;
public: public:
js::function operator()(const object::handle &) const; js::function operator()(const object::handle &) const;
function(trap &, function(struct trap &,
std::string name, const std::string &name,
const uint &flags = 0, const uint16_t &flags = 0,
const uint &arity = 0, const uint16_t &arity = 0,
const closure & = {}); const closure & = {});
function(function &&) = delete; function(function &&) = delete;

View file

@ -27,10 +27,12 @@ namespace js {
struct trap::property struct trap::property
{ {
friend struct trap;
using function = js::function; using function = js::function;
struct trap *trap; struct trap *trap;
const std::string name; std::string name;
JSPropertySpec spec;
virtual value on_set(function::handle, object::handle, value::handle); virtual value on_set(function::handle, object::handle, value::handle);
virtual value on_get(function::handle, object::handle); virtual value on_get(function::handle, object::handle);
@ -40,7 +42,7 @@ struct trap::property
static bool handle_get(JSContext *c, unsigned argc, JS::Value *argv) noexcept; static bool handle_get(JSContext *c, unsigned argc, JS::Value *argv) noexcept;
public: public:
property(struct trap &, std::string name); property(struct trap &, const std::string &name, const uint &flags = 0);
property(property &&) = delete; property(property &&) = delete;
property(const property &) = delete; property(const property &) = delete;
virtual ~property() noexcept; virtual ~property() noexcept;

View file

@ -45,7 +45,7 @@ template<> constexpr jstype type<JSString *>() { return jstype::STRING;
template<> constexpr jstype type<JS::Symbol *>() { return jstype::SYMBOL; } template<> constexpr jstype type<JS::Symbol *>() { return jstype::SYMBOL; }
template<> constexpr jstype type<jsid>() { return jstype::ID; } template<> constexpr jstype type<jsid>() { return jstype::ID; }
inline jstype // This cannot be constexpr <= GCC-4.9 constexpr jstype
type(const JSType &t) type(const JSType &t)
{ {
switch(t) switch(t)
@ -59,8 +59,9 @@ type(const JSType &t)
case JSTYPE_BOOLEAN: return jstype::VALUE; case JSTYPE_BOOLEAN: return jstype::VALUE;
case JSTYPE_NULL: return jstype::VALUE; case JSTYPE_NULL: return jstype::VALUE;
case JSTYPE_LIMIT: return jstype::VALUE; case JSTYPE_LIMIT: return jstype::VALUE;
default: return jstype::VALUE;
} }
return jstype::VALUE;
} }
} // namespace js } // namespace js

View file

@ -171,7 +171,7 @@ value::value(const std::string &s)
:value::root::type{[&s] :value::root::type{[&s]
{ {
if(s.empty()) if(s.empty())
return JS::StringValue(JS_GetEmptyString(*rt)); return JS::StringValue(JS_GetEmptyString(*cx));
auto buf(native_external_copy(s)); auto buf(native_external_copy(s));
const auto ret(JS_NewExternalString(*cx, buf.get(), s.size(), &native_external_delete)); const auto ret(JS_NewExternalString(*cx, buf.get(), s.size(), &native_external_delete));
@ -186,7 +186,7 @@ value::value(const char *const &s)
:value::root::type{[&s] :value::root::type{[&s]
{ {
if(!s || !*s) if(!s || !*s)
return JS::StringValue(JS_GetEmptyString(*rt)); return JS::StringValue(JS_GetEmptyString(*cx));
const auto len(strlen(s)); const auto len(strlen(s));
auto buf(native_external_copy(s, len)); auto buf(native_external_copy(s, len));

View file

@ -64,11 +64,24 @@ struct vector<value>
struct handle struct handle
:JS::HandleValueArray :JS::HandleValueArray
{ {
using JS::HandleValueArray::HandleValueArray; handle()
handle(const JS::CallArgs &args): JS::HandleValueArray{args} {} :JS::HandleValueArray{JS::HandleValueArray::empty()}
handle(): JS::HandleValueArray{JS::HandleValueArray::empty()} {} {}
handle(const JS::CallArgs &args)
:JS::HandleValueArray{args}
{}
handle(const size_t &len, const JS::Value *const &elems)
:JS::HandleValueArray{JS::HandleValueArray::fromMarkedLocation(len, elems)}
{}
}; };
operator handle() const
{
return { length(), begin() };
}
/* /*
// Construct vector from initializer list of raw `JS::Value` // Construct vector from initializer list of raw `JS::Value`
// ex: JS::Value a; vector foo {{ a, a, ... }}; // ex: JS::Value a; vector foo {{ a, a, ... }};

3161
ircd/js.cc

File diff suppressed because it is too large Load diff

269
modules/kernel.cc Normal file
View file

@ -0,0 +1,269 @@
/*
* Copyright (C) 2016 Charybdis Development Team
* Copyright (C) 2016 Jason Volk <jason@zemos.net>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice is present in all copies.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <ircd/js/js.h>
struct assertions
{
assertions();
}
static assertions;
namespace ircd {
namespace js {
struct kernel
:trap
{
JSPrincipals *principals;
static const char *const source;
std::shared_ptr<task> process;
value on_call(object::handle, value::handle, const args &) override;
value on_set(object::handle, id::handle, value::handle) override;
value on_get(object::handle, id::handle, value::handle) override;
void on_add(object::handle, id::handle, value::handle) override;
bool on_del(object::handle, id::handle) override;
bool on_has(object::handle, id::handle) override;
void on_enu(object::handle) override;
void on_new(object::handle, object &, const args &) override;
void on_gc(JSObject *const &) override;
void main() noexcept;
kernel();
~kernel() noexcept;
}
static kernel;
} // namespace js
} // namespace ircd
///////////////////////////////////////////////////////////////////////////////
//
// Kernel source
//
const char *const
ircd::js::kernel::source
{R"(
'use strict';
import * as console from "server.console";
import * as listener from "server.listener";
var ircd =
{
};
ircd.opts =
{
};
ircd.opts.listener =
{
host: "127.0.0.1",
port: 8448,
backlog: 1024,
ssl_certificate_file: "/home/jason/newcert.pem",
ssl_private_key_file_pem: "/home/jason/privkey.pem",
ssl_certificate_chain_file: "/home/jason/newcert.pem",
ssl_tmp_dh_file: "/home/jason/dh512.pem",
};
let main = async function()
{
console.debug("IRCd.js Greetings from JavaScript");
listener.listen(ircd.opts.listener);
};
let fini = function()
{
console.info("IRCd.js finished");
}
main().then(fini);
)"};
///////////////////////////////////////////////////////////////////////////////
ircd::js::kernel::kernel()
:trap
{
"[global]",
JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(1) | JSCLASS_HAS_PRIVATE | JSCLASS_EMULATES_UNDEFINED,
}
,principals
{
nullptr
}
,process
{
std::make_shared<task>(source)
}
{
}
ircd::js::kernel::~kernel()
noexcept
{
}
void
ircd::js::kernel::main()
noexcept try
{
std::map<std::string, ircd::module> modules;
// These modules host databases and have to be loaded first.
modules.emplace("root.so"s, "root.so"s);
modules.emplace("client_account.so"s, "client_account.so"s);
modules.emplace("client_room.so"s, "client_room.so"s);
for(const auto &name : mods::available())
if(startswith(name, "client_"))
modules.emplace(name, name);
task::enter(process, [](auto &task)
{
task.main();
});
printf("main finished\n");
ctx::wait();
log.debug("Kernel finished");
}
catch(const ircd::ctx::interrupted &e)
{
log.debug("Kernel interrupted");
return;
}
catch(const std::exception &e)
{
log.critical("Kernel PANIC: %s", e.what());
std::terminate();
}
void
ircd::js::kernel::on_gc(JSObject *const &obj)
{
//trap::on_gc(obj);
}
void
ircd::js::kernel::on_new(object::handle ca,
object &obj,
const args &args)
{
trap::on_new(ca, obj, args);
}
void
ircd::js::kernel::on_enu(object::handle obj)
{
if(!JS_EnumerateStandardClasses(*cx, obj))
throw internal_error("Failed to enumerate standard classes");
}
bool
ircd::js::kernel::on_has(object::handle obj,
id::handle id)
{
return trap::on_has(obj, id);
}
bool
ircd::js::kernel::on_del(object::handle obj,
id::handle id)
{
return trap::on_del(obj, id);
}
void
ircd::js::kernel::on_add(object::handle obj,
id::handle id,
value::handle val)
{
trap::on_add(obj, id, val);
}
ircd::js::value
ircd::js::kernel::on_get(object::handle obj,
id::handle id,
value::handle val)
{
return trap::on_get(obj, id, val);
}
ircd::js::value
ircd::js::kernel::on_set(object::handle obj,
id::handle id,
value::handle val)
{
return trap::on_set(obj, id, val);
}
ircd::js::value
ircd::js::kernel::on_call(object::handle ca,
value::handle that,
const args &args)
{
return trap::on_call(ca, that, args);
}
// Unmangled alias to the main task.
extern "C"
void kmain()
{
ircd::js::kernel.main();
}
assertions::assertions()
{
using ircd::js::error;
if(!ircd::js::cx)
throw error("Kernel cannot find required JS context instance on this thread.");
}
const auto on_load([]
{
using namespace ircd::js;
});
const auto on_unload([]
{
using namespace ircd::js;
});
ircd::mapi::header IRCD_MODULE
{
"IRCd.js kernel - program which helps programs run",
on_load,
on_unload
};

173
modules/server/console.cc Normal file
View file

@ -0,0 +1,173 @@
/*
* Copyright (C) 2016 Charybdis Development Team
* Copyright (C) 2016 Jason Volk <jason@zemos.net>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice is present in all copies.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <ircd/js/js.h>
namespace ircd {
namespace js {
struct console
:trap
{
static const char *const source;
struct module module;
console();
}
static console;
console::console()
:trap
{
"__console",
JSCLASS_HAS_PRIVATE
}
,module
{
JS::CompileOptions(*cx),
locale::char16::conv(source),
this,
true
}
{
}
const char *const
console::source
{R"(
export function critical(msg) { __console.critical(msg); }
export function error(msg) { __console.error(msg); }
export function warn(msg) { __console.warn(msg); }
export function notice(msg) { __console.notice(msg); }
export function info(msg) { __console.info(msg); }
export function debug(msg) { __console.debug(msg); }
export function cout(msg) { __console.cout(msg); }
export function log(msg) { __console.info(msg); }
)"};
struct console_critical
:trap::function
{
value on_call(object::handle obj, value::handle _this, const args &args) override
{
ircd::js::log(ircd::log::CRITICAL, "%s", std::string(args[0]));
return {};
}
using trap::function::function;
}
static console_critical{console, "critical"};
struct console_error
:trap::function
{
value on_call(object::handle obj, value::handle _this, const args &args) override
{
ircd::js::log(ircd::log::ERROR, "%s", std::string(args[0]));
return {};
}
using trap::function::function;
}
static console_error{console, "error"};
struct console_warn
:trap::function
{
value on_call(object::handle obj, value::handle _this, const args &args) override
{
ircd::js::log(ircd::log::WARNING, "%s", std::string(args[0]));
return {};
}
using trap::function::function;
}
static console_warn{console, "warn"};
struct console_notice
:trap::function
{
value on_call(object::handle obj, value::handle _this, const args &args) override
{
ircd::js::log(ircd::log::NOTICE, "%s", std::string(args[0]));
return {};
}
using trap::function::function;
}
static console_notice{console, "notice"};
struct console_info
:trap::function
{
value on_call(object::handle obj, value::handle _this, const args &args) override
{
ircd::js::log(ircd::log::INFO, "%s", std::string(args[0]));
return {};
}
using trap::function::function;
}
static console_info{console, "info"};
struct console_debug
:trap::function
{
value on_call(object::handle obj, value::handle _this, const args &args) override
{
ircd::js::log.debug("%s", std::string(args[0]));
return {};
}
using trap::function::function;
}
static console_debug{console, "debug"};
struct console_cout
:trap::function
{
value on_call(object::handle obj, value::handle _this, const args &args) override
{
std::cout << string(args[0]) << std::endl;
return {};
}
using trap::function::function;
}
static console_cout{console, "cout"};
} // namespace js
} // namespace ircd
extern "C" ircd::js::module *
IRCD_JS_MODULE
{
&ircd::js::console.module
};
ircd::mapi::header
IRCD_MODULE
{
"Provides simple I/O for debugging similar to that found in web browsers."
};

View file

@ -19,72 +19,87 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#pragma once #include <ircd/listen.h>
#define HAVE_IRCD_JS_GENERATOR_H #include <ircd/js/js.h>
namespace ircd { namespace ircd {
namespace js { namespace js {
struct generator struct listener
:js::trap
{ {
object state; struct listen;
object last;
bool done() const; static const char *const source;
template<class... args> value next(args&&...); struct module module;
template<class... args> value _throw(args&&...);
template<class... args> value _return(args&&...);
generator(object::handle state); listener();
generator(object state); }
generator() = default; static listener;
struct listener::listen
:trap::function
{
ircd::listener *l;
value on_call(object::handle obj, value::handle _this, const args &args) override
{
l = new ircd::listener(std::string(args[0]));
return {};
}
using trap::function::function;
}
static listener_listen
{
listener, "listen"
}; };
inline
generator::generator(object state)
:state{state}
{
}
inline
generator::generator(object::handle state)
:state{state}
{
}
template<class... args>
value
generator::_return(args&&... a)
{
function func(get(state, "return"));
last = func(state, std::forward<args>(a)...);
return has(last, "value")? get(last, "value") : value{};
}
template<class... args>
value
generator::_throw(args&&... a)
{
function func(get(state, "throw"));
last = func(state, std::forward<args>(a)...);
return has(last, "value")? get(last, "value") : value{};
}
template<class... args>
value
generator::next(args&&... a)
{
function func(get(state, "next"));
last = func(state, std::forward<args>(a)...);
return has(last, "value")? get(last, "value") : value{};
}
inline bool
generator::done()
const
{
return bool(get(last, "done"));
}
} // namespace js } // namespace js
} // namespace ircd } // namespace ircd
///////////////////////////////////////////////////////////////////////////////
//
// Listener source
//
const char *const
ircd::js::listener::source
{R"(
import * as console from "server.console";
export function listen(opts)
{
__listener.listen(JSON.stringify(opts));
}
)"};
///////////////////////////////////////////////////////////////////////////////
ircd::js::listener::listener()
:js::trap
{
"__listener",
}
,module
{
JS::CompileOptions(*cx),
locale::char16::conv(source),
this,
true
}
{
}
extern "C" ircd::js::module *
IRCD_JS_MODULE
{
&ircd::js::listener.module
};
ircd::mapi::header
IRCD_MODULE
{
"Network listener socket support for servers"
};

View file

@ -46,8 +46,8 @@ USERDIR=$PWD # Save current dir and return to it later
run git submodule update --init --remote gecko-dev run git submodule update --init --remote gecko-dev
run cd gecko-dev run cd gecko-dev
#run git fetch --depth=1 origin esr45 #run git fetch --depth=1 origin $BRANCH
#run git checkout FETCH_HEAD run git checkout $BRANCH
run cd js/src run cd js/src
run autoconf2.13 run autoconf2.13
@ -60,12 +60,12 @@ run cd build_OPT.OBJ
# may actually be the best behavior in production but right now this test # may actually be the best behavior in production but right now this test
# prevents rebuilds # prevents rebuilds
if test $ALREADY_EXISTS -eq 0; then if test $ALREADY_EXISTS -eq 0; then
run ../configure $CONFIG_OPTIONS run ../configure $CONFIG_OPTIONS JS_STANDALONE=1
fi fi
#run ../configure --enable-debug #run ../configure --enable-debug
# run ../configure --disable-shared-js --enable-debug # --enable-replace-malloc # run ../configure --disable-shared-js --enable-debug # --enable-replace-malloc
run make run make -j8
run cd $USERDIR # Return to user's original directory run cd $USERDIR # Return to user's original directory