Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 73 additions & 11 deletions quickjs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1863,7 +1863,7 @@ typedef struct JSClassShortDef {
static JSClassShortDef const js_std_class_def[] = {
{ JS_ATOM_Object, NULL, NULL }, /* JS_CLASS_OBJECT */
{ JS_ATOM_Array, js_array_finalizer, js_array_mark }, /* JS_CLASS_ARRAY */
{ JS_ATOM_Error, NULL, NULL }, /* JS_CLASS_ERROR */
{ JS_ATOM_Error, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_ERROR */
{ JS_ATOM_Number, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_NUMBER */
{ JS_ATOM_String, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_STRING */
{ JS_ATOM_Boolean, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BOOLEAN */
Expand Down Expand Up @@ -5829,6 +5829,7 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas
p->u.array.u.ptr = NULL;
p->u.array.count = 0;
break;
case JS_CLASS_ERROR:
case JS_CLASS_NUMBER:
case JS_CLASS_STRING:
case JS_CLASS_BOOLEAN:
Expand Down Expand Up @@ -7286,6 +7287,7 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
}
}
break;
case JS_CLASS_ERROR: /* u.object_data */
case JS_CLASS_NUMBER: /* u.object_data */
case JS_CLASS_STRING: /* u.object_data */
case JS_CLASS_BOOLEAN: /* u.object_data */
Expand Down Expand Up @@ -7749,7 +7751,23 @@ static bool can_add_backtrace(JSValueConst obj)
if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
return false;
p = JS_VALUE_GET_OBJ(obj);
if (p->class_id != JS_CLASS_ERROR && p->class_id != JS_CLASS_DOM_EXCEPTION)
if (p->class_id != JS_CLASS_DOM_EXCEPTION)
return false;
if (find_own_property1(p, JS_ATOM_stack))
return false;
return true;
}

/* Note: it is important that no exception is returned by this function */
static bool can_store_error_stack(JSValueConst obj)
{
JSObject *p;
if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)
return false;
p = JS_VALUE_GET_OBJ(obj);
if (p->class_id != JS_CLASS_ERROR)
return false;
if (!JS_IsUndefined(p->u.object_data))
return false;
if (find_own_property1(p, JS_ATOM_stack))
return false;
Expand Down Expand Up @@ -7952,7 +7970,18 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_val,

if (JS_IsUndefined(ctx->error_back_trace))
ctx->error_back_trace = js_dup(stack);
if (has_filter_func || can_add_backtrace(error_obj)) {
if (has_filter_func) {
/* Error.captureStackTrace(target, ...): install an own data property
on the (possibly non-Error) target, shadowing the accessor */
JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_stack, stack,
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
} else if (can_store_error_stack(error_obj)) {
/* genuine Error instance: store as the [[ErrorData]] stack value */
p = JS_VALUE_GET_OBJ(error_obj);
JS_FreeValue(ctx, p->u.object_data);
p->u.object_data = stack;
} else if (can_add_backtrace(error_obj)) {
/* DOMException and the like keep an own "stack" data property */
JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_stack, stack,
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
} else {
Expand Down Expand Up @@ -17536,14 +17565,7 @@ static void print_func_name(JSFunctionBytecode *b);

static bool needs_backtrace(JSValue exc)
{
JSObject *p;

if (JS_VALUE_GET_TAG(exc) != JS_TAG_OBJECT)
return false;
p = JS_VALUE_GET_OBJ(exc);
if (p->class_id != JS_CLASS_ERROR)
return false;
return !find_own_property1(p, JS_ATOM_stack);
return can_store_error_stack(exc) || can_add_backtrace(exc);
}

/* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */
Expand Down Expand Up @@ -42005,10 +42027,50 @@ static JSValue js_error_toString(JSContext *ctx, JSValueConst this_val,
return JS_ConcatString(ctx, name, msg);
}

static JSValue js_error_get_stack(JSContext *ctx, JSValueConst this_val)
{
JSObject *p;

if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
return JS_ThrowTypeErrorNotAnObject(ctx);
p = JS_VALUE_GET_OBJ(this_val);
if (p->class_id != JS_CLASS_ERROR)
return JS_UNDEFINED;
return js_dup(p->u.object_data);
}

static JSValue js_error_set_stack(JSContext *ctx, JSValueConst this_val,
JSValueConst value)
{
int ret, flags;

if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
return JS_ThrowTypeErrorNotAnObject(ctx);
if (!JS_IsString(value))
return JS_ThrowTypeError(ctx, "Error.prototype.stack setter expects a string");
if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_ERROR]))
return JS_ThrowTypeError(ctx, "Error.prototype.stack setter called on the home object");
ret = JS_GetOwnPropertyFlagsInternal(ctx, &flags, JS_VALUE_GET_OBJ(this_val),
JS_ATOM_stack);
if (ret < 0)
return JS_EXCEPTION;
if (ret == 0) {
if (JS_DefinePropertyValue(ctx, this_val, JS_ATOM_stack, js_dup(value),
JS_PROP_C_W_E | JS_PROP_THROW) < 0)
return JS_EXCEPTION;
} else {
if (JS_SetPropertyInternal2(ctx, this_val, JS_ATOM_stack, js_dup(value),
this_val, JS_PROP_THROW) < 0)
return JS_EXCEPTION;
}
return JS_UNDEFINED;
}

static const JSCFunctionListEntry js_error_proto_funcs[] = {
JS_CFUNC_DEF("toString", 0, js_error_toString ),
JS_PROP_STRING_DEF("name", "Error", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
JS_PROP_STRING_DEF("message", "", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),
JS_CGETSET_DEF("stack", js_error_get_stack, js_error_set_stack ),
};

static JSValue js_error_isError(JSContext *ctx, JSValueConst this_val,
Expand Down
2 changes: 1 addition & 1 deletion test262.conf
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ destructuring-assignment
destructuring-binding
dynamic-import
error-cause
error-stack-accessor=skip
error-stack-accessor
Error.isError
explicit-resource-management
exponentiation
Expand Down
Loading