Browse Source

Simulate a defprop in error .fileName etc setters

Previous behavior was to ignore the setter call, so that attempting a write
would be a no-op: "err.fileName = 'dummy';" would do nothing.  Because the
inherited setter is configurable, the user could still create an own property
of the same name using Object.defineProperty() or duk_def_prop() but this is
not very intuitive nor very well documented.

The updated behavior is to make the .fileName, .lineNumber, and .stack setter
make the duk_def_prop() call automatically so that writing to these properties
will seem to work as if the property was not an inherited accessor.

This matches how e.g. V8 and Spidermonkey work, and also matches how Duktape
works when tracebacks are disabled and .fileName and .lineNumber are concrete
own properties.
pull/390/head
Sami Vaarala 9 years ago
parent
commit
d8e49b7f41
  1. 53
      src/duk_bi_error.c
  2. 4
      src/duk_bi_protos.h
  3. 5
      src/duk_hthread_builtins.c
  4. 11
      src/genbuiltins.py

53
src/duk_bi_error.c

@ -93,7 +93,7 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) {
return 1;
}
#ifdef DUK_USE_TRACEBACKS
#if defined(DUK_USE_TRACEBACKS)
/*
* Traceback handling
@ -114,7 +114,7 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) {
#define DUK__OUTPUT_TYPE_FILENAME 0
#define DUK__OUTPUT_TYPE_LINENUMBER 1
DUK_LOCAL duk_ret_t duk__traceback_getter_helper(duk_context *ctx, duk_small_int_t output_type) {
DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t output_type) {
duk_hthread *thr = (duk_hthread *) ctx;
duk_idx_t idx_td;
duk_small_int_t i; /* traceback depth fits into 16 bits */
@ -277,20 +277,20 @@ DUK_LOCAL duk_ret_t duk__traceback_getter_helper(duk_context *ctx, duk_small_int
}
}
/* XXX: output type could be encoded into native function 'magic' value to
* save space.
/* XXX: Output type could be encoded into native function 'magic' value to
* save space. For setters the stridx could be encoded into 'magic'.
*/
DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx) {
return duk__traceback_getter_helper(ctx, DUK__OUTPUT_TYPE_TRACEBACK);
return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_TRACEBACK);
}
DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx) {
return duk__traceback_getter_helper(ctx, DUK__OUTPUT_TYPE_FILENAME);
return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_FILENAME);
}
DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx) {
return duk__traceback_getter_helper(ctx, DUK__OUTPUT_TYPE_LINENUMBER);
return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_LINENUMBER);
}
#undef DUK__OUTPUT_TYPE_TRACEBACK
@ -330,11 +330,40 @@ DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx
#endif /* DUK_USE_TRACEBACKS */
DUK_INTERNAL duk_ret_t duk_bi_error_prototype_nop_setter(duk_context *ctx) {
/* Attempt to write 'stack', 'fileName', 'lineNumber' is a silent no-op.
* User can use Object.defineProperty() to override this behavior.
DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_context *ctx, duk_small_uint_t stridx_key) {
/* Attempt to write 'stack', 'fileName', 'lineNumber' works as if
* user code called Object.defineProperty() to create an overriding
* own property. This allows user code to overwrite .fileName etc
* intuitively as e.g. "err.fileName = 'dummy'" as one might expect.
* See https://github.com/svaarala/duktape/issues/387.
*/
DUK_ASSERT_TOP(ctx, 1); /* fixed arg count */
DUK_UNREF(ctx);
DUK_ASSERT_TOP(ctx, 1); /* fixed arg count: value */
duk_push_this(ctx);
duk_push_hstring_stridx(ctx, (duk_small_int_t) stridx_key);
duk_dup(ctx, 0);
/* [ ... obj key value ] */
DUK_DD(DUK_DDPRINT("error setter: %!T %!T %!T",
duk_get_tval(ctx, -3), duk_get_tval(ctx, -2), duk_get_tval(ctx, -1)));
duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE |
DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE |
DUK_DEFPROP_HAVE_ENUMERABLE | /*not enumerable*/
DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE);
return 0;
}
DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx) {
return duk__error_setter_helper(ctx, DUK_STRIDX_STACK);
}
DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx) {
return duk__error_setter_helper(ctx, DUK_STRIDX_FILE_NAME);
}
DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx) {
return duk__error_setter_helper(ctx, DUK_STRIDX_LINE_NUMBER);
}

4
src/duk_bi_protos.h

@ -97,7 +97,9 @@ DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_nop_setter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_constructor(duk_context *ctx);
DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_context *ctx);

5
src/duk_hthread_builtins.c

@ -330,9 +330,6 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
duk_c_function c_func_getter;
duk_c_function c_func_setter;
/* XXX: this is a bit awkward because there is no exposed helper
* in the API style, only this internal helper.
*/
DUK_DDD(DUK_DDDPRINT("built-in accessor property: objidx=%ld, stridx=%ld, getteridx=%ld, setteridx=%ld, flags=0x%04lx",
(long) i, (long) stridx, (long) natidx_getter, (long) natidx_setter, (unsigned long) prop_flags));
@ -341,7 +338,7 @@ DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
duk_push_c_function_noconstruct_noexotic(ctx, c_func_getter, 0); /* always 0 args */
duk_push_c_function_noconstruct_noexotic(ctx, c_func_setter, 1); /* always 1 arg */
/* XXX: magic for getter/setter? */
/* XXX: magic for getter/setter? use duk_def_prop()? */
prop_flags |= DUK_PROPDESC_FLAG_ACCESSOR; /* accessor flag not encoded explicitly */
duk_hobject_define_accessor_internal(thr,

11
src/genbuiltins.py

@ -852,13 +852,13 @@ bi_error_prototype = {
{ 'name': 'stack',
'getter': 'duk_bi_error_prototype_stack_getter',
'setter': 'duk_bi_error_prototype_nop_setter' },
'setter': 'duk_bi_error_prototype_stack_setter' },
{ 'name': 'fileName',
'getter': 'duk_bi_error_prototype_filename_getter',
'setter': 'duk_bi_error_prototype_nop_setter' },
'setter': 'duk_bi_error_prototype_filename_setter' },
{ 'name': 'lineNumber',
'getter': 'duk_bi_error_prototype_linenumber_getter',
'setter': 'duk_bi_error_prototype_nop_setter' },
'setter': 'duk_bi_error_prototype_linenumber_setter' },
],
'functions': [
{ 'name': 'toString', 'native': 'duk_bi_error_prototype_to_string', 'length': 0 },
@ -2008,6 +2008,11 @@ class GenBuiltins:
#print(v, '->', i)
return i
raise Exception('invalid builtin index for magic: ' % repr(v))
elif elem['type'] == 'stridx':
v = self.gs.stringToIndex(valspec['name'])
if not (v >= -0x8000 and v <= 0x7fff):
raise Exception('invalid stridx value for magic: %s' % repr(v))
return v & 0xffff
elif elem['type'] == 'plain':
v = elem['value']
if not (v >= -0x8000 and v <= 0x7fff):

Loading…
Cancel
Save