Example #1
0
void duk_debug_dump_hobject(duk_hobject *obj) {
	duk_uint_fast32_t i;
	const char *str_empty = "";
	const char *str_excl = "!";

	DUK_D(DUK_DPRINT("=== hobject %p ===", (void *) obj));
	if (!obj) {
		return;
	}

	DUK_D(DUK_DPRINT("  %sextensible", DUK_HOBJECT_HAS_EXTENSIBLE(obj) ? str_empty : str_excl));
	DUK_D(DUK_DPRINT("  %sconstructable", DUK_HOBJECT_HAS_CONSTRUCTABLE(obj) ? str_empty : str_excl));
	DUK_D(DUK_DPRINT("  %sbound", DUK_HOBJECT_HAS_BOUND(obj) ? str_empty : str_excl));
	DUK_D(DUK_DPRINT("  %scompiledfunction", DUK_HOBJECT_HAS_COMPILEDFUNCTION(obj) ? str_empty : str_excl));
	DUK_D(DUK_DPRINT("  %snativefunction", DUK_HOBJECT_HAS_NATIVEFUNCTION(obj) ? str_empty : str_excl));
	DUK_D(DUK_DPRINT("  %sthread", DUK_HOBJECT_HAS_THREAD(obj) ? str_empty : str_excl));
	DUK_D(DUK_DPRINT("  %sarray_part", DUK_HOBJECT_HAS_ARRAY_PART(obj) ? str_empty : str_excl));
	DUK_D(DUK_DPRINT("  %sstrict", DUK_HOBJECT_HAS_STRICT(obj) ? str_empty : str_excl));
	DUK_D(DUK_DPRINT("  %snewenv", DUK_HOBJECT_HAS_NEWENV(obj) ? str_empty : str_excl));
	DUK_D(DUK_DPRINT("  %snamebinding", DUK_HOBJECT_HAS_NAMEBINDING(obj) ? str_empty : str_excl));
	DUK_D(DUK_DPRINT("  %screateargs", DUK_HOBJECT_HAS_CREATEARGS(obj) ? str_empty : str_excl));
	DUK_D(DUK_DPRINT("  %senvrecclosed", DUK_HOBJECT_HAS_ENVRECCLOSED(obj) ? str_empty : str_excl));
	DUK_D(DUK_DPRINT("  %sexotic_array", DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj) ? str_empty : str_excl));
	DUK_D(DUK_DPRINT("  %sexotic_stringobj", DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(obj) ? str_empty : str_excl));
	DUK_D(DUK_DPRINT("  %sexotic_arguments", DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) ? str_empty : str_excl));
	DUK_D(DUK_DPRINT("  %sexotic_dukfunc", DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(obj) ? str_empty : str_excl));
	DUK_D(DUK_DPRINT("  %sexotic_bufferobj", DUK_HOBJECT_HAS_EXOTIC_BUFFEROBJ(obj) ? str_empty : str_excl));
	DUK_D(DUK_DPRINT("  %sexotic_proxyobj", DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj) ? str_empty : str_excl));

	DUK_D(DUK_DPRINT("  class: number %d -> %s",
	                 (int) DUK_HOBJECT_GET_CLASS_NUMBER(obj),
	                 duk__class_names[(DUK_HOBJECT_GET_CLASS_NUMBER(obj)) & ((1 << DUK_HOBJECT_FLAG_CLASS_BITS) - 1)]));

	DUK_D(DUK_DPRINT("  prototype: %p -> %!O",
	                 (void *) obj->prototype,
	                 (duk_heaphdr *) obj->prototype));

	DUK_D(DUK_DPRINT("  props: p=%p, e_size=%d, e_used=%d, a_size=%d, h_size=%d",
	                 (void *) obj->p,
	                 (int) obj->e_size,
	                 (int) obj->e_used,
	                 (int) obj->a_size,
	                 (int) obj->h_size));

	/*
	 *  Object (struct layout) specific dumping.  Inline code here
	 *  instead of helpers, to ensure debug line prefix is identical.
	 */

	if (DUK_HOBJECT_IS_COMPILEDFUNCTION(obj)) {
		duk_hcompiledfunction *h = (duk_hcompiledfunction *) obj;

		DUK_D(DUK_DPRINT("  hcompiledfunction"));
		DUK_D(DUK_DPRINT("  data: %!O", h->data));
		DUK_D(DUK_DPRINT("  nregs: %d", (int) h->nregs));
		DUK_D(DUK_DPRINT("  nargs: %d", (int) h->nargs));

		if (h->data && DUK_HBUFFER_HAS_DYNAMIC(h->data) && DUK_HBUFFER_GET_DATA_PTR(h->data)) {
			DUK_D(DUK_DPRINT("  consts: %p (%d, %d bytes)",
			                 (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(h),
			                 (int) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(h),
			                 (int) DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE(h)));
			DUK_D(DUK_DPRINT("  funcs: %p (%d, %d bytes)",
			                 (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(h),
			                 (int) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(h),
			                 (int) DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE(h)));
			DUK_D(DUK_DPRINT("  bytecode: %p (%d, %d bytes)",
			                 (void *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(h),
			                 (int) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(h),
			                 (int) DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(h)));
		} else {
			DUK_D(DUK_DPRINT("  consts: ???"));
			DUK_D(DUK_DPRINT("  funcs: ???"));
			DUK_D(DUK_DPRINT("  bytecode: ???"));
		}
	} else if (DUK_HOBJECT_IS_NATIVEFUNCTION(obj)) {
		duk_hnativefunction *h = (duk_hnativefunction *) obj;

		DUK_D(DUK_DPRINT("  hnativefunction"));
		/* XXX: h->func, cannot print function pointers portably */
		DUK_D(DUK_DPRINT("  nargs: %d", (int) h->nargs));
	} else if (DUK_HOBJECT_IS_THREAD(obj)) {
		duk_hthread *thr = (duk_hthread *) obj;
		duk_tval *p;

		DUK_D(DUK_DPRINT("  hthread"));
		DUK_D(DUK_DPRINT("  strict: %d", (int) thr->strict));
		DUK_D(DUK_DPRINT("  state: %d", (int) thr->state));

		DUK_D(DUK_DPRINT("  valstack_max: %d, callstack_max:%d, catchstack_max: %d",
		                 thr->valstack_max, thr->callstack_max, thr->catchstack_max));

		DUK_D(DUK_DPRINT("  callstack: ptr %p, size %d, top %d, preventcount %d, used size %d entries (%d bytes), alloc size %d entries (%d bytes)",
		                 (void *) thr->callstack,
		                 thr->callstack_size,
		                 thr->callstack_top,
		                 thr->callstack_preventcount,
		                 thr->callstack_top,
		                 thr->callstack_top * sizeof(duk_activation),
		                 thr->callstack_size,
		                 thr->callstack_size * sizeof(duk_activation)));

		DUK_DEBUG_SUMMARY_INIT();
		DUK_DEBUG_SUMMARY_CHAR('[');
		for (i = 0; i <= thr->callstack_size; i++) {
			if (i == thr->callstack_top) {
				DUK_DEBUG_SUMMARY_CHAR('|');
			}
			if (!thr->callstack) {
				DUK_DEBUG_SUMMARY_CHAR('@');
			} else if (i < thr->callstack_size) {
				if (i < thr->callstack_top) {
					/* tailcalling is nice to see immediately; other flags (e.g. strict)
					 * not that important.
					 */
					if (thr->callstack[i].flags & DUK_ACT_FLAG_TAILCALLED) {
						DUK_DEBUG_SUMMARY_CHAR('/');
					}
					DUK_DEBUG_SUMMARY_CHAR(duk__get_act_summary_char(&thr->callstack[i]));
				} else {
					DUK_DEBUG_SUMMARY_CHAR('.');
				}
			}
		}
		DUK_DEBUG_SUMMARY_CHAR(']');
		DUK_DEBUG_SUMMARY_FINISH();

		DUK_D(DUK_DPRINT("  valstack: ptr %p, end %p (%d), bottom %p (%d), top %p (%d), used size %d entries (%d bytes), alloc size %d entries (%d bytes)",
		                 (void *) thr->valstack,
		                 (void *) thr->valstack_end,
		                 (int) (thr->valstack_end - thr->valstack),
		                 (void *) thr->valstack_bottom,
		                 (int) (thr->valstack_bottom - thr->valstack),
		                 (void *) thr->valstack_top,
		                 (int) (thr->valstack_top - thr->valstack),
		                 (int) (thr->valstack_top - thr->valstack),
		                 (int) (thr->valstack_top - thr->valstack) * sizeof(duk_tval),
		                 (int) (thr->valstack_end - thr->valstack),
		                 (int) (thr->valstack_end - thr->valstack) * sizeof(duk_tval)));

		DUK_DEBUG_SUMMARY_INIT();
		DUK_DEBUG_SUMMARY_CHAR('[');
		p = thr->valstack;
		while (p <= thr->valstack_end) {
			i = (duk_uint_fast32_t) (p - thr->valstack);
			if (thr->callstack &&
			    thr->callstack_top > 0 &&
			    i == (duk_size_t) (thr->callstack + thr->callstack_top - 1)->idx_bottom) {
				DUK_DEBUG_SUMMARY_CHAR('>');
			}
			if (p == thr->valstack_top) {
				DUK_DEBUG_SUMMARY_CHAR('|');
			}
			if (p < thr->valstack_end) {
				if (p < thr->valstack_top) {
					DUK_DEBUG_SUMMARY_CHAR(duk__get_tval_summary_char(p));
				} else {
					/* XXX: safe printer for these?  would be nice, because
					 * we could visualize whether the values are in proper
					 * state.
					 */
					DUK_DEBUG_SUMMARY_CHAR('.');
				}
			}
			p++;
		}
		DUK_DEBUG_SUMMARY_CHAR(']');
		DUK_DEBUG_SUMMARY_FINISH();

		DUK_D(DUK_DPRINT("  catchstack: ptr %p, size %d, top %d, used size %d entries (%d bytes), alloc size %d entries (%d bytes)",
		                 (void *) thr->catchstack,
		                 thr->catchstack_size,
		                 thr->catchstack_top,
		                 thr->catchstack_top,
		                 thr->catchstack_top * sizeof(duk_catcher),
		                 thr->catchstack_size,
		                 thr->catchstack_size * sizeof(duk_catcher)));

		DUK_DEBUG_SUMMARY_INIT();
		DUK_DEBUG_SUMMARY_CHAR('[');
		for (i = 0; i <= thr->catchstack_size; i++) {
			if (i == thr->catchstack_top) {
				DUK_DEBUG_SUMMARY_CHAR('|');
			}
			if (!thr->catchstack) {
				DUK_DEBUG_SUMMARY_CHAR('@');
			} else if (i < thr->catchstack_size) {
				if (i < thr->catchstack_top) {
					DUK_DEBUG_SUMMARY_CHAR(duk__get_cat_summary_char(&thr->catchstack[i]));
				} else {
					DUK_DEBUG_SUMMARY_CHAR('.');
				}
			}
		}
		DUK_DEBUG_SUMMARY_CHAR(']');
		DUK_DEBUG_SUMMARY_FINISH();

		DUK_D(DUK_DPRINT("  resumer: ptr %p",
		                 (void *) thr->resumer));

#if 0  /* worth dumping? */
		for (i = 0; i < DUK_NUM_BUILTINS; i++) {
			DUK_D(DUK_DPRINT("  builtins[%d] -> %!@O", i, thr->builtins[i]));
		}
#endif
	}

	if (obj->p) {
		DUK_D(DUK_DPRINT("  props alloc size: %d",
		                 (int) DUK_HOBJECT_P_COMPUTE_SIZE(obj->e_size, obj->a_size, obj->h_size)));
	} else {
		DUK_D(DUK_DPRINT("  props alloc size: n/a"));
	}

	DUK_D(DUK_DPRINT("  prop entries:"));
	for (i = 0; i < obj->e_size; i++) {
		duk_hstring *k;
		duk_propvalue *v;

		k = DUK_HOBJECT_E_GET_KEY(obj, i);
		v = DUK_HOBJECT_E_GET_VALUE_PTR(obj, i);

		if (i >= obj->e_used) {
			DUK_D(DUK_DPRINT("    [%d]: UNUSED", i));
			continue;
		}

		if (!k) {
			DUK_D(DUK_DPRINT("    [%d]: NULL", i));
			continue;
		}

		if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(obj, i)) {
			DUK_D(DUK_DPRINT("    [%d]: [w=%d e=%d c=%d a=%d] %!O -> get:%p set:%p; get %!O; set %!O",
			                 i,
			                 DUK_HOBJECT_E_SLOT_IS_WRITABLE(obj, i),
			                 DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(obj, i),
			                 DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(obj, i),
			                 DUK_HOBJECT_E_SLOT_IS_ACCESSOR(obj, i),
			                 k,
			                 (void *) v->a.get,
			                 (void *) v->a.set,
			                 (duk_heaphdr *) v->a.get,
			                 (duk_heaphdr *) v->a.set));
		} else {
			DUK_D(DUK_DPRINT("    [%d]: [w=%d e=%d c=%d a=%d] %!O -> %!T",
			                 i,
			                 DUK_HOBJECT_E_SLOT_IS_WRITABLE(obj, i),
			                 DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(obj, i),
			                 DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(obj, i),
			                 DUK_HOBJECT_E_SLOT_IS_ACCESSOR(obj, i),
			                 k,
			                 &v->v));
		}
	}

	DUK_D(DUK_DPRINT("  array entries:"));
	for (i = 0; i < obj->a_size; i++) {
		DUK_D(DUK_DPRINT("    [%d]: [w=%d e=%d c=%d a=%d] %d -> %!T",
		                 i,
		                 1,  /* implicit attributes */
		                 1,
		                 1,
		                 0,
		                 i,
		                 DUK_HOBJECT_A_GET_VALUE_PTR(obj, i)));
	}

	DUK_D(DUK_DPRINT("  hash entries:"));
	for (i = 0; i < obj->h_size; i++) {
		duk_uint32_t t = DUK_HOBJECT_H_GET_INDEX(obj, i);
		if (t == DUK_HOBJECT_HASHIDX_UNUSED) {
			DUK_D(DUK_DPRINT("    [%d]: unused", i));
		} else if (t == DUK_HOBJECT_HASHIDX_DELETED) {
			DUK_D(DUK_DPRINT("    [%d]: deleted", i));
		} else {
			DUK_D(DUK_DPRINT("    [%d]: %d",
			                 i,
			                 (int) t));
		}
	}
}
Example #2
0
static void duk__refcount_finalize_hobject(duk_hthread *thr, duk_hobject *h) {
	duk_uint_fast32_t i;

	DUK_ASSERT(h);
	DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h) == DUK_HTYPE_OBJECT);

	/* XXX: better to get base and walk forwards? */

	for (i = 0; i < (duk_uint_fast32_t) h->e_next; i++) {
		duk_hstring *key = DUK_HOBJECT_E_GET_KEY(h, i);
		if (!key) {
			continue;
		}
		duk_heap_heaphdr_decref(thr, (duk_heaphdr *) key);
		if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(h, i)) {
			duk_heap_heaphdr_decref(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_GETTER(h, i));
			duk_heap_heaphdr_decref(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_SETTER(h, i));
		} else {
			duk_heap_tval_decref(thr, DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(h, i));
		}
	}

	for (i = 0; i < (duk_uint_fast32_t) h->a_size; i++) {
		duk_heap_tval_decref(thr, DUK_HOBJECT_A_GET_VALUE_PTR(h, i));
	}

	/* hash part is a 'weak reference' and does not contribute */

	duk_heap_heaphdr_decref(thr, (duk_heaphdr *) h->prototype);

	if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
		duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
		duk_tval *tv, *tv_end;
		duk_hobject **funcs, **funcs_end;

		DUK_ASSERT(f->data != NULL);  /* compiled functions must be created 'atomically' */

		tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(f);
		tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(f);
		while (tv < tv_end) {
			duk_heap_tval_decref(thr, tv);
			tv++;
		}

		funcs = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(f);
		funcs_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(f);
		while (funcs < funcs_end) {
			duk_heap_heaphdr_decref(thr, (duk_heaphdr *) *funcs);
			funcs++;
		}

		duk_heap_heaphdr_decref(thr, (duk_heaphdr *) f->data);
	} else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
		duk_hnativefunction *f = (duk_hnativefunction *) h;
		DUK_UNREF(f);
		/* nothing to finalize */
	} else if (DUK_HOBJECT_IS_THREAD(h)) {
		duk_hthread *t = (duk_hthread *) h;
		duk_tval *tv;

		tv = t->valstack;
		while (tv < t->valstack_end) {
			duk_heap_tval_decref(thr, tv);
			tv++;
		}

		for (i = 0; i < (duk_uint_fast32_t) t->callstack_top; i++) {
			duk_activation *act = t->callstack + i;
			duk_heap_heaphdr_decref(thr, (duk_heaphdr *) act->func);
			duk_heap_heaphdr_decref(thr, (duk_heaphdr *) act->var_env);
			duk_heap_heaphdr_decref(thr, (duk_heaphdr *) act->lex_env);
#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
			duk_heap_heaphdr_decref(thr, (duk_heaphdr *) act->prev_caller);
#endif
		}

#if 0  /* nothing now */
		for (i = 0; i < (duk_uint_fast32_t) t->catchstack_top; i++) {
			duk_catcher *cat = t->catchstack + i;
		}
#endif

		for (i = 0; i < DUK_NUM_BUILTINS; i++) {
			duk_heap_heaphdr_decref(thr, (duk_heaphdr *) t->builtins[i]);
		}

		duk_heap_heaphdr_decref(thr, (duk_heaphdr *) t->resumer);
	}
}
DUK_LOCAL void duk__mark_hobject(duk_heap *heap, duk_hobject *h) {
	duk_uint_fast32_t i;

	DUK_DDD(DUK_DDDPRINT("duk__mark_hobject: %p", (void *) h));

	DUK_ASSERT(h);

	/* XXX: use advancing pointers instead of index macros -> faster and smaller? */

	for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
		duk_hstring *key = DUK_HOBJECT_E_GET_KEY(heap, h, i);
		if (!key) {
			continue;
		}
		duk__mark_heaphdr(heap, (duk_heaphdr *) key);
		if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)) {
			duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.get);
			duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.set);
		} else {
			duk__mark_tval(heap, &DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->v);
		}
	}

	for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
		duk__mark_tval(heap, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i));
	}

	/* hash part is a 'weak reference' and does not contribute */

	duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h));

	if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
		duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
		duk_tval *tv, *tv_end;
		duk_hobject **fn, **fn_end;

		/* 'data' is reachable through every compiled function which
		 * contains a reference.
		 */

		duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPILEDFUNCTION_GET_DATA(heap, f));

		tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(heap, f);
		tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(heap, f);
		while (tv < tv_end) {
			duk__mark_tval(heap, tv);
			tv++;
		}

		fn = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(heap, f);
		fn_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(heap, f);
		while (fn < fn_end) {
			duk__mark_heaphdr(heap, (duk_heaphdr *) *fn);
			fn++;
		}
	} else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
		duk_hnativefunction *f = (duk_hnativefunction *) h;
		DUK_UNREF(f);
		/* nothing to mark */
	} else if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
		duk_hbufferobject *b = (duk_hbufferobject *) h;
		duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf);
	} else if (DUK_HOBJECT_IS_THREAD(h)) {
		duk_hthread *t = (duk_hthread *) h;
		duk_tval *tv;

		tv = t->valstack;
		while (tv < t->valstack_top) {
			duk__mark_tval(heap, tv);
			tv++;
		}

		for (i = 0; i < (duk_uint_fast32_t) t->callstack_top; i++) {
			duk_activation *act = t->callstack + i;
			duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_ACT_GET_FUNC(act));
			duk__mark_heaphdr(heap, (duk_heaphdr *) act->var_env);
			duk__mark_heaphdr(heap, (duk_heaphdr *) act->lex_env);
#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
			duk__mark_heaphdr(heap, (duk_heaphdr *) act->prev_caller);
#endif
		}

#if 0  /* nothing now */
		for (i = 0; i < (duk_uint_fast32_t) t->catchstack_top; i++) {
			duk_catcher *cat = t->catchstack + i;
		}
#endif

		duk__mark_heaphdr(heap, (duk_heaphdr *) t->resumer);

		/* XXX: duk_small_uint_t would be enough for this loop */
		for (i = 0; i < DUK_NUM_BUILTINS; i++) {
			duk__mark_heaphdr(heap, (duk_heaphdr *) t->builtins[i]);
		}
	}
}
Example #4
0
static void duk__mark_hobject(duk_heap *heap, duk_hobject *h) {
	duk_uint_fast32_t i;

	DUK_DDD(DUK_DDDPRINT("duk__mark_hobject: %p", (void *) h));

	DUK_ASSERT(h);

	/* XXX: use advancing pointers instead of index macros -> faster and smaller? */

	for (i = 0; i < h->e_used; i++) {
		duk_hstring *key = DUK_HOBJECT_E_GET_KEY(h, i);
		if (!key) {
			continue;
		}
		duk__mark_heaphdr(heap, (duk_heaphdr *) key);
		if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(h, i)) {
			duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(h, i)->a.get);
			duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(h, i)->a.set);
		} else {
			duk__mark_tval(heap, &DUK_HOBJECT_E_GET_VALUE_PTR(h, i)->v);
		}
	}

	for (i = 0; i < h->a_size; i++) {
		duk__mark_tval(heap, DUK_HOBJECT_A_GET_VALUE_PTR(h, i));
	}

	/* hash part is a 'weak reference' and does not contribute */

	duk__mark_heaphdr(heap, (duk_heaphdr *) h->prototype);

	if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
		duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
		duk_tval *tv, *tv_end;
		duk_hobject **funcs, **funcs_end;

		/* 'data' is reachable through every compiled function which
		 * contains a reference.
		 */

		duk__mark_heaphdr(heap, (duk_heaphdr *) f->data);

		tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(f);
		tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(f);
		while (tv < tv_end) {
			duk__mark_tval(heap, tv);
			tv++;
		}

		funcs = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(f);
		funcs_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(f);
		while (funcs < funcs_end) {
			duk__mark_heaphdr(heap, (duk_heaphdr *) *funcs);
			funcs++;
		}
	} else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
		duk_hnativefunction *f = (duk_hnativefunction *) h;
		DUK_UNREF(f);
		/* nothing to mark */
	} else if (DUK_HOBJECT_IS_THREAD(h)) {
		duk_hthread *t = (duk_hthread *) h;
		duk_tval *tv;

		tv = t->valstack;
		while (tv < t->valstack_end) {
			duk__mark_tval(heap, tv);
			tv++;
		}

		for (i = 0; i < t->callstack_top; i++) {
			duk_activation *act = &t->callstack[i];
			duk__mark_heaphdr(heap, (duk_heaphdr *) act->func);
			duk__mark_heaphdr(heap, (duk_heaphdr *) act->var_env);
			duk__mark_heaphdr(heap, (duk_heaphdr *) act->lex_env);
#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
			duk__mark_heaphdr(heap, (duk_heaphdr *) act->prev_caller);
#endif
		}

#if 0  /* nothing now */
		for (i = 0; i < t->catchstack_top; i++) {
			duk_catcher *cat = &t->catchstack[i];
		}
#endif

		duk__mark_heaphdr(heap, (duk_heaphdr *) t->resumer);

		for (i = 0; i < DUK_NUM_BUILTINS; i++) {
			duk__mark_heaphdr(heap, (duk_heaphdr *) t->builtins[i]);
		}
	}
}
Example #5
0
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;
}