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) { duk_tval *tv; tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx)); if (tv != NULL && DUK_TVAL_IS_BUFFER(tv)) { duk_hbuffer *h_buf; h_buf = DUK_TVAL_GET_BUFFER(tv); DUK_ASSERT(h_buf != NULL); DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HBUFFER_GET_SIZE(h_buf), p); p = duk__dump_hbuffer_raw(thr, p, h_buf); } else { p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p); DUK_RAW_WRITE_U32_BE(p, 0); } return p; }
DUK_LOCAL duk_uint8_t *duk__dump_varmap(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func) { duk_tval *tv; tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_STRING_INT_VARMAP(thr)); if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) { duk_hobject *h; duk_uint_fast32_t i; h = DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(h != NULL); /* We know _Varmap only has own properties so walk property * table directly. We also know _Varmap is dense and all * values are numbers; assert for these. GC and finalizers * shouldn't affect _Varmap so side effects should be fine. */ for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) { duk_hstring *key; duk_tval *tv_val; duk_uint32_t val; key = DUK_HOBJECT_E_GET_KEY(thr->heap, h, i); DUK_ASSERT(key != NULL); /* _Varmap is dense */ DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h, i)); tv_val = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h, i); DUK_ASSERT(tv_val != NULL); DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_val)); /* known to be number; in fact an integer */ #if defined(DUK_USE_FASTINT) DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv_val)); DUK_ASSERT(DUK_TVAL_GET_FASTINT(tv_val) == (duk_int64_t) DUK_TVAL_GET_FASTINT_U32(tv_val)); /* known to be 32-bit */ val = DUK_TVAL_GET_FASTINT_U32(tv_val); #else val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv_val); #endif DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(key) + 4, p); p = duk__dump_hstring_raw(p, key); DUK_RAW_WRITE_U32_BE(p, val); } } p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p); DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Varmap */ return p; }
DUK_LOCAL duk_uint8_t *duk__dump_formals(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func) { duk_tval *tv; 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)) { duk_hobject *h; duk_uint_fast32_t i; h = DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(h != NULL); /* We know _Formals is dense and all entries will be in the * array part. GC and finalizers shouldn't affect _Formals * so side effects should be fine. */ for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) { duk_tval *tv_val; duk_hstring *varname; tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, h, i); DUK_ASSERT(tv_val != NULL); if (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); DUK_ASSERT(varname != NULL); 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__dump_hstring_raw(p, varname); } } } p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p); DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Formals */ return p; }
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) { duk_tval *tv; duk_uint32_t val; tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx)); if (tv != NULL && DUK_TVAL_IS_NUMBER(tv)) { val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv); } else { val = def_value; } p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p); DUK_RAW_WRITE_U32_BE(p, val); return p; }
DUK_LOCAL void duk__create_escaped_source(duk_hthread *thr, int idx_pattern) { duk_context *ctx = (duk_context *) thr; duk_hstring *h; const duk_uint8_t *p; duk_bufwriter_ctx bw_alloc; duk_bufwriter_ctx *bw; duk_uint8_t *q; duk_size_t i, n; duk_uint_fast8_t c_prev, c; h = duk_get_hstring(ctx, idx_pattern); DUK_ASSERT(h != NULL); p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h); n = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h); if (n == 0) { /* return '(?:)' */ duk_push_hstring_stridx(ctx, DUK_STRIDX_ESCAPED_EMPTY_REGEXP); return; } bw = &bw_alloc; DUK_BW_INIT_PUSHBUF(thr, bw, n); q = DUK_BW_GET_PTR(thr, bw); c_prev = (duk_uint_fast8_t) 0; for (i = 0; i < n; i++) { c = p[i]; q = DUK_BW_ENSURE_RAW(thr, bw, 2, q); if (c == (duk_uint_fast8_t) '/' && c_prev != (duk_uint_fast8_t) '\\') { /* Unescaped '/' ANYWHERE in the regexp (in disjunction, * inside a character class, ...) => same escape works. */ *q++ = DUK_ASC_BACKSLASH; } *q++ = (duk_uint8_t) c; c_prev = c; } DUK_BW_SETPTR_AND_COMPACT(thr, bw, q); duk_to_string(ctx, -1); /* -> [ ... escaped_source ] */ }
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) { duk_hstring *h_str; duk_tval *tv; tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx)); if (tv != NULL && DUK_TVAL_IS_STRING(tv)) { h_str = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h_str != NULL); } else { h_str = DUK_HTHREAD_STRING_EMPTY_STRING(thr); DUK_ASSERT(h_str != NULL); } DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(h_str), p); p = duk__dump_hstring_raw(p, h_str); return p; }
static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func, duk_bufwriter_ctx *bw_ctx, duk_uint8_t *p) { duk_hthread *thr; duk_tval *tv, *tv_end; duk_instr_t *ins, *ins_end; duk_hobject **fn, **fn_end; duk_hstring *h_str; duk_uint32_t count_instr; duk_uint32_t tmp32; duk_uint16_t tmp16; duk_double_t d; thr = (duk_hthread *) ctx; DUK_UNREF(ctx); DUK_UNREF(thr); DUK_DD(DUK_DDPRINT("dumping function %p to %p: " "consts=[%p,%p[ (%ld bytes, %ld items), " "funcs=[%p,%p[ (%ld bytes, %ld items), " "code=[%p,%p[ (%ld bytes, %ld items)", (void *) func, (void *) p, (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, func), (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, func), (long) DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE(thr->heap, func), (long) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(thr->heap, func), (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, func), (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, func), (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE(thr->heap, func), (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, func), (void *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, func), (void *) DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, func), (long) DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(thr->heap, func), (long) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(thr->heap, func))); DUK_ASSERT(DUK_USE_ESBC_MAX_BYTES <= 0x7fffffffUL); /* ensures no overflow */ count_instr = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(thr->heap, func); p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 3 * 4 + 2 * 2 + 3 * 4 + count_instr * 4, p); /* Fixed header info. */ tmp32 = count_instr; DUK_RAW_WRITE_U32_BE(p, tmp32); tmp32 = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(thr->heap, func); DUK_RAW_WRITE_U32_BE(p, tmp32); tmp32 = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, func); DUK_RAW_WRITE_U32_BE(p, tmp32); tmp16 = func->nregs; DUK_RAW_WRITE_U16_BE(p, tmp16); tmp16 = func->nargs; DUK_RAW_WRITE_U16_BE(p, tmp16); #if defined(DUK_USE_DEBUGGER_SUPPORT) tmp32 = func->start_line; DUK_RAW_WRITE_U32_BE(p, tmp32); tmp32 = func->end_line; DUK_RAW_WRITE_U32_BE(p, tmp32); #else DUK_RAW_WRITE_U32_BE(p, 0); DUK_RAW_WRITE_U32_BE(p, 0); #endif tmp32 = ((duk_heaphdr *) func)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK; DUK_RAW_WRITE_U32_BE(p, tmp32); /* Bytecode instructions: endian conversion needed unless * platform is big endian. */ ins = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, func); ins_end = DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, func); DUK_ASSERT((duk_size_t) (ins_end - ins) == (duk_size_t) count_instr); #if defined(DUK_USE_INTEGER_BE) DUK_MEMCPY((void *) p, (const void *) ins, (size_t) (ins_end - ins)); p += (size_t) (ins_end - ins); #else while (ins != ins_end) { tmp32 = (duk_uint32_t) (*ins); DUK_RAW_WRITE_U32_BE(p, tmp32); ins++; } #endif /* Constants: variable size encoding. */ tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, func); tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, func); while (tv != tv_end) { /* constants are strings or numbers now */ DUK_ASSERT(DUK_TVAL_IS_STRING(tv) || DUK_TVAL_IS_NUMBER(tv)); if (DUK_TVAL_IS_STRING(tv)) { h_str = DUK_TVAL_GET_STRING(tv); DUK_ASSERT(h_str != NULL); DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */ p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1 + 4 + DUK_HSTRING_GET_BYTELEN(h_str), p), *p++ = DUK__SER_STRING; p = duk__dump_hstring_raw(p, h_str); } else { DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1 + 8, p); *p++ = DUK__SER_NUMBER; d = DUK_TVAL_GET_NUMBER(tv); DUK_RAW_WRITE_DOUBLE_BE(p, d); } tv++; } /* Inner functions recursively. */ fn = (duk_hobject **) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, func); fn_end = (duk_hobject **) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, func); while (fn != fn_end) { /* XXX: This causes recursion up to inner function depth * which is normally not an issue, e.g. mark-and-sweep uses * a recursion limiter to avoid C stack issues. Avoiding * this would mean some sort of a work list or just refusing * to serialize deep functions. */ DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(*fn)); p = duk__dump_func(ctx, (duk_hcompiledfunction *) *fn, bw_ctx, p); fn++; } /* Object extra properties. * * There are some difference between function templates and functions. * For example, function templates don't have .length and nargs is * normally used to instantiate the functions. */ p = duk__dump_uint32_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_LENGTH, (duk_uint32_t) func->nargs); p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_NAME); p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_FILE_NAME); p = duk__dump_buffer_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_INT_PC2LINE); p = duk__dump_varmap(thr, p, bw_ctx, (duk_hobject *) func); p = duk__dump_formals(thr, p, bw_ctx, (duk_hobject *) func); DUK_DD(DUK_DDPRINT("serialized function %p -> final pointer %p", (void *) func, (void *) p)); return p; }