@@ -394,6 +394,7 @@ struct JSContext {
394394 JSValue promise_ctor;
395395 JSValue native_error_proto[JS_NATIVE_ERROR_COUNT];
396396 JSValue error_ctor;
397+ JSValue error_back_trace;
397398 JSValue error_prepare_stack;
398399 int error_stack_trace_limit;
399400 JSValue iterator_ctor;
@@ -2305,6 +2306,7 @@ JSContext *JS_NewContextRaw(JSRuntime *rt)
23052306 ctx->regexp_ctor = JS_NULL;
23062307 ctx->promise_ctor = JS_NULL;
23072308 ctx->error_ctor = JS_NULL;
2309+ ctx->error_back_trace = JS_UNDEFINED;
23082310 ctx->error_prepare_stack = JS_UNDEFINED;
23092311 ctx->error_stack_trace_limit = 10;
23102312 init_list_head(&ctx->loaded_modules);
@@ -2424,6 +2426,7 @@ static void JS_MarkContext(JSRuntime *rt, JSContext *ctx,
24242426 JS_MarkValue(rt, ctx->native_error_proto[i], mark_func);
24252427 }
24262428 JS_MarkValue(rt, ctx->error_ctor, mark_func);
2429+ JS_MarkValue(rt, ctx->error_back_trace, mark_func);
24272430 JS_MarkValue(rt, ctx->error_prepare_stack, mark_func);
24282431 for(i = 0; i < rt->class_count; i++) {
24292432 JS_MarkValue(rt, ctx->class_proto[i], mark_func);
@@ -2491,6 +2494,7 @@ void JS_FreeContext(JSContext *ctx)
24912494 JS_FreeValue(ctx, ctx->native_error_proto[i]);
24922495 }
24932496 JS_FreeValue(ctx, ctx->error_ctor);
2497+ JS_FreeValue(ctx, ctx->error_back_trace);
24942498 JS_FreeValue(ctx, ctx->error_prepare_stack);
24952499 for(i = 0; i < rt->class_count; i++) {
24962500 JS_FreeValue(ctx, ctx->class_proto[i]);
@@ -6616,14 +6620,28 @@ static const char *get_func_name(JSContext *ctx, JSValue func)
66166620 return JS_ToCString(ctx, val);
66176621}
66186622
6623+ /* Note: it is important that no exception is returned by this function */
6624+ static bool can_add_backtrace(JSValue obj)
6625+ {
6626+ JSObject *p;
6627+ if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
6628+ return false;
6629+ p = JS_VALUE_GET_OBJ(obj);
6630+ if (p->class_id != JS_CLASS_ERROR)
6631+ return false;
6632+ if (find_own_property1(p, JS_ATOM_stack))
6633+ return false;
6634+ return true;
6635+ }
6636+
66196637#define JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL (1 << 0)
66206638/* only taken into account if filename is provided */
66216639#define JS_BACKTRACE_FLAG_SINGLE_LEVEL (1 << 1)
66226640#define JS_BACKTRACE_FLAG_FILTER_FUNC (1 << 2)
66236641
66246642/* if filename != NULL, an additional level is added with the filename
66256643 and line number information (used for parse error). */
6626- static void build_backtrace(JSContext *ctx, JSValue error_obj , JSValue filter_func,
6644+ static void build_backtrace(JSContext *ctx, JSValue error_val , JSValue filter_func,
66276645 const char *filename, int line_num, int col_num,
66286646 int backtrace_flags)
66296647{
@@ -6634,7 +6652,7 @@ static void build_backtrace(JSContext *ctx, JSValue error_obj, JSValue filter_fu
66346652 const char *str1;
66356653 JSObject *p;
66366654 JSFunctionBytecode *b;
6637- bool backtrace_barrier, has_prepare;
6655+ bool backtrace_barrier, has_prepare, has_filter_func ;
66386656 JSRuntime *rt;
66396657 JSCallSiteData csd[64];
66406658 uint32_t i;
@@ -6646,6 +6664,7 @@ static void build_backtrace(JSContext *ctx, JSValue error_obj, JSValue filter_fu
66466664 stack_trace_limit = max_int(stack_trace_limit, 0);
66476665 rt = ctx->rt;
66486666 has_prepare = false;
6667+ has_filter_func = backtrace_flags & JS_BACKTRACE_FLAG_FILTER_FUNC;
66496668 i = 0;
66506669
66516670 if (!rt->in_prepare_stack_trace && !JS_IsNull(ctx->error_ctor)) {
@@ -6681,7 +6700,7 @@ static void build_backtrace(JSContext *ctx, JSValue error_obj, JSValue filter_fu
66816700
66826701 /* Find the frame we want to start from. Note that when a filter is used the filter
66836702 function will be the first, but we also specify we want to skip the first one. */
6684- if (backtrace_flags & JS_BACKTRACE_FLAG_FILTER_FUNC ) {
6703+ if (has_filter_func ) {
66856704 for (sf = sf_start; sf != NULL && i < stack_trace_limit; sf = sf->prev_frame) {
66866705 if (js_same_value(ctx, sf->cur_func, filter_func)) {
66876706 sf_start = sf;
@@ -6717,23 +6736,24 @@ static void build_backtrace(JSContext *ctx, JSValue error_obj, JSValue filter_fu
67176736 dbuf_printf(&dbuf, " at %s", str1);
67186737 JS_FreeCString(ctx, func_name_str);
67196738
6720- if (b) {
6739+ if (b && sf->cur_pc ) {
67216740 const char *atom_str;
67226741 int line_num1, col_num1;
6742+ uint32_t pc;
67236743
6724- /* Bytecode functions must have cur_pc set in the stack frame. */
6725- if (sf->cur_pc == NULL)
6726- abort();
6727-
6728- line_num1 = find_line_num(ctx, b,
6729- sf->cur_pc - b->byte_code_buf - 1,
6730- &col_num1);
6744+ pc = sf->cur_pc - b->byte_code_buf - 1;
6745+ line_num1 = find_line_num(ctx, b, pc, &col_num1);
67316746 atom_str = b->filename ? JS_AtomToCString(ctx, b->filename) : NULL;
67326747 dbuf_printf(&dbuf, " (%s", atom_str ? atom_str : "<null>");
67336748 JS_FreeCString(ctx, atom_str);
67346749 if (line_num1 != -1)
67356750 dbuf_printf(&dbuf, ":%d:%d", line_num1, col_num1);
67366751 dbuf_putc(&dbuf, ')');
6752+ } else if (b) {
6753+ // FIXME(bnoordhuis) Missing `sf->cur_pc = pc` in bytecode
6754+ // handler in JS_CallInternal. Almost never user observable
6755+ // except with intercepting JS proxies that throw exceptions.
6756+ dbuf_printf(&dbuf, " (missing)");
67376757 } else {
67386758 dbuf_printf(&dbuf, " (native)");
67396759 }
@@ -6769,7 +6789,7 @@ static void build_backtrace(JSContext *ctx, JSValue error_obj, JSValue filter_fu
67696789 JS_FreeValue(ctx, csd[k].func_name);
67706790 }
67716791 JSValue args[] = {
6772- error_obj ,
6792+ error_val ,
67736793 stack,
67746794 };
67756795 JSValue stack2 = JS_Call(ctx, prepare, ctx->error_ctor, countof(args), args);
@@ -6790,21 +6810,14 @@ static void build_backtrace(JSContext *ctx, JSValue error_obj, JSValue filter_fu
67906810 }
67916811
67926812 rt->in_prepare_stack_trace = false;
6793- JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_stack, stack, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
6794- }
6795-
6796- /* Note: it is important that no exception is returned by this function */
6797- static bool is_backtrace_needed(JSContext *ctx, JSValue obj)
6798- {
6799- JSObject *p;
6800- if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
6801- return false;
6802- p = JS_VALUE_GET_OBJ(obj);
6803- if (p->class_id != JS_CLASS_ERROR)
6804- return false;
6805- if (find_own_property1(p, JS_ATOM_stack))
6806- return false;
6807- return true;
6813+ if (JS_IsUndefined(ctx->error_back_trace))
6814+ ctx->error_back_trace = js_dup(stack);
6815+ if (has_filter_func || can_add_backtrace(error_val)) {
6816+ JS_DefinePropertyValue(ctx, error_val, JS_ATOM_stack, stack,
6817+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
6818+ } else {
6819+ JS_FreeValue(ctx, stack);
6820+ }
68086821}
68096822
68106823JSValue JS_NewError(JSContext *ctx)
@@ -17432,13 +17445,8 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValue func_obj,
1743217445 }
1743317446 }
1743417447 exception:
17435- if (is_backtrace_needed(ctx, rt->current_exception)) {
17436- /* add the backtrace information now (it is not done
17437- before if the exception happens in a bytecode
17438- operation */
17439- sf->cur_pc = pc;
17440- build_backtrace(ctx, rt->current_exception, JS_UNDEFINED, NULL, 0, 0, 0);
17441- }
17448+ sf->cur_pc = pc;
17449+ build_backtrace(ctx, rt->current_exception, JS_UNDEFINED, NULL, 0, 0, 0);
1744217450 if (!JS_IsUncatchableError(ctx, rt->current_exception)) {
1744317451 while (sp > stack_buf) {
1744417452 JSValue val = *--sp;
@@ -17453,6 +17461,8 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValue func_obj,
1745317461 } else {
1745417462 *sp++ = rt->current_exception;
1745517463 rt->current_exception = JS_UNINITIALIZED;
17464+ JS_FreeValueRT(rt, ctx->error_back_trace);
17465+ ctx->error_back_trace = JS_UNDEFINED;
1745617466 pc = b->byte_code_buf + pos;
1745717467 goto restart;
1745817468 }
@@ -25570,6 +25580,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
2557025580 js_parse_error(s, "line terminator not allowed after throw");
2557125581 goto fail;
2557225582 }
25583+ emit_source_loc(s);
2557325584 if (js_parse_expr(s))
2557425585 goto fail;
2557525586 emit_op(s, OP_throw);
@@ -56168,7 +56179,9 @@ bool JS_DetectModule(const char *input, size_t input_len)
5616856179}
5616956180
5617056181uintptr_t js_std_cmd(int cmd, ...) {
56182+ JSContext *ctx;
5617156183 JSRuntime *rt;
56184+ JSValue *pv;
5617256185 uintptr_t rv;
5617356186 va_list ap;
5617456187
@@ -56183,6 +56196,12 @@ uintptr_t js_std_cmd(int cmd, ...) {
5618356196 rt = va_arg(ap, JSRuntime *);
5618456197 rt->libc_opaque = va_arg(ap, void *);
5618556198 break;
56199+ case 2: // ErrorBackTrace
56200+ ctx = va_arg(ap, JSContext *);
56201+ pv = va_arg(ap, JSValue *);
56202+ *pv = ctx->error_back_trace;
56203+ ctx->error_back_trace = JS_UNDEFINED;
56204+ break;
5618656205 default:
5618756206 rv = -1;
5618856207 }
0 commit comments