Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t output_type) {
	duk_hthread *thr = (duk_hthread *) ctx;
	duk_idx_t idx_td;
	duk_small_int_t i;  /* traceback depth fits into 16 bits */
	duk_small_int_t t;  /* stack type fits into 16 bits */
	duk_small_int_t count_func = 0;  /* traceback depth ensures fits into 16 bits */
	const char *str_tailcall = " tailcall";
	const char *str_strict = " strict";
	const char *str_construct = " construct";
	const char *str_prevyield = " preventsyield";
	const char *str_directeval = " directeval";
	const char *str_empty = "";

	DUK_ASSERT_TOP(ctx, 0);  /* fixed arg count */
	DUK_UNREF(thr);

	duk_push_this(ctx);
	duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TRACEDATA);
	idx_td = duk_get_top_index(ctx);

	duk_push_hstring_stridx(ctx, DUK_STRIDX_NEWLINE_4SPACE);
	duk_push_this(ctx);

	/* [ ... this tracedata sep this ] */

	/* XXX: skip null filename? */

	if (duk_check_type(ctx, idx_td, DUK_TYPE_OBJECT)) {
		/* Current tracedata contains 2 entries per callstack entry. */
		for (i = 0; ; i += 2) {
			duk_int_t pc;
			duk_int_t line;
			duk_int_t flags;
			duk_double_t d;
			const char *funcname;
			const char *filename;
			duk_hobject *h_func;
			duk_hstring *h_name;

			duk_require_stack(ctx, 5);
			duk_get_prop_index(ctx, idx_td, i);
			duk_get_prop_index(ctx, idx_td, i + 1);
			d = duk_to_number(ctx, -1);
			pc = (duk_int_t) DUK_FMOD(d, DUK_DOUBLE_2TO32);
			flags = (duk_int_t) DUK_FLOOR(d / DUK_DOUBLE_2TO32);
			t = (duk_small_int_t) duk_get_type(ctx, -2);

			if (t == DUK_TYPE_OBJECT || t == DUK_TYPE_LIGHTFUNC) {
				/*
				 *  Ecmascript/native function call or lightfunc call
				 */

				count_func++;

				/* [ ... v1(func) v2(pc+flags) ] */

				h_func = duk_get_hobject(ctx, -2);  /* NULL for lightfunc */

				duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
				duk_get_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME);

#if defined(DUK_USE_PC2LINE)
				line = duk_hobject_pc2line_query(ctx, -4, (duk_uint_fast32_t) pc);
#else
				line = 0;
#endif

				/* [ ... v1 v2 name filename ] */

				/* When looking for .fileName/.lineNumber, blame first
				 * function which has a .fileName.
				 */
				if (duk_is_string(ctx, -1)) {
					if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
						return 1;
					} else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
						duk_push_int(ctx, line);
						return 1;
					}
				}

				/* XXX: Change 'anon' handling here too, to use empty string for anonymous functions? */
				/* XXX: Could be improved by coercing to a readable duk_tval (especially string escaping) */
				h_name = duk_get_hstring(ctx, -2);  /* may be NULL */
				funcname = (h_name == NULL || h_name == DUK_HTHREAD_STRING_EMPTY_STRING(thr)) ?
				           "[anon]" : (const char *) DUK_HSTRING_GET_DATA(h_name);
				filename = duk_get_string(ctx, -1);
				filename = filename ? filename : "";
				DUK_ASSERT(funcname != NULL);
				DUK_ASSERT(filename != NULL);

				if (h_func == NULL) {
					duk_push_sprintf(ctx, "at %s light%s%s%s%s%s",
					                 (const char *) funcname,
					                 (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
					                 (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
					                 (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
					                 (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
					                 (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
				} else if (DUK_HOBJECT_HAS_NATFUNC(h_func)) {
					duk_push_sprintf(ctx, "at %s (%s) native%s%s%s%s%s",
					                 (const char *) funcname,
					                 (const char *) filename,
					                 (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
					                 (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
					                 (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
					                 (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
					                 (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
				} else {
					duk_push_sprintf(ctx, "at %s (%s:%ld)%s%s%s%s%s",
					                 (const char *) funcname,
					                 (const char *) filename,
					                 (long) line,
					                 (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
					                 (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
					                 (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
					                 (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
					                 (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
				}
				duk_replace(ctx, -5);   /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */
				duk_pop_n(ctx, 3);      /* -> [ ... str ] */
			} else if (t == DUK_TYPE_STRING) {
				/*
				 *  __FILE__ / __LINE__ entry, here 'pc' is line number directly.
				 *  Sometimes __FILE__ / __LINE__ is reported as the source for
				 *  the error (fileName, lineNumber), sometimes not.
				 */

				/* [ ... v1(filename) v2(line+flags) ] */

				/* When looking for .fileName/.lineNumber, blame compilation
				 * or C call site unless flagged not to do so.
				 */
				if (!(flags & DUK_TB_FLAG_NOBLAME_FILELINE)) {
					if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
						duk_pop(ctx);
						return 1;
					} else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
						duk_push_int(ctx, pc);
						return 1;
					}
				}

				duk_push_sprintf(ctx, "at [anon] (%s:%ld) internal",
				                 (const char *) duk_get_string(ctx, -2), (long) pc);
				duk_replace(ctx, -3);  /* [ ... v1 v2 str ] -> [ ... str v2 ] */
				duk_pop(ctx);          /* -> [ ... str ] */
			} else {
				/* unknown, ignore */
				duk_pop_2(ctx);
				break;
			}
		}

		if (count_func >= DUK_USE_TRACEBACK_DEPTH) {
			/* Possibly truncated; there is no explicit truncation
			 * marker so this is the best we can do.
			 */

			duk_push_hstring_stridx(ctx, DUK_STRIDX_BRACKETED_ELLIPSIS);
		}
	}

	/* [ ... this tracedata sep this str1 ... strN ] */

	if (output_type != DUK__OUTPUT_TYPE_TRACEBACK) {
		return 0;
	} else {
		/* The 'this' after 'sep' will get ToString() coerced by
		 * duk_join() automatically.  We don't want to do that
		 * coercion when providing .fileName or .lineNumber (GH-254).
		 */
		duk_join(ctx, duk_get_top(ctx) - (idx_td + 2) /*count, not including sep*/);
		return 1;
	}
}
Exemplo n.º 3
0
static int duk__traceback_getter_helper(duk_context *ctx, int output_type) {
	duk_hthread *thr = (duk_hthread *) ctx;
	int idx_td;
	int i;
	const char *str_tailcalled = " tailcalled";
	const char *str_strict = " strict";
	const char *str_construct = " construct";
	const char *str_prevyield = " preventsyield";
	const char *str_directeval = " directeval";
	const char *str_empty = "";

	DUK_ASSERT_TOP(ctx, 0);  /* fixed arg count */

	duk_push_this(ctx);
	duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TRACEDATA);
	idx_td = duk_get_top_index(ctx);

	duk_push_hstring_stridx(ctx, DUK_STRIDX_NEWLINE_TAB);
	duk_push_this(ctx);
	duk_to_string(ctx, -1);

	/* [ ... this tracedata sep ToString(this) ] */

	/* FIXME: skip null filename? */

	if (duk_check_type(ctx, idx_td, DUK_TYPE_OBJECT)) {
		int t;

		/* Current tracedata contains 2 entries per callstack entry. */
		for (i = 0; ; i += 2) {
			int pc;
			int line;
			int flags;
			double d;
			const char *funcname;
			duk_hobject *h_func;
			duk_hstring *h_name;
			duk_hbuffer_fixed *pc2line;

			duk_require_stack(ctx, 5);
			duk_get_prop_index(ctx, idx_td, i);
			duk_get_prop_index(ctx, idx_td, i + 1);
			d = duk_to_number(ctx, -1);
			pc = (int) fmod(d, DUK_DOUBLE_2TO32);
			flags = (int) floor(d / DUK_DOUBLE_2TO32);
			t = duk_get_type(ctx, -2);

			if (t == DUK_TYPE_OBJECT) {
				/*
				 *  Ecmascript/native function call
				 */

				/* [ ... v1(func) v2(pc+flags) ] */

				h_func = duk_get_hobject(ctx, -2);
				DUK_ASSERT(h_func != NULL);

				duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
				duk_get_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME);

				duk_get_prop_stridx(ctx, -4, DUK_STRIDX_INT_PC2LINE);
				if (duk_is_buffer(ctx, -1)) {
					pc2line = (duk_hbuffer_fixed *) duk_get_hbuffer(ctx, -1);
					DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) pc2line));
					line = duk_hobject_pc2line_query(pc2line, (duk_uint_fast32_t) pc);
				} else {
					line = 0;
				}
				duk_pop(ctx);

				/* [ ... v1 v2 name filename ] */

				if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
					return 1;
				} else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
					duk_push_int(ctx, line);
					return 1;
				}

				h_name = duk_get_hstring(ctx, -2);  /* may be NULL */
				funcname = (h_name == NULL || h_name == DUK_HTHREAD_STRING_EMPTY_STRING(thr)) ?
				           "anon" : (const char *) DUK_HSTRING_GET_DATA(h_name);
				if (DUK_HOBJECT_HAS_NATIVEFUNCTION(h_func)) {
					duk_push_sprintf(ctx, "%s %s native%s%s%s%s%s",
					                 funcname,
					                 duk_get_string(ctx, -1),
					                 (flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty,
					                 (flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcalled : str_empty,
					                 (flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty,
					                 (flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty,
					                 (flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty);

				} else {
					duk_push_sprintf(ctx, "%s %s:%d%s%s%s%s%s",
					                 funcname,
					                 duk_get_string(ctx, -1),
					                 line,
					                 (flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty,
					                 (flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcalled : str_empty,
					                 (flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty,
					                 (flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty,
					                 (flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty);
				}
				duk_replace(ctx, -5);   /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */
				duk_pop_n(ctx, 3);      /* -> [ ... str ] */
			} else if (t == DUK_TYPE_STRING) {
				/*
				 *  __FILE__ / __LINE__ entry, here 'pc' is line number directly.
				 *  Sometimes __FILE__ / __LINE__ is reported as the source for
				 *  the error (fileName, lineNumber), sometimes not.
				 */

				/* [ ... v1(filename) v2(line+flags) ] */

				if (!(flags & DUK_TB_FLAG_NOBLAME_FILELINE)) {
					if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
						duk_pop(ctx);
						return 1;
					} else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
						duk_push_int(ctx, pc);
						return 1;
					}
				}

				duk_push_sprintf(ctx, "%s:%d",
				                 duk_get_string(ctx, -2), pc);
				duk_replace(ctx, -3);  /* [ ... v1 v2 str ] -> [ ... str v2 ] */
				duk_pop(ctx);          /* -> [ ... str ] */
			} else {
				/* unknown, ignore */
				duk_pop_2(ctx);
				break;
			}
		}

		if (i >= DUK_USE_TRACEBACK_DEPTH * 2) {
			/* Possibly truncated; there is no explicit truncation
			 * marker so this is the best we can do.
			 */

			duk_push_hstring_stridx(ctx, DUK_STRIDX_BRACKETED_ELLIPSIS);
		}
	}

	/* [ ... this tracedata sep ToString(this) str1 ... strN ] */

	if (output_type != DUK__OUTPUT_TYPE_TRACEBACK) {
		return 0;
	} else {
		duk_join(ctx, duk_get_top(ctx) - (idx_td + 2) /*count, not including sep*/);
		return 1;
	}
}