mirror of
https://github.com/matrix-construct/construct
synced 2024-06-02 18:18:56 +02:00
ircd::js: Add js exception hierarchy.
This commit is contained in:
parent
2c231ac187
commit
4171a9c834
84
include/ircd/js/error.h
Normal file
84
include/ircd/js/error.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* 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_ERROR_H
|
||||
|
||||
namespace ircd {
|
||||
namespace js {
|
||||
|
||||
class error_handler
|
||||
{
|
||||
friend class runtime;
|
||||
using closure = std::function<void (const char *const &msg, JSErrorReport &)>;
|
||||
|
||||
error_handler *theirs;
|
||||
closure handler;
|
||||
|
||||
public:
|
||||
error_handler(const closure &handler);
|
||||
error_handler(closure &&handler);
|
||||
~error_handler() noexcept;
|
||||
};
|
||||
|
||||
struct jserror
|
||||
:js::error
|
||||
{
|
||||
protected:
|
||||
std::u16string msg;
|
||||
JSErrorReport report;
|
||||
|
||||
void generate(const JSExnType &type, const char *const &fmt, va_list ap);
|
||||
|
||||
public:
|
||||
JS::Value create_error(const JS::HandleObject &stack, const JS::HandleString &file, const std::pair<uint, uint> &linecol) const;
|
||||
JS::Value create_error() const;
|
||||
|
||||
void set_pending() const;
|
||||
|
||||
jserror(generate_skip_t);
|
||||
jserror(const char *fmt = " ", ...) AFP(2, 3);
|
||||
};
|
||||
|
||||
#define IRCD_JS_ERROR_DEF(name, type) \
|
||||
struct name \
|
||||
:jserror \
|
||||
{ \
|
||||
name(const char *const fmt = " ", ...) AFP(2, 3) \
|
||||
:jserror(generate_skip) \
|
||||
{ \
|
||||
va_list ap; \
|
||||
va_start(ap, fmt); \
|
||||
generate(type, fmt, ap); \
|
||||
va_end(ap); \
|
||||
} \
|
||||
};
|
||||
|
||||
IRCD_JS_ERROR_DEF( internal_error, JSEXN_INTERNALERR )
|
||||
IRCD_JS_ERROR_DEF( eval_error, JSEXN_EVALERR )
|
||||
IRCD_JS_ERROR_DEF( range_error, JSEXN_RANGEERR )
|
||||
IRCD_JS_ERROR_DEF( reference_error, JSEXN_REFERENCEERR )
|
||||
IRCD_JS_ERROR_DEF( syntax_error, JSEXN_SYNTAXERR )
|
||||
IRCD_JS_ERROR_DEF( type_error, JSEXN_TYPEERR )
|
||||
IRCD_JS_ERROR_DEF( uri_error, JSEXN_URIERR )
|
||||
|
||||
} // namespace js
|
||||
} // namespace ircd
|
|
@ -62,6 +62,7 @@ JSVersion version(const char *const &v) { return JS_StringToVersion(v);
|
|||
#include "runtime.h"
|
||||
#include "context.h"
|
||||
#include "compartment.h"
|
||||
#include "error.h"
|
||||
#include "id.h"
|
||||
#include "string.h"
|
||||
#include "for_each.h"
|
||||
|
|
126
ircd/js.cc
126
ircd/js.cc
|
@ -321,6 +321,29 @@ const
|
|||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
ircd::js::trap::host_exception(const char *const fmt,
|
||||
...)
|
||||
const
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
char buf[1024];
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
log.error("trap(%p) \"%s\": %s",
|
||||
reinterpret_cast<const void *>(this),
|
||||
name().c_str(),
|
||||
buf);
|
||||
|
||||
JS_ReportError(*cx, "BUG: trap(%p) \"%s\" %s",
|
||||
reinterpret_cast<const void *>(this),
|
||||
name().c_str(),
|
||||
buf);
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::js::trap::on_ctor(const unsigned &argc,
|
||||
JS::Value &argv)
|
||||
|
@ -417,6 +440,92 @@ ircd::js::string_convert(const char16_t *const &s)
|
|||
return s? converter.to_bytes(s) : std::string{};
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ircd/js/error.h
|
||||
//
|
||||
|
||||
ircd::js::error_handler::error_handler(closure &&handler)
|
||||
:theirs{rt->error_handler}
|
||||
,handler{std::move(handler)}
|
||||
{
|
||||
rt->error_handler = this;
|
||||
}
|
||||
|
||||
ircd::js::error_handler::error_handler(const closure &handler)
|
||||
:theirs{rt->error_handler}
|
||||
,handler{handler}
|
||||
{
|
||||
rt->error_handler = this;
|
||||
}
|
||||
|
||||
ircd::js::error_handler::~error_handler()
|
||||
noexcept
|
||||
{
|
||||
assert(rt->error_handler == this);
|
||||
rt->error_handler = theirs;
|
||||
}
|
||||
|
||||
ircd::js::jserror::jserror(generate_skip_t)
|
||||
:ircd::js::error(generate_skip)
|
||||
{
|
||||
}
|
||||
|
||||
ircd::js::jserror::jserror(const char *const fmt,
|
||||
...)
|
||||
:ircd::js::error(generate_skip)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
generate(JSEXN_ERR, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
ircd::js::jserror::set_pending()
|
||||
const
|
||||
{
|
||||
JS::RootedValue ex(*cx, create_error());
|
||||
JS_SetPendingException(*cx, ex);
|
||||
}
|
||||
|
||||
JS::Value
|
||||
ircd::js::jserror::create_error(const JS::HandleObject &stack,
|
||||
const JS::HandleString &file,
|
||||
const std::pair<uint, uint> &linecol)
|
||||
const
|
||||
{
|
||||
JS::RootedValue ret(*cx);
|
||||
JS::RootedString msg(*cx);
|
||||
const auto type((JSExnType)report.exnType);
|
||||
const auto &line(linecol.first);
|
||||
const auto &col(linecol.second);
|
||||
if(!JS::CreateError(*cx, type, stack, file, line, col, const_cast<JSErrorReport *>(&report), msg, &ret))
|
||||
throw error("Failed to construct jserror exception!");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
JS::Value
|
||||
ircd::js::jserror::create_error()
|
||||
const
|
||||
{
|
||||
JS::RootedObject stack(*cx);
|
||||
JS::RootedString file(*cx);
|
||||
return create_error(stack, file, {0, 0});
|
||||
}
|
||||
|
||||
void
|
||||
ircd::js::jserror::generate(const JSExnType &type,
|
||||
const char *const &fmt,
|
||||
va_list ap)
|
||||
{
|
||||
ircd::exception::generate(fmt, ap);
|
||||
msg = string_convert(what());
|
||||
report.ucmessage = msg.c_str();
|
||||
report.exnType = type;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ircd/js/debug.h
|
||||
|
@ -731,7 +840,8 @@ ircd::js::runtime::runtime(const struct opts &opts)
|
|||
JS_NewRuntime(opts.maxbytes),
|
||||
JS_DestroyRuntime
|
||||
}
|
||||
,opts(opts)
|
||||
,error_handler{nullptr}
|
||||
,opts{opts}
|
||||
{
|
||||
// We use their privdata to find `this` via our(JSRuntime*) function.
|
||||
// Any additional user privdata will have to ride a member in this class itself.
|
||||
|
@ -756,7 +866,8 @@ ircd::js::runtime::runtime(const struct opts &opts)
|
|||
ircd::js::runtime::runtime(runtime &&other)
|
||||
noexcept
|
||||
:custom_ptr<JSRuntime>{std::move(other)}
|
||||
,opts(std::move(other.opts))
|
||||
,error_handler{nullptr}
|
||||
,opts{std::move(other.opts)}
|
||||
{
|
||||
// Branch not taken for null/defaulted instance of JSRuntime smart ptr
|
||||
if(!!*this)
|
||||
|
@ -771,6 +882,7 @@ ircd::js::runtime::operator=(runtime &&other)
|
|||
noexcept
|
||||
{
|
||||
static_cast<custom_ptr<JSRuntime> &>(*this) = std::move(other);
|
||||
error_handler = std::move(other.error_handler);
|
||||
opts = std::move(other.opts);
|
||||
|
||||
// Branch not taken for null/defaulted instance of JSRuntime smart ptr
|
||||
|
@ -860,6 +972,14 @@ void
|
|||
ircd::js::runtime::handle_error(JSContext *const ctx,
|
||||
const char *const msg,
|
||||
JSErrorReport *const report)
|
||||
noexcept
|
||||
{
|
||||
log.error("JSContext(%p): %s [%s]", (const void *)ctx, msg, debug(*report).c_str());
|
||||
if(!rt->error_handler)
|
||||
{
|
||||
log.error("Unhandled: JSContext(%p): %s [%s]", (const void *)ctx, msg, debug(*report).c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
assert(report);
|
||||
rt->error_handler->handler(msg, *report);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue