Browse Source

Handle missing and empty _Formals in dump format

The distinction matters when loading back: if _Formals was omitted, we don't
want to load back an empty _Formals array for a function template because it
then breaks function instance .length computation.
pull/1516/head
Sami Vaarala 8 years ago
parent
commit
8d5ec2bff3
  1. 62
      src-input/duk_api_bytecode.c

62
src-input/duk_api_bytecode.c

@ -19,6 +19,7 @@
#define DUK__SER_STRING 0x00 #define DUK__SER_STRING 0x00
#define DUK__SER_NUMBER 0x01 #define DUK__SER_NUMBER 0x01
#define DUK__BYTECODE_INITIAL_ALLOC 256 #define DUK__BYTECODE_INITIAL_ALLOC 256
#define DUK__NO_FORMALS 0xffffffffUL
/* /*
* Dump/load helpers, xxx_raw() helpers do no buffer checks * Dump/load helpers, xxx_raw() helpers do no buffer checks
@ -183,40 +184,44 @@ DUK_LOCAL duk_uint8_t *duk__dump_formals(duk_hthread *thr, duk_uint8_t *p, duk_b
tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_STRING_INT_FORMALS(thr)); tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_STRING_INT_FORMALS(thr));
if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) { if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) {
duk_hobject *h; duk_harray *h;
duk_uint_fast32_t i; duk_uint32_t i;
h = DUK_TVAL_GET_OBJECT(tv); /* Here we rely on _Formals being a dense array containing
* strings. This should be the case unless _Formals has been
* tweaked by the application (which we don't support right
* now).
*/
h = (duk_harray *) DUK_TVAL_GET_OBJECT(tv);
DUK_ASSERT(h != NULL); DUK_ASSERT(h != NULL);
DUK_ASSERT(DUK_HOBJECT_IS_ARRAY((duk_hobject *) h));
DUK_ASSERT(h->length <= DUK_HOBJECT_GET_ASIZE((duk_hobject *) h));
/* We know _Formals is dense and all entries will be in the p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
* array part. GC and finalizers shouldn't affect _Formals DUK_ASSERT(h->length != DUK__NO_FORMALS); /* limits */
* so side effects should be fine. DUK_RAW_WRITE_U32_BE(p, h->length);
*/
for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) { for (i = 0; i < h->length; i++) {
duk_tval *tv_val; duk_tval *tv_val;
duk_hstring *varname; duk_hstring *varname;
tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, h, i); tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, (duk_hobject *) h, i);
DUK_ASSERT(tv_val != NULL); DUK_ASSERT(tv_val != NULL);
if (DUK_TVAL_IS_STRING(tv_val)) { DUK_ASSERT(DUK_TVAL_IS_STRING(tv_val));
/* Array is dense and contains only strings, but ASIZE may
* be larger than used part and there are UNUSED entries.
*/
varname = DUK_TVAL_GET_STRING(tv_val); varname = DUK_TVAL_GET_STRING(tv_val);
DUK_ASSERT(varname != NULL); DUK_ASSERT(varname != NULL);
DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(varname) >= 1); /* won't be confused with terminator */ DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(varname) >= 1);
DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(varname), p); p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(varname), p);
p = duk__dump_hstring_raw(p, varname); p = duk__dump_hstring_raw(p, varname);
} }
}
} else { } else {
DUK_DD(DUK_DDPRINT("dumping function without _Formals, emit empty list")); DUK_DD(DUK_DDPRINT("dumping function without _Formals, emit marker to indicate missing _Formals"));
}
p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p); p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Formals */ DUK_RAW_WRITE_U32_BE(p, DUK__NO_FORMALS); /* marker: no formals */
}
return p; return p;
} }
@ -394,6 +399,7 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
duk_idx_t idx_base; duk_idx_t idx_base;
duk_tval *tv1; duk_tval *tv1;
duk_uarridx_t arr_idx; duk_uarridx_t arr_idx;
duk_uarridx_t arr_limit;
duk_hobject *func_env; duk_hobject *func_env;
duk_bool_t need_pop; duk_bool_t need_pop;
@ -659,26 +665,20 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t
duk_compact_m1(ctx); duk_compact_m1(ctx);
duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE); duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
/* If _Formals wasn't present in the original function, the list /* _Formals may have been missing in the original function, which is
* here will be empty. Same happens if _Formals was present but * handled using a marker length.
* had zero length. We can omit _Formals from the result if its
* length is zero and matches nargs.
*/ */
arr_limit = DUK_RAW_READ_U32_BE(p);
if (arr_limit != DUK__NO_FORMALS) {
duk_push_array(ctx); /* _Formals */ duk_push_array(ctx); /* _Formals */
for (arr_idx = 0; ; arr_idx++) { for (arr_idx = 0; arr_idx < arr_limit; arr_idx++) {
/* XXX: awkward */
p = duk__load_string_raw(ctx, p); p = duk__load_string_raw(ctx, p);
if (duk_get_length(ctx, -1) == 0) {
duk_pop(ctx);
break;
}
duk_put_prop_index(ctx, -2, arr_idx); duk_put_prop_index(ctx, -2, arr_idx);
} }
if (arr_idx == 0 && h_fun->nargs == 0) {
duk_pop(ctx);
} else {
duk_compact_m1(ctx); duk_compact_m1(ctx);
duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE); duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
} else {
DUK_DD(DUK_DDPRINT("no _Formals in dumped function"));
} }
/* Return with final function pushed on stack top. */ /* Return with final function pushed on stack top. */

Loading…
Cancel
Save