Exemplo n.º 1
0
duk_ret_t duk_bi_duktape_object_act(duk_context *ctx) {
	duk_hthread *thr = (duk_hthread *) ctx;
	duk_activation *act;
	duk_hobject *h_func;
	duk_uint_fast32_t pc;
	duk_uint_fast32_t line;
	duk_int_t level;

	/* -1             = top callstack entry, callstack[callstack_top - 1]
	 * -callstack_top = bottom callstack entry, callstack[0]
	 */
	level = duk_to_int(ctx, 0);
	if (level >= 0 || -level > (duk_int_t) thr->callstack_top) {
		return 0;
	}
	DUK_ASSERT(level >= -((duk_int_t) thr->callstack_top) && level <= -1);
	act = thr->callstack + thr->callstack_top + level;

	duk_push_object(ctx);

	h_func = act->func;
	DUK_ASSERT(h_func != NULL);
	duk_push_hobject(ctx, h_func);

	pc = (duk_uint_fast32_t) act->pc;
	duk_push_int(ctx, (int) pc);  /* FIXME: typing */

	line = duk_hobject_pc2line_query(ctx, -2, pc);
	duk_push_int(ctx, (int) line);  /* FIXME: typing */

	/* Providing access to e.g. act->lex_env would be dangerous: these
	 * internal structures must never be accessible to the application.
	 * Duktape relies on them having consistent data, and this consistency
	 * is only asserted for, not checked for.
	 */

	/* [ level obj func pc line ] */

	/* FIXME: version specific array format instead? */
	duk_def_prop_stridx_wec(ctx, -4, DUK_STRIDX_LINE_NUMBER);
	duk_def_prop_stridx_wec(ctx, -3, DUK_STRIDX_PC);
	duk_def_prop_stridx_wec(ctx, -2, DUK_STRIDX_LC_FUNCTION);
	return 1;
}
Exemplo n.º 2
0
static void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack, const char *filename, duk_int_t line, duk_bool_t noblame_fileline) {
	duk_context *ctx = (duk_context *) thr;
	duk_small_uint_t depth;
	duk_int_t i, i_min;
	duk_uarridx_t arr_idx;
	duk_double_t d;

	DUK_ASSERT(thr != NULL);
	DUK_ASSERT(thr_callstack != NULL);
	DUK_ASSERT(ctx != NULL);

	/* [ ... error ] */

	/*
	 *  The traceback format is pretty arcane in an attempt to keep it compact
	 *  and cheap to create.  It may change arbitrarily from version to version.
	 *  It should be decoded/accessed through version specific accessors only.
	 *
	 *  See doc/error-objects.txt.
	 */

	DUK_DDD(DUK_DDDPRINT("adding traceback to object: %!T",
	                     (duk_tval *) duk_get_tval(ctx, -1)));

	duk_push_array(ctx);  /* XXX: specify array size, as we know it */
	arr_idx = 0;

	/* filename/line from C macros (__FILE__, __LINE__) are added as an
	 * entry with a special format: (string, number).  The number contains
	 * the line and flags.
	 */

	/* XXX: optimize: allocate an array part to the necessary size (upwards
	 * estimate) and fill in the values directly into the array part; finally
	 * update 'length'.
	 */

	/* XXX: using duk_put_prop_index() would cause obscure error cases when Array.prototype
	 * has write-protected array index named properties.  This was seen as DoubleErrors
	 * in e.g. some test262 test cases.  Using duk_def_prop_index() is better but heavier.
	 * The best fix is to fill in the tracedata directly into the array part.
	 */

	/* [ ... error arr ] */

	if (filename) {
		duk_push_string(ctx, filename);
		duk_def_prop_index_wec(ctx, -2, arr_idx);
		arr_idx++;

		d = (noblame_fileline ? ((duk_double_t) DUK_TB_FLAG_NOBLAME_FILELINE) * DUK_DOUBLE_2TO32 : 0.0) +
		    (duk_double_t) line;
		duk_push_number(ctx, d);
		duk_def_prop_index_wec(ctx, -2, arr_idx);
		arr_idx++;
	}

	/* traceback depth doesn't take into account the filename/line
	 * special handling above (intentional)
	 */
	depth = DUK_USE_TRACEBACK_DEPTH;
	i_min = (thr_callstack->callstack_top > (duk_size_t) depth ? (duk_int_t) (thr_callstack->callstack_top - depth) : 0);
	DUK_ASSERT(i_min >= 0);

	/* [ ... error arr ] */

	DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX);  /* callstack limits */
	for (i = (duk_int_t) (thr_callstack->callstack_top - 1); i >= i_min; i--) {
		duk_uint32_t pc;

		/*
		 *  Note: each API operation potentially resizes the callstack,
		 *  so be careful to re-lookup after every operation.  Currently
		 *  these is no issue because we don't store a temporary 'act'
		 *  pointer at all.  (This would be a non-issue if we operated
		 *  directly on the array part.)
		 */

		/* [... arr] */

		DUK_ASSERT(thr_callstack->callstack[i].func != NULL);
		DUK_ASSERT_DISABLE(thr_callstack->callstack[i].pc >= 0);  /* unsigned */

		/* add function */
		duk_push_hobject(ctx, thr_callstack->callstack[i].func);  /* -> [... arr func] */
		duk_def_prop_index_wec(ctx, -2, arr_idx);
		arr_idx++;

		/* add a number containing: pc, activation flags */

		/* Add a number containing: pc, activation flag
		 *
		 * PC points to next instruction, find offending PC.  Note that
		 * PC == 0 for native code.
		 */
		pc = thr_callstack->callstack[i].pc;
		if (pc > 0) {
			pc--;
		}
		DUK_ASSERT_DISABLE(pc >= 0);  /* unsigned */
		DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32);  /* assume PC is at most 32 bits and non-negative */
		d = ((duk_double_t) thr_callstack->callstack[i].flags) * DUK_DOUBLE_2TO32 + (duk_double_t) pc;
		duk_push_number(ctx, d);  /* -> [... arr num] */
		duk_def_prop_index_wec(ctx, -2, arr_idx);
		arr_idx++;
	}

	/* XXX: set with duk_hobject_set_length() when tracedata is filled directly */
	duk_push_uint(ctx, (duk_uint_t) arr_idx);
	duk_def_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_WC);

	/* [ ... error arr ] */

	duk_def_prop_stridx_wec(ctx, -2, DUK_STRIDX_TRACEDATA);  /* -> [ ... error ] */
}