|
19 | 19 | #define DUK__SER_STRING 0x00 |
20 | 20 | #define DUK__SER_NUMBER 0x01 |
21 | 21 | #define DUK__BYTECODE_INITIAL_ALLOC 256 |
| 22 | +#define DUK__NO_FORMALS 0xffffffffUL |
22 | 23 |
|
23 | 24 | /* |
24 | 25 | * 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 |
183 | 184 |
|
184 | 185 | tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_STRING_INT_FORMALS(thr)); |
185 | 186 | if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) { |
186 | | - duk_hobject *h; |
187 | | - duk_uint_fast32_t i; |
| 187 | + duk_harray *h; |
| 188 | + duk_uint32_t i; |
188 | 189 |
|
189 | | - h = DUK_TVAL_GET_OBJECT(tv); |
| 190 | + /* Here we rely on _Formals being a dense array containing |
| 191 | + * strings. This should be the case unless _Formals has been |
| 192 | + * tweaked by the application (which we don't support right |
| 193 | + * now). |
| 194 | + */ |
| 195 | + h = (duk_harray *) DUK_TVAL_GET_OBJECT(tv); |
190 | 196 | DUK_ASSERT(h != NULL); |
| 197 | + DUK_ASSERT(DUK_HOBJECT_IS_ARRAY((duk_hobject *) h)); |
| 198 | + DUK_ASSERT(h->length <= DUK_HOBJECT_GET_ASIZE((duk_hobject *) h)); |
191 | 199 |
|
192 | | - /* We know _Formals is dense and all entries will be in the |
193 | | - * array part. GC and finalizers shouldn't affect _Formals |
194 | | - * so side effects should be fine. |
195 | | - */ |
196 | | - for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) { |
| 200 | + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p); |
| 201 | + DUK_ASSERT(h->length != DUK__NO_FORMALS); /* limits */ |
| 202 | + DUK_RAW_WRITE_U32_BE(p, h->length); |
| 203 | + |
| 204 | + for (i = 0; i < h->length; i++) { |
197 | 205 | duk_tval *tv_val; |
198 | 206 | duk_hstring *varname; |
199 | 207 |
|
200 | | - tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, h, i); |
| 208 | + tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, (duk_hobject *) h, i); |
201 | 209 | DUK_ASSERT(tv_val != NULL); |
202 | | - if (DUK_TVAL_IS_STRING(tv_val)) { |
203 | | - /* Array is dense and contains only strings, but ASIZE may |
204 | | - * be larger than used part and there are UNUSED entries. |
205 | | - */ |
206 | | - varname = DUK_TVAL_GET_STRING(tv_val); |
207 | | - DUK_ASSERT(varname != NULL); |
208 | | - DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(varname) >= 1); /* won't be confused with terminator */ |
209 | | - |
210 | | - DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ |
211 | | - p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(varname), p); |
212 | | - p = duk__dump_hstring_raw(p, varname); |
213 | | - } |
| 210 | + DUK_ASSERT(DUK_TVAL_IS_STRING(tv_val)); |
| 211 | + |
| 212 | + varname = DUK_TVAL_GET_STRING(tv_val); |
| 213 | + DUK_ASSERT(varname != NULL); |
| 214 | + DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(varname) >= 1); |
| 215 | + |
| 216 | + DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ |
| 217 | + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(varname), p); |
| 218 | + p = duk__dump_hstring_raw(p, varname); |
214 | 219 | } |
215 | 220 | } else { |
216 | | - DUK_DD(DUK_DDPRINT("dumping function without _Formals, emit empty list")); |
| 221 | + DUK_DD(DUK_DDPRINT("dumping function without _Formals, emit marker to indicate missing _Formals")); |
| 222 | + p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p); |
| 223 | + DUK_RAW_WRITE_U32_BE(p, DUK__NO_FORMALS); /* marker: no formals */ |
217 | 224 | } |
218 | | - p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p); |
219 | | - DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Formals */ |
220 | 225 | return p; |
221 | 226 | } |
222 | 227 |
|
@@ -394,6 +399,7 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t |
394 | 399 | duk_idx_t idx_base; |
395 | 400 | duk_tval *tv1; |
396 | 401 | duk_uarridx_t arr_idx; |
| 402 | + duk_uarridx_t arr_limit; |
397 | 403 | duk_hobject *func_env; |
398 | 404 | duk_bool_t need_pop; |
399 | 405 |
|
@@ -659,26 +665,20 @@ static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t |
659 | 665 | duk_compact_m1(ctx); |
660 | 666 | duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE); |
661 | 667 |
|
662 | | - /* If _Formals wasn't present in the original function, the list |
663 | | - * here will be empty. Same happens if _Formals was present but |
664 | | - * had zero length. We can omit _Formals from the result if its |
665 | | - * length is zero and matches nargs. |
| 668 | + /* _Formals may have been missing in the original function, which is |
| 669 | + * handled using a marker length. |
666 | 670 | */ |
667 | | - duk_push_array(ctx); /* _Formals */ |
668 | | - for (arr_idx = 0; ; arr_idx++) { |
669 | | - /* XXX: awkward */ |
670 | | - p = duk__load_string_raw(ctx, p); |
671 | | - if (duk_get_length(ctx, -1) == 0) { |
672 | | - duk_pop(ctx); |
673 | | - break; |
| 671 | + arr_limit = DUK_RAW_READ_U32_BE(p); |
| 672 | + if (arr_limit != DUK__NO_FORMALS) { |
| 673 | + duk_push_array(ctx); /* _Formals */ |
| 674 | + for (arr_idx = 0; arr_idx < arr_limit; arr_idx++) { |
| 675 | + p = duk__load_string_raw(ctx, p); |
| 676 | + duk_put_prop_index(ctx, -2, arr_idx); |
674 | 677 | } |
675 | | - duk_put_prop_index(ctx, -2, arr_idx); |
676 | | - } |
677 | | - if (arr_idx == 0 && h_fun->nargs == 0) { |
678 | | - duk_pop(ctx); |
679 | | - } else { |
680 | 678 | duk_compact_m1(ctx); |
681 | 679 | duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE); |
| 680 | + } else { |
| 681 | + DUK_DD(DUK_DDPRINT("no _Formals in dumped function")); |
682 | 682 | } |
683 | 683 |
|
684 | 684 | /* Return with final function pushed on stack top. */ |
|
0 commit comments