mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-25 06:42:27 +00:00
Reduce build latency and fix old cpu bugs
This commit is contained in:
parent
df8ab0aa0c
commit
533f3d1ef1
69 changed files with 43069 additions and 43683 deletions
418
third_party/quickjs/err.c
vendored
Normal file
418
third_party/quickjs/err.c
vendored
Normal file
|
@ -0,0 +1,418 @@
|
|||
/*
|
||||
* QuickJS Javascript Engine
|
||||
*
|
||||
* Copyright (c) 2017-2021 Fabrice Bellard
|
||||
* Copyright (c) 2017-2021 Charlie Gordon
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "third_party/quickjs/internal.h"
|
||||
#include "third_party/quickjs/leb128.h"
|
||||
#include "third_party/quickjs/libregexp.h"
|
||||
#include "third_party/quickjs/quickjs.h"
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
QuickJS (MIT License)\\n\
|
||||
Copyright (c) 2017-2021 Fabrice Bellard\\n\
|
||||
Copyright (c) 2017-2021 Charlie Gordon\"");
|
||||
asm(".include \"libc/disclaimer.inc\"");
|
||||
/* clang-format off */
|
||||
|
||||
int js_parse_error(JSParseState *s, const char *fmt, ...)
|
||||
{
|
||||
JSContext *ctx = s->ctx;
|
||||
va_list ap;
|
||||
int backtrace_flags;
|
||||
va_start(ap, fmt);
|
||||
JS_ThrowError2(ctx, JS_SYNTAX_ERROR, fmt, ap, FALSE);
|
||||
va_end(ap);
|
||||
backtrace_flags = 0;
|
||||
if (s->cur_func && s->cur_func->backtrace_barrier)
|
||||
backtrace_flags = JS_BACKTRACE_FLAG_SINGLE_LEVEL;
|
||||
build_backtrace(ctx, ctx->rt->current_exception, s->filename, s->line_num,
|
||||
backtrace_flags);
|
||||
return -1;
|
||||
}
|
||||
|
||||
JSValue JS_NewError(JSContext *ctx)
|
||||
{
|
||||
return JS_NewObjectClass(ctx, JS_CLASS_ERROR);
|
||||
}
|
||||
|
||||
JSValue JS_ThrowError2(JSContext *ctx, JSErrorEnum error_num, const char *fmt, va_list ap, BOOL add_backtrace)
|
||||
{
|
||||
char buf[256];
|
||||
JSValue obj, ret;
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
obj = JS_NewObjectProtoClass(ctx, ctx->native_error_proto[error_num],
|
||||
JS_CLASS_ERROR);
|
||||
if (UNLIKELY(JS_IsException(obj))) {
|
||||
/* out of memory: throw JS_NULL to avoid recursing */
|
||||
obj = JS_NULL;
|
||||
} else {
|
||||
JS_DefinePropertyValue(ctx, obj, JS_ATOM_message,
|
||||
JS_NewString(ctx, buf),
|
||||
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
|
||||
}
|
||||
if (add_backtrace) {
|
||||
build_backtrace(ctx, obj, NULL, 0, 0);
|
||||
}
|
||||
ret = JS_Throw(ctx, obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
JSValue JS_ThrowError(JSContext *ctx, JSErrorEnum error_num, const char *fmt, va_list ap)
|
||||
{
|
||||
JSRuntime *rt = ctx->rt;
|
||||
JSStackFrame *sf;
|
||||
BOOL add_backtrace;
|
||||
/* the backtrace is added later if called from a bytecode function */
|
||||
sf = rt->current_stack_frame;
|
||||
add_backtrace = !rt->in_out_of_memory &&
|
||||
(!sf || (JS_GetFunctionBytecode(sf->cur_func) == NULL));
|
||||
return JS_ThrowError2(ctx, error_num, fmt, ap, add_backtrace);
|
||||
}
|
||||
|
||||
JSValue JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...)
|
||||
{
|
||||
JSValue val;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
val = JS_ThrowError(ctx, JS_SYNTAX_ERROR, fmt, ap);
|
||||
va_end(ap);
|
||||
return val;
|
||||
}
|
||||
|
||||
JSValue JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...)
|
||||
{
|
||||
JSValue val;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
val = JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap);
|
||||
va_end(ap);
|
||||
return val;
|
||||
}
|
||||
|
||||
int JS_ThrowTypeErrorOrFalse(JSContext *ctx, int flags, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
if ((flags & JS_PROP_THROW) ||
|
||||
((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
|
||||
va_start(ap, fmt);
|
||||
JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap);
|
||||
va_end(ap);
|
||||
return -1;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* never use it directly */
|
||||
JSValue __JS_ThrowTypeErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)
|
||||
{
|
||||
char buf[ATOM_GET_STR_BUF_SIZE];
|
||||
return JS_ThrowTypeError(ctx, fmt,
|
||||
JS_AtomGetStr(ctx, buf, sizeof(buf), atom));
|
||||
}
|
||||
|
||||
/* never use it directly */
|
||||
JSValue __JS_ThrowSyntaxErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)
|
||||
{
|
||||
char buf[ATOM_GET_STR_BUF_SIZE];
|
||||
return JS_ThrowSyntaxError(ctx, fmt,
|
||||
JS_AtomGetStr(ctx, buf, sizeof(buf), atom));
|
||||
}
|
||||
|
||||
int JS_ThrowTypeErrorReadOnly(JSContext *ctx, int flags, JSAtom atom)
|
||||
{
|
||||
if ((flags & JS_PROP_THROW) ||
|
||||
((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
|
||||
JS_ThrowTypeErrorAtom(ctx, "'%s' is read-only", atom);
|
||||
return -1;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
JSValue JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...)
|
||||
{
|
||||
JSValue val;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
val = JS_ThrowError(ctx, JS_REFERENCE_ERROR, fmt, ap);
|
||||
va_end(ap);
|
||||
return val;
|
||||
}
|
||||
|
||||
JSValue JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...)
|
||||
{
|
||||
JSValue val;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
val = JS_ThrowError(ctx, JS_RANGE_ERROR, fmt, ap);
|
||||
va_end(ap);
|
||||
return val;
|
||||
}
|
||||
|
||||
JSValue JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...)
|
||||
{
|
||||
JSValue val;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
val = JS_ThrowError(ctx, JS_INTERNAL_ERROR, fmt, ap);
|
||||
va_end(ap);
|
||||
return val;
|
||||
}
|
||||
|
||||
JSValue JS_ThrowOutOfMemory(JSContext *ctx)
|
||||
{
|
||||
JSRuntime *rt = ctx->rt;
|
||||
if (!rt->in_out_of_memory) {
|
||||
rt->in_out_of_memory = TRUE;
|
||||
JS_ThrowInternalError(ctx, "out of memory");
|
||||
rt->in_out_of_memory = FALSE;
|
||||
}
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
JSValue JS_ThrowStackOverflow(JSContext *ctx)
|
||||
{
|
||||
return JS_ThrowInternalError(ctx, "stack overflow");
|
||||
}
|
||||
|
||||
JSValue JS_ThrowTypeErrorNotAnObject(JSContext *ctx)
|
||||
{
|
||||
return JS_ThrowTypeError(ctx, "not an object");
|
||||
}
|
||||
|
||||
JSValue JS_ThrowTypeErrorNotASymbol(JSContext *ctx)
|
||||
{
|
||||
return JS_ThrowTypeError(ctx, "not a symbol");
|
||||
}
|
||||
|
||||
int js_throw_URIError(JSContext *ctx, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
JS_ThrowError(ctx, JS_URI_ERROR, fmt, ap);
|
||||
va_end(ap);
|
||||
return -1;
|
||||
}
|
||||
|
||||
JSValue JS_ThrowReferenceErrorNotDefined(JSContext *ctx, JSAtom name)
|
||||
{
|
||||
char buf[ATOM_GET_STR_BUF_SIZE];
|
||||
return JS_ThrowReferenceError(ctx, "'%s' is not defined",
|
||||
JS_AtomGetStr(ctx, buf, sizeof(buf), name));
|
||||
}
|
||||
|
||||
JSValue JS_ThrowReferenceErrorUninitialized(JSContext *ctx, JSAtom name)
|
||||
{
|
||||
char buf[ATOM_GET_STR_BUF_SIZE];
|
||||
return JS_ThrowReferenceError(ctx, "%s is not initialized",
|
||||
name == JS_ATOM_NULL ? "lexical variable" :
|
||||
JS_AtomGetStr(ctx, buf, sizeof(buf), name));
|
||||
}
|
||||
|
||||
JSValue JS_ThrowReferenceErrorUninitialized2(JSContext *ctx,
|
||||
JSFunctionBytecode *b,
|
||||
int idx, BOOL is_ref)
|
||||
{
|
||||
JSAtom atom = JS_ATOM_NULL;
|
||||
if (is_ref) {
|
||||
atom = b->closure_var[idx].var_name;
|
||||
} else {
|
||||
/* not present if the function is stripped and contains no eval() */
|
||||
if (b->vardefs)
|
||||
atom = b->vardefs[b->arg_count + idx].var_name;
|
||||
}
|
||||
return JS_ThrowReferenceErrorUninitialized(ctx, atom);
|
||||
}
|
||||
|
||||
JSValue JS_ThrowSyntaxErrorVarRedeclaration(JSContext *ctx, JSAtom prop)
|
||||
{
|
||||
return JS_ThrowSyntaxErrorAtom(ctx, "redeclaration of '%s'", prop);
|
||||
}
|
||||
|
||||
JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext *ctx, JSAtom atom)
|
||||
{
|
||||
return JS_ThrowTypeErrorAtom(ctx, "private class field '%s' does not exist",
|
||||
atom);
|
||||
}
|
||||
|
||||
JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx)
|
||||
{
|
||||
return JS_ThrowTypeError(ctx, "ArrayBuffer is detached");
|
||||
}
|
||||
|
||||
/* in order to avoid executing arbitrary code during the stack trace
|
||||
generation, we only look at simple 'name' properties containing a
|
||||
string. */
|
||||
static const char *get_func_name(JSContext *ctx, JSValueConst func)
|
||||
{
|
||||
JSProperty *pr;
|
||||
JSShapeProperty *prs;
|
||||
JSValueConst val;
|
||||
if (JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT)
|
||||
return NULL;
|
||||
prs = find_own_property(&pr, JS_VALUE_GET_OBJ(func), JS_ATOM_name);
|
||||
if (!prs)
|
||||
return NULL;
|
||||
if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)
|
||||
return NULL;
|
||||
val = pr->u.value;
|
||||
if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)
|
||||
return NULL;
|
||||
return JS_ToCString(ctx, val);
|
||||
}
|
||||
|
||||
int find_line_num(JSContext *ctx, JSFunctionBytecode *b, uint32_t pc_value)
|
||||
{
|
||||
const uint8_t *p_end, *p;
|
||||
int new_line_num, line_num, pc, v, ret;
|
||||
unsigned int op;
|
||||
if (!b->has_debug || !b->debug.pc2line_buf) {
|
||||
/* function was stripped */
|
||||
return -1;
|
||||
}
|
||||
p = b->debug.pc2line_buf;
|
||||
p_end = p + b->debug.pc2line_len;
|
||||
pc = 0;
|
||||
line_num = b->debug.line_num;
|
||||
while (p < p_end) {
|
||||
op = *p++;
|
||||
if (op == 0) {
|
||||
uint32_t val;
|
||||
ret = get_leb128(&val, p, p_end);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
pc += val;
|
||||
p += ret;
|
||||
ret = get_sleb128(&v, p, p_end);
|
||||
if (ret < 0) {
|
||||
fail:
|
||||
/* should never happen */
|
||||
return b->debug.line_num;
|
||||
}
|
||||
p += ret;
|
||||
new_line_num = line_num + v;
|
||||
} else {
|
||||
op -= PC2LINE_OP_FIRST;
|
||||
pc += (op / PC2LINE_RANGE);
|
||||
new_line_num = line_num + (op % PC2LINE_RANGE) + PC2LINE_BASE;
|
||||
}
|
||||
if (pc_value < pc)
|
||||
return line_num;
|
||||
line_num = new_line_num;
|
||||
}
|
||||
return line_num;
|
||||
}
|
||||
|
||||
/* if filename != NULL, an additional level is added with the filename
|
||||
and line number information (used for parse error). */
|
||||
void build_backtrace(JSContext *ctx, JSValueConst error_obj,
|
||||
const char *filename, int line_num,
|
||||
int backtrace_flags)
|
||||
{
|
||||
JSStackFrame *sf;
|
||||
JSValue str;
|
||||
DynBuf dbuf;
|
||||
const char *func_name_str;
|
||||
const char *str1;
|
||||
JSObject *p;
|
||||
BOOL backtrace_barrier;
|
||||
js_dbuf_init(ctx, &dbuf);
|
||||
if (filename) {
|
||||
dbuf_printf(&dbuf, " at %s", filename);
|
||||
if (line_num != -1)
|
||||
dbuf_printf(&dbuf, ":%d", line_num);
|
||||
dbuf_putc(&dbuf, '\n');
|
||||
str = JS_NewString(ctx, filename);
|
||||
JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_fileName, str,
|
||||
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
|
||||
JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_lineNumber, JS_NewInt32(ctx, line_num),
|
||||
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
|
||||
if (backtrace_flags & JS_BACKTRACE_FLAG_SINGLE_LEVEL)
|
||||
goto done;
|
||||
}
|
||||
for(sf = ctx->rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) {
|
||||
if (backtrace_flags & JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL) {
|
||||
backtrace_flags &= ~JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL;
|
||||
continue;
|
||||
}
|
||||
func_name_str = get_func_name(ctx, sf->cur_func);
|
||||
if (!func_name_str || func_name_str[0] == '\0')
|
||||
str1 = "<anonymous>";
|
||||
else
|
||||
str1 = func_name_str;
|
||||
dbuf_printf(&dbuf, " at %s", str1);
|
||||
JS_FreeCString(ctx, func_name_str);
|
||||
p = JS_VALUE_GET_OBJ(sf->cur_func);
|
||||
backtrace_barrier = FALSE;
|
||||
if (js_class_has_bytecode(p->class_id)) {
|
||||
JSFunctionBytecode *b;
|
||||
const char *atom_str;
|
||||
int line_num1;
|
||||
b = p->u.func.function_bytecode;
|
||||
backtrace_barrier = b->backtrace_barrier;
|
||||
if (b->has_debug) {
|
||||
line_num1 = find_line_num(ctx, b,
|
||||
sf->cur_pc - b->byte_code_buf - 1);
|
||||
atom_str = JS_AtomToCString(ctx, b->debug.filename);
|
||||
dbuf_printf(&dbuf, " (%s",
|
||||
atom_str ? atom_str : "<null>");
|
||||
JS_FreeCString(ctx, atom_str);
|
||||
if (line_num1 != -1)
|
||||
dbuf_printf(&dbuf, ":%d", line_num1);
|
||||
dbuf_putc(&dbuf, ')');
|
||||
}
|
||||
} else {
|
||||
dbuf_printf(&dbuf, " (native)");
|
||||
}
|
||||
dbuf_putc(&dbuf, '\n');
|
||||
/* stop backtrace if JS_EVAL_FLAG_BACKTRACE_BARRIER was used */
|
||||
if (backtrace_barrier)
|
||||
break;
|
||||
}
|
||||
done:
|
||||
dbuf_putc(&dbuf, '\0');
|
||||
if (dbuf_error(&dbuf))
|
||||
str = JS_NULL;
|
||||
else
|
||||
str = JS_NewString(ctx, (char *)dbuf.buf);
|
||||
dbuf_free(&dbuf);
|
||||
JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_stack, str,
|
||||
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
|
||||
}
|
||||
|
||||
JSValue throw_bf_exception(JSContext *ctx, int status)
|
||||
{
|
||||
const char *str;
|
||||
if (status & BF_ST_MEM_ERROR)
|
||||
return JS_ThrowOutOfMemory(ctx);
|
||||
if (status & BF_ST_DIVIDE_ZERO) {
|
||||
str = "division by zero";
|
||||
} else if (status & BF_ST_INVALID_OP) {
|
||||
str = "invalid operation";
|
||||
} else {
|
||||
str = "integer overflow";
|
||||
}
|
||||
return JS_ThrowRangeError(ctx, "%s", str);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue