4 * The bytecode load primitive is more important performance-wise than the
7 * Unlike most Duktape API calls, bytecode dump/load is not guaranteed to be
8 * memory safe for invalid arguments - caller beware! There's little point
9 * in trying to achieve memory safety unless bytecode instructions are also
10 * validated which is not easy to do with indirect register references etc.
13 #include "duk_internal.h"
15 #if defined(DUK_USE_BYTECODE_DUMP_SUPPORT)
17 #define DUK__SER_MARKER 0xff
18 #define DUK__SER_VERSION 0x00
19 #define DUK__SER_STRING 0x00
20 #define DUK__SER_NUMBER 0x01
21 #define DUK__BYTECODE_INITIAL_ALLOC 256
24 * Dump/load helpers, xxx_raw() helpers do no buffer checks
27 DUK_LOCAL duk_uint8_t
*duk__load_string_raw(duk_context
*ctx
, duk_uint8_t
*p
) {
30 len
= DUK_RAW_READ_U32_BE(p
);
31 duk_push_lstring(ctx
, (const char *) p
, len
);
36 DUK_LOCAL duk_uint8_t
*duk__load_buffer_raw(duk_context
*ctx
, duk_uint8_t
*p
) {
40 len
= DUK_RAW_READ_U32_BE(p
);
41 buf
= (duk_uint8_t
*) duk_push_fixed_buffer(ctx
, (duk_size_t
) len
);
42 DUK_ASSERT(buf
!= NULL
);
43 DUK_MEMCPY((void *) buf
, (const void *) p
, (size_t) len
);
48 DUK_LOCAL duk_uint8_t
*duk__dump_hstring_raw(duk_uint8_t
*p
, duk_hstring
*h
) {
52 DUK_ASSERT(h
!= NULL
);
54 len
= DUK_HSTRING_GET_BYTELEN(h
);
55 DUK_ASSERT(len
<= 0xffffffffUL
); /* string limits */
56 tmp32
= (duk_uint32_t
) len
;
57 DUK_RAW_WRITE_U32_BE(p
, tmp32
);
58 DUK_MEMCPY((void *) p
,
59 (const void *) DUK_HSTRING_GET_DATA(h
),
65 DUK_LOCAL duk_uint8_t
*duk__dump_hbuffer_raw(duk_hthread
*thr
, duk_uint8_t
*p
, duk_hbuffer
*h
) {
69 DUK_ASSERT(thr
!= NULL
);
70 DUK_ASSERT(h
!= NULL
);
73 len
= DUK_HBUFFER_GET_SIZE(h
);
74 DUK_ASSERT(len
<= 0xffffffffUL
); /* buffer limits */
75 tmp32
= (duk_uint32_t
) len
;
76 DUK_RAW_WRITE_U32_BE(p
, tmp32
);
77 DUK_MEMCPY((void *) p
,
78 (const void *) DUK_HBUFFER_GET_DATA_PTR(thr
->heap
, h
),
84 DUK_LOCAL duk_uint8_t
*duk__dump_string_prop(duk_hthread
*thr
, duk_uint8_t
*p
, duk_bufwriter_ctx
*bw_ctx
, duk_hobject
*func
, duk_small_uint_t stridx
) {
88 tv
= duk_hobject_find_existing_entry_tval_ptr(thr
->heap
, (duk_hobject
*) func
, DUK_HTHREAD_GET_STRING(thr
, stridx
));
89 if (tv
!= NULL
&& DUK_TVAL_IS_STRING(tv
)) {
90 h_str
= DUK_TVAL_GET_STRING(tv
);
91 DUK_ASSERT(h_str
!= NULL
);
93 h_str
= DUK_HTHREAD_STRING_EMPTY_STRING(thr
);
94 DUK_ASSERT(h_str
!= NULL
);
96 DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN
<= 0x7fffffffUL
); /* ensures no overflow */
97 p
= DUK_BW_ENSURE_RAW(thr
, bw_ctx
, 4 + DUK_HSTRING_GET_BYTELEN(h_str
), p
);
98 p
= duk__dump_hstring_raw(p
, h_str
);
102 DUK_LOCAL duk_uint8_t
*duk__dump_buffer_prop(duk_hthread
*thr
, duk_uint8_t
*p
, duk_bufwriter_ctx
*bw_ctx
, duk_hobject
*func
, duk_small_uint_t stridx
) {
105 tv
= duk_hobject_find_existing_entry_tval_ptr(thr
->heap
, (duk_hobject
*) func
, DUK_HTHREAD_GET_STRING(thr
, stridx
));
106 if (tv
!= NULL
&& DUK_TVAL_IS_BUFFER(tv
)) {
108 h_buf
= DUK_TVAL_GET_BUFFER(tv
);
109 DUK_ASSERT(h_buf
!= NULL
);
110 DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN
<= 0x7fffffffUL
); /* ensures no overflow */
111 p
= DUK_BW_ENSURE_RAW(thr
, bw_ctx
, 4 + DUK_HBUFFER_GET_SIZE(h_buf
), p
);
112 p
= duk__dump_hbuffer_raw(thr
, p
, h_buf
);
114 p
= DUK_BW_ENSURE_RAW(thr
, bw_ctx
, 4, p
);
115 DUK_RAW_WRITE_U32_BE(p
, 0);
120 DUK_LOCAL duk_uint8_t
*duk__dump_uint32_prop(duk_hthread
*thr
, duk_uint8_t
*p
, duk_bufwriter_ctx
*bw_ctx
, duk_hobject
*func
, duk_small_uint_t stridx
, duk_uint32_t def_value
) {
124 tv
= duk_hobject_find_existing_entry_tval_ptr(thr
->heap
, (duk_hobject
*) func
, DUK_HTHREAD_GET_STRING(thr
, stridx
));
125 if (tv
!= NULL
&& DUK_TVAL_IS_NUMBER(tv
)) {
126 val
= (duk_uint32_t
) DUK_TVAL_GET_NUMBER(tv
);
130 p
= DUK_BW_ENSURE_RAW(thr
, bw_ctx
, 4, p
);
131 DUK_RAW_WRITE_U32_BE(p
, val
);
135 DUK_LOCAL duk_uint8_t
*duk__dump_varmap(duk_hthread
*thr
, duk_uint8_t
*p
, duk_bufwriter_ctx
*bw_ctx
, duk_hobject
*func
) {
138 tv
= duk_hobject_find_existing_entry_tval_ptr(thr
->heap
, (duk_hobject
*) func
, DUK_HTHREAD_STRING_INT_VARMAP(thr
));
139 if (tv
!= NULL
&& DUK_TVAL_IS_OBJECT(tv
)) {
143 h
= DUK_TVAL_GET_OBJECT(tv
);
144 DUK_ASSERT(h
!= NULL
);
146 /* We know _Varmap only has own properties so walk property
147 * table directly. We also know _Varmap is dense and all
148 * values are numbers; assert for these. GC and finalizers
149 * shouldn't affect _Varmap so side effects should be fine.
151 for (i
= 0; i
< (duk_uint_fast32_t
) DUK_HOBJECT_GET_ENEXT(h
); i
++) {
156 key
= DUK_HOBJECT_E_GET_KEY(thr
->heap
, h
, i
);
157 DUK_ASSERT(key
!= NULL
); /* _Varmap is dense */
158 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr
->heap
, h
, i
));
159 tv_val
= DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr
->heap
, h
, i
);
160 DUK_ASSERT(tv_val
!= NULL
);
161 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_val
)); /* known to be number; in fact an integer */
162 #if defined(DUK_USE_FASTINT)
163 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv_val
));
164 DUK_ASSERT(DUK_TVAL_GET_FASTINT(tv_val
) == (duk_int64_t
) DUK_TVAL_GET_FASTINT_U32(tv_val
)); /* known to be 32-bit */
165 val
= DUK_TVAL_GET_FASTINT_U32(tv_val
);
167 val
= (duk_uint32_t
) DUK_TVAL_GET_NUMBER(tv_val
);
170 DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN
<= 0x7fffffffUL
); /* ensures no overflow */
171 p
= DUK_BW_ENSURE_RAW(thr
, bw_ctx
, 4 + DUK_HSTRING_GET_BYTELEN(key
) + 4, p
);
172 p
= duk__dump_hstring_raw(p
, key
);
173 DUK_RAW_WRITE_U32_BE(p
, val
);
176 p
= DUK_BW_ENSURE_RAW(thr
, bw_ctx
, 4, p
);
177 DUK_RAW_WRITE_U32_BE(p
, 0); /* end of _Varmap */
181 DUK_LOCAL duk_uint8_t
*duk__dump_formals(duk_hthread
*thr
, duk_uint8_t
*p
, duk_bufwriter_ctx
*bw_ctx
, duk_hobject
*func
) {
184 tv
= duk_hobject_find_existing_entry_tval_ptr(thr
->heap
, (duk_hobject
*) func
, DUK_HTHREAD_STRING_INT_FORMALS(thr
));
185 if (tv
!= NULL
&& DUK_TVAL_IS_OBJECT(tv
)) {
189 h
= DUK_TVAL_GET_OBJECT(tv
);
190 DUK_ASSERT(h
!= NULL
);
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.
196 for (i
= 0; i
< (duk_uint_fast32_t
) DUK_HOBJECT_GET_ASIZE(h
); i
++) {
198 duk_hstring
*varname
;
200 tv_val
= DUK_HOBJECT_A_GET_VALUE_PTR(thr
->heap
, h
, i
);
201 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.
206 varname
= DUK_TVAL_GET_STRING(tv_val
);
207 DUK_ASSERT(varname
!= NULL
);
209 DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN
<= 0x7fffffffUL
); /* ensures no overflow */
210 p
= DUK_BW_ENSURE_RAW(thr
, bw_ctx
, 4 + DUK_HSTRING_GET_BYTELEN(varname
), p
);
211 p
= duk__dump_hstring_raw(p
, varname
);
215 p
= DUK_BW_ENSURE_RAW(thr
, bw_ctx
, 4, p
);
216 DUK_RAW_WRITE_U32_BE(p
, 0); /* end of _Formals */
220 static duk_uint8_t
*duk__dump_func(duk_context
*ctx
, duk_hcompiledfunction
*func
, duk_bufwriter_ctx
*bw_ctx
, duk_uint8_t
*p
) {
222 duk_tval
*tv
, *tv_end
;
223 duk_instr_t
*ins
, *ins_end
;
224 duk_hobject
**fn
, **fn_end
;
226 duk_uint32_t count_instr
;
231 thr
= (duk_hthread
*) ctx
;
235 DUK_DD(DUK_DDPRINT("dumping function %p to %p: "
236 "consts=[%p,%p[ (%ld bytes, %ld items), "
237 "funcs=[%p,%p[ (%ld bytes, %ld items), "
238 "code=[%p,%p[ (%ld bytes, %ld items)",
241 (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr
->heap
, func
),
242 (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr
->heap
, func
),
243 (long) DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE(thr
->heap
, func
),
244 (long) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(thr
->heap
, func
),
245 (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr
->heap
, func
),
246 (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr
->heap
, func
),
247 (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE(thr
->heap
, func
),
248 (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr
->heap
, func
),
249 (void *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr
->heap
, func
),
250 (void *) DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr
->heap
, func
),
251 (long) DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(thr
->heap
, func
),
252 (long) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(thr
->heap
, func
)));
254 DUK_ASSERT(DUK_USE_ESBC_MAX_BYTES
<= 0x7fffffffUL
); /* ensures no overflow */
255 count_instr
= (duk_uint32_t
) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(thr
->heap
, func
);
256 p
= DUK_BW_ENSURE_RAW(thr
, bw_ctx
, 3 * 4 + 2 * 2 + 3 * 4 + count_instr
* 4, p
);
258 /* Fixed header info. */
260 DUK_RAW_WRITE_U32_BE(p
, tmp32
);
261 tmp32
= (duk_uint32_t
) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(thr
->heap
, func
);
262 DUK_RAW_WRITE_U32_BE(p
, tmp32
);
263 tmp32
= (duk_uint32_t
) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr
->heap
, func
);
264 DUK_RAW_WRITE_U32_BE(p
, tmp32
);
266 DUK_RAW_WRITE_U16_BE(p
, tmp16
);
268 DUK_RAW_WRITE_U16_BE(p
, tmp16
);
269 #if defined(DUK_USE_DEBUGGER_SUPPORT)
270 tmp32
= func
->start_line
;
271 DUK_RAW_WRITE_U32_BE(p
, tmp32
);
272 tmp32
= func
->end_line
;
273 DUK_RAW_WRITE_U32_BE(p
, tmp32
);
275 DUK_RAW_WRITE_U32_BE(p
, 0);
276 DUK_RAW_WRITE_U32_BE(p
, 0);
278 tmp32
= ((duk_heaphdr
*) func
)->h_flags
& DUK_HEAPHDR_FLAGS_FLAG_MASK
;
279 DUK_RAW_WRITE_U32_BE(p
, tmp32
);
281 /* Bytecode instructions: endian conversion needed unless
282 * platform is big endian.
284 ins
= DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr
->heap
, func
);
285 ins_end
= DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr
->heap
, func
);
286 DUK_ASSERT((duk_size_t
) (ins_end
- ins
) == (duk_size_t
) count_instr
);
287 #if defined(DUK_USE_INTEGER_BE)
288 DUK_MEMCPY((void *) p
, (const void *) ins
, (size_t) (ins_end
- ins
));
289 p
+= (size_t) (ins_end
- ins
);
291 while (ins
!= ins_end
) {
292 tmp32
= (duk_uint32_t
) (*ins
);
293 DUK_RAW_WRITE_U32_BE(p
, tmp32
);
298 /* Constants: variable size encoding. */
299 tv
= DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr
->heap
, func
);
300 tv_end
= DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr
->heap
, func
);
301 while (tv
!= tv_end
) {
302 /* constants are strings or numbers now */
303 DUK_ASSERT(DUK_TVAL_IS_STRING(tv
) ||
304 DUK_TVAL_IS_NUMBER(tv
));
306 if (DUK_TVAL_IS_STRING(tv
)) {
307 h_str
= DUK_TVAL_GET_STRING(tv
);
308 DUK_ASSERT(h_str
!= NULL
);
309 DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN
<= 0x7fffffffUL
); /* ensures no overflow */
310 p
= DUK_BW_ENSURE_RAW(thr
, bw_ctx
, 1 + 4 + DUK_HSTRING_GET_BYTELEN(h_str
), p
),
311 *p
++ = DUK__SER_STRING
;
312 p
= duk__dump_hstring_raw(p
, h_str
);
314 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv
));
315 p
= DUK_BW_ENSURE_RAW(thr
, bw_ctx
, 1 + 8, p
);
316 *p
++ = DUK__SER_NUMBER
;
317 d
= DUK_TVAL_GET_NUMBER(tv
);
318 DUK_RAW_WRITE_DOUBLE_BE(p
, d
);
323 /* Inner functions recursively. */
324 fn
= (duk_hobject
**) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr
->heap
, func
);
325 fn_end
= (duk_hobject
**) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr
->heap
, func
);
326 while (fn
!= fn_end
) {
327 /* XXX: This causes recursion up to inner function depth
328 * which is normally not an issue, e.g. mark-and-sweep uses
329 * a recursion limiter to avoid C stack issues. Avoiding
330 * this would mean some sort of a work list or just refusing
331 * to serialize deep functions.
333 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(*fn
));
334 p
= duk__dump_func(ctx
, (duk_hcompiledfunction
*) *fn
, bw_ctx
, p
);
338 /* Object extra properties.
340 * There are some difference between function templates and functions.
341 * For example, function templates don't have .length and nargs is
342 * normally used to instantiate the functions.
345 p
= duk__dump_uint32_prop(thr
, p
, bw_ctx
, (duk_hobject
*) func
, DUK_STRIDX_LENGTH
, (duk_uint32_t
) func
->nargs
);
346 p
= duk__dump_string_prop(thr
, p
, bw_ctx
, (duk_hobject
*) func
, DUK_STRIDX_NAME
);
347 p
= duk__dump_string_prop(thr
, p
, bw_ctx
, (duk_hobject
*) func
, DUK_STRIDX_FILE_NAME
);
348 p
= duk__dump_buffer_prop(thr
, p
, bw_ctx
, (duk_hobject
*) func
, DUK_STRIDX_INT_PC2LINE
);
349 p
= duk__dump_varmap(thr
, p
, bw_ctx
, (duk_hobject
*) func
);
350 p
= duk__dump_formals(thr
, p
, bw_ctx
, (duk_hobject
*) func
);
352 DUK_DD(DUK_DDPRINT("serialized function %p -> final pointer %p", (void *) func
, (void *) p
));
357 /* Load a function from bytecode. The function object returned here must
358 * match what is created by duk_js_push_closure() with respect to its flags,
361 * NOTE: there are intentionally no input buffer length / bound checks.
362 * Adding them would be easy but wouldn't ensure memory safety as untrusted
363 * or broken bytecode is unsafe during execution unless the opcodes themselves
364 * are validated (which is quite complex, especially for indirect opcodes).
367 #define DUK__ASSERT_LEFT(n) do { \
368 DUK_ASSERT((duk_size_t) (p_end - p) >= (duk_size_t) (n)); \
371 static duk_uint8_t
*duk__load_func(duk_context
*ctx
, duk_uint8_t
*p
, duk_uint8_t
*p_end
) {
373 duk_hcompiledfunction
*h_fun
;
375 duk_size_t data_size
;
376 duk_uint32_t count_instr
, count_const
, count_funcs
;
379 duk_small_uint_t const_type
;
380 duk_uint8_t
*fun_data
;
384 duk_uarridx_t arr_idx
;
386 /* XXX: There's some overlap with duk_js_closure() here, but
387 * seems difficult to share code. Ensure that the final function
388 * looks the same as created by duk_js_closure().
391 DUK_ASSERT(ctx
!= NULL
);
392 thr
= (duk_hthread
*) ctx
;
394 DUK_DD(DUK_DDPRINT("loading function, p=%p, p_end=%p", (void *) p
, (void *) p_end
));
396 DUK__ASSERT_LEFT(3 * 4);
397 count_instr
= DUK_RAW_READ_U32_BE(p
);
398 count_const
= DUK_RAW_READ_U32_BE(p
);
399 count_funcs
= DUK_RAW_READ_U32_BE(p
);
401 data_size
= sizeof(duk_tval
) * count_const
+
402 sizeof(duk_hobject
*) * count_funcs
+
403 sizeof(duk_instr_t
) * count_instr
;
405 DUK_DD(DUK_DDPRINT("instr=%ld, const=%ld, funcs=%ld, data_size=%ld",
406 (long) count_instr
, (long) count_const
,
407 (long) count_const
, (long) data_size
));
409 /* Value stack is used to ensure reachability of constants and
410 * inner functions being loaded. Require enough space to handle
411 * large functions correctly.
413 duk_require_stack(ctx
, 2 + count_const
+ count_funcs
);
414 idx_base
= duk_get_top(ctx
);
416 /* Push function object, init flags etc. This must match
417 * duk_js_push_closure() quite carefully.
419 duk_push_compiledfunction(ctx
);
420 h_fun
= duk_get_hcompiledfunction(ctx
, -1);
421 DUK_ASSERT(h_fun
!= NULL
);
422 DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject
*) h_fun
));
423 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr
->heap
, h_fun
) == NULL
);
424 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr
->heap
, h_fun
) == NULL
);
425 DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr
->heap
, h_fun
) == NULL
);
427 h_fun
->nregs
= DUK_RAW_READ_U16_BE(p
);
428 h_fun
->nargs
= DUK_RAW_READ_U16_BE(p
);
429 #if defined(DUK_USE_DEBUGGER_SUPPORT)
430 h_fun
->start_line
= DUK_RAW_READ_U32_BE(p
);
431 h_fun
->end_line
= DUK_RAW_READ_U32_BE(p
);
433 p
+= 8; /* skip line info */
436 /* duk_hcompiledfunction flags; quite version specific */
437 tmp32
= DUK_RAW_READ_U32_BE(p
);
438 DUK_HEAPHDR_SET_FLAGS((duk_heaphdr
*) h_fun
, tmp32
);
440 /* standard prototype */
441 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr
, &h_fun
->obj
, thr
->builtins
[DUK_BIDX_FUNCTION_PROTOTYPE
]);
443 /* assert just a few critical flags */
444 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr
*) h_fun
) == DUK_HTYPE_OBJECT
);
445 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&h_fun
->obj
));
446 DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(&h_fun
->obj
));
447 DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(&h_fun
->obj
));
448 DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(&h_fun
->obj
));
449 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&h_fun
->obj
));
450 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&h_fun
->obj
));
451 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&h_fun
->obj
));
453 /* Create function 'data' buffer but don't attach it yet. */
454 fun_data
= (duk_uint8_t
*) duk_push_fixed_buffer(ctx
, data_size
);
455 DUK_ASSERT(fun_data
!= NULL
);
457 /* Load bytecode instructions. */
458 DUK_ASSERT(sizeof(duk_instr_t
) == 4);
459 DUK__ASSERT_LEFT(count_instr
* sizeof(duk_instr_t
));
460 #if defined(DUK_USE_INTEGER_BE)
461 q
= fun_data
+ sizeof(duk_tval
) * count_const
+ sizeof(duk_hobject
*) * count_funcs
;
462 DUK_MEMCPY((void *) q
,
464 sizeof(duk_instr_t
) * count_instr
);
465 p
+= sizeof(duk_instr_t
) * count_instr
;
467 q
= fun_data
+ sizeof(duk_tval
) * count_const
+ sizeof(duk_hobject
*) * count_funcs
;
468 for (n
= count_instr
; n
> 0; n
--) {
469 *((duk_instr_t
*) (void *) q
) = DUK_RAW_READ_U32_BE(p
);
470 q
+= sizeof(duk_instr_t
);
474 /* Load constants onto value stack but don't yet copy to buffer. */
475 for (n
= count_const
; n
> 0; n
--) {
477 const_type
= DUK_RAW_READ_U8(p
);
478 switch (const_type
) {
479 case DUK__SER_STRING
: {
480 p
= duk__load_string_raw(ctx
, p
);
483 case DUK__SER_NUMBER
: {
484 /* Important to do a fastint check so that constants are
485 * properly read back as fastints.
490 val
= DUK_RAW_READ_DOUBLE_BE(p
);
491 DUK_TVAL_SET_NUMBER_CHKFAST(&tv_tmp
, val
);
492 duk_push_tval(ctx
, &tv_tmp
);
501 /* Load inner functions to value stack, but don't yet copy to buffer. */
502 for (n
= count_funcs
; n
> 0; n
--) {
503 p
= duk__load_func(ctx
, p
, p_end
);
509 /* With constants and inner functions on value stack, we can now
510 * atomically finish the function 'data' buffer, bump refcounts,
513 * Here we take advantage of the value stack being just a duk_tval
514 * array: we can just memcpy() the constants as long as we incref
518 h_data
= (duk_hbuffer
*) duk_get_hbuffer(ctx
, idx_base
+ 1);
519 DUK_ASSERT(h_data
!= NULL
);
520 DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC(h_data
));
521 DUK_HCOMPILEDFUNCTION_SET_DATA(thr
->heap
, h_fun
, h_data
);
522 DUK_HBUFFER_INCREF(thr
, h_data
);
524 tv1
= duk_get_tval(ctx
, idx_base
+ 2); /* may be NULL if no constants or inner funcs */
525 DUK_ASSERT((count_const
== 0 && count_funcs
== 0) || tv1
!= NULL
);
528 if (count_const
> 0) {
529 /* Explicit zero size check to avoid NULL 'tv1'. */
530 DUK_MEMCPY((void *) q
, (const void *) tv1
, sizeof(duk_tval
) * count_const
);
531 for (n
= count_const
; n
> 0; n
--) {
532 DUK_TVAL_INCREF_FAST(thr
, (duk_tval
*) (void *) q
); /* no side effects */
533 q
+= sizeof(duk_tval
);
538 DUK_HCOMPILEDFUNCTION_SET_FUNCS(thr
->heap
, h_fun
, (duk_hobject
**) (void *) q
);
539 for (n
= count_funcs
; n
> 0; n
--) {
542 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1
));
543 h_obj
= DUK_TVAL_GET_OBJECT(tv1
);
544 DUK_ASSERT(h_obj
!= NULL
);
546 DUK_HOBJECT_INCREF(thr
, h_obj
);
548 *((duk_hobject
**) (void *) q
) = h_obj
;
549 q
+= sizeof(duk_hobject
*);
552 DUK_HCOMPILEDFUNCTION_SET_BYTECODE(thr
->heap
, h_fun
, (duk_instr_t
*) (void *) q
);
554 /* The function object is now reachable and refcounts are fine,
555 * so we can pop off all the temporaries.
557 DUK_DDD(DUK_DDDPRINT("function is reachable, reset top; func: %!iT", duk_get_tval(ctx
, idx_base
)));
558 duk_set_top(ctx
, idx_base
+ 1);
560 /* Setup function properties. */
561 tmp32
= DUK_RAW_READ_U32_BE(p
);
562 duk_push_u32(ctx
, tmp32
);
563 duk_xdef_prop_stridx(ctx
, -2, DUK_STRIDX_LENGTH
, DUK_PROPDESC_FLAGS_NONE
);
565 p
= duk__load_string_raw(ctx
, p
);
566 if (DUK_HOBJECT_HAS_NAMEBINDING((duk_hobject
*) h_fun
)) {
567 /* Original function instance/template had NAMEBINDING.
568 * Must create a lexical environment on loading to allow
569 * recursive functions like 'function foo() { foo(); }'.
573 proto
= thr
->builtins
[DUK_BIDX_GLOBAL_ENV
];
574 (void) duk_push_object_helper_proto(ctx
,
575 DUK_HOBJECT_FLAG_EXTENSIBLE
|
576 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV
),
578 duk_dup(ctx
, -2); /* -> [ func funcname env funcname ] */
579 duk_dup(ctx
, idx_base
); /* -> [ func funcname env funcname func ] */
580 duk_xdef_prop(ctx
, -3, DUK_PROPDESC_FLAGS_NONE
); /* -> [ func funcname env ] */
581 duk_xdef_prop_stridx(ctx
, idx_base
, DUK_STRIDX_INT_LEXENV
, DUK_PROPDESC_FLAGS_WC
);
582 /* since closure has NEWENV, never define DUK_STRIDX_INT_VARENV, as it
583 * will be ignored anyway
586 duk_xdef_prop_stridx(ctx
, -2, DUK_STRIDX_NAME
, DUK_PROPDESC_FLAGS_NONE
);
588 p
= duk__load_string_raw(ctx
, p
);
589 duk_xdef_prop_stridx(ctx
, -2, DUK_STRIDX_FILE_NAME
, DUK_PROPDESC_FLAGS_WC
);
591 duk_push_object(ctx
);
593 duk_xdef_prop_stridx(ctx
, -2, DUK_STRIDX_CONSTRUCTOR
, DUK_PROPDESC_FLAGS_WC
); /* func.prototype.constructor = func */
594 duk_compact(ctx
, -1);
595 duk_xdef_prop_stridx(ctx
, -2, DUK_STRIDX_PROTOTYPE
, DUK_PROPDESC_FLAGS_W
);
597 p
= duk__load_buffer_raw(ctx
, p
);
598 duk_xdef_prop_stridx(ctx
, -2, DUK_STRIDX_INT_PC2LINE
, DUK_PROPDESC_FLAGS_WC
);
600 duk_push_object(ctx
); /* _Varmap */
603 p
= duk__load_string_raw(ctx
, p
);
604 if (duk_get_length(ctx
, -1) == 0) {
608 tmp32
= DUK_RAW_READ_U32_BE(p
);
609 duk_push_u32(ctx
, tmp32
);
610 duk_put_prop(ctx
, -3);
612 duk_compact(ctx
, -1);
613 duk_xdef_prop_stridx(ctx
, -2, DUK_STRIDX_INT_VARMAP
, DUK_PROPDESC_FLAGS_NONE
);
615 duk_push_array(ctx
); /* _Formals */
616 for (arr_idx
= 0; ; arr_idx
++) {
618 p
= duk__load_string_raw(ctx
, p
);
619 if (duk_get_length(ctx
, -1) == 0) {
623 duk_put_prop_index(ctx
, -2, arr_idx
);
625 duk_compact(ctx
, -1);
626 duk_xdef_prop_stridx(ctx
, -2, DUK_STRIDX_INT_FORMALS
, DUK_PROPDESC_FLAGS_NONE
);
628 /* Return with final function pushed on stack top. */
629 DUK_DD(DUK_DDPRINT("final loaded function: %!iT", duk_get_tval(ctx
, -1)));
630 DUK_ASSERT_TOP(ctx
, idx_base
+ 1);
637 DUK_EXTERNAL
void duk_dump_function(duk_context
*ctx
) {
639 duk_hcompiledfunction
*func
;
640 duk_bufwriter_ctx bw_ctx_alloc
;
641 duk_bufwriter_ctx
*bw_ctx
= &bw_ctx_alloc
;
644 DUK_ASSERT(ctx
!= NULL
);
645 thr
= (duk_hthread
*) ctx
;
647 /* Bound functions don't have all properties so we'd either need to
648 * lookup the non-bound target function or reject bound functions.
649 * For now, bound functions are rejected.
651 func
= duk_require_hcompiledfunction(ctx
, -1);
652 DUK_ASSERT(func
!= NULL
);
653 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&func
->obj
));
655 /* Estimating the result size beforehand would be costly, so
656 * start with a reasonable size and extend as needed.
658 DUK_BW_INIT_PUSHBUF(thr
, bw_ctx
, DUK__BYTECODE_INITIAL_ALLOC
);
659 p
= DUK_BW_GET_PTR(thr
, bw_ctx
);
660 *p
++ = DUK__SER_MARKER
;
661 *p
++ = DUK__SER_VERSION
;
662 p
= duk__dump_func(ctx
, func
, bw_ctx
, p
);
663 DUK_BW_SET_PTR(thr
, bw_ctx
, p
);
664 DUK_BW_COMPACT(thr
, bw_ctx
);
666 DUK_DD(DUK_DDPRINT("serialized result: %!T", duk_get_tval(ctx
, -1)));
668 duk_remove(ctx
, -2); /* [ ... func buf ] -> [ ... buf ] */
671 DUK_EXTERNAL
void duk_load_function(duk_context
*ctx
) {
673 duk_uint8_t
*p_buf
, *p
, *p_end
;
676 DUK_ASSERT(ctx
!= NULL
);
677 thr
= (duk_hthread
*) ctx
;
680 p_buf
= (duk_uint8_t
*) duk_require_buffer(ctx
, -1, &sz
);
681 DUK_ASSERT(p_buf
!= NULL
);
683 /* The caller is responsible for being sure that bytecode being loaded
684 * is valid and trusted. Invalid bytecode can cause memory unsafe
685 * behavior directly during loading or later during bytecode execution
686 * (instruction validation would be quite complex to implement).
688 * This signature check is the only sanity check for detecting
689 * accidental invalid inputs. The initial 0xFF byte ensures no
690 * ordinary string will be accepted by accident.
694 if (sz
< 2 || p
[0] != DUK__SER_MARKER
|| p
[1] != DUK__SER_VERSION
) {
699 p
= duk__load_func(ctx
, p
, p_end
);
704 duk_remove(ctx
, -2); /* [ ... buf func ] -> [ ... func ] */
708 DUK_ERROR(thr
, DUK_ERR_TYPE_ERROR
, DUK_STR_DECODE_FAILED
);
711 #undef DUK__SER_MARKER
712 #undef DUK__SER_VERSION
713 #undef DUK__SER_STRING
714 #undef DUK__SER_NUMBER
715 #undef DUK__BYTECODE_INITIAL_ALLOC
717 #else /* DUK_USE_BYTECODE_DUMP_SUPPORT */
719 DUK_EXTERNAL
void duk_dump_function(duk_context
*ctx
) {
720 DUK_ERROR((duk_hthread
*) ctx
, DUK_ERR_ERROR
, DUK_STR_UNSUPPORTED
);
723 DUK_EXTERNAL
void duk_load_function(duk_context
*ctx
) {
724 DUK_ERROR((duk_hthread
*) ctx
, DUK_ERR_ERROR
, DUK_STR_UNSUPPORTED
);
727 #endif /* DUK_USE_BYTECODE_DUMP_SUPPORT */