Beispiel #1
0
/* intern built-in strings from precooked data (genstrings.py) */
DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) {
	duk_bitdecoder_ctx bd_ctx;
	duk_bitdecoder_ctx *bd = &bd_ctx;  /* convenience */
	duk_small_uint_t i, j;

	DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
	bd->data = (const duk_uint8_t *) duk_strings_data;
	bd->length = (duk_size_t) DUK_STRDATA_DATA_LENGTH;

	for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
		duk_uint8_t tmp[DUK_STRDATA_MAX_STRLEN];
		duk_hstring *h;
		duk_small_uint_t len;
		duk_small_uint_t mode;
		duk_small_uint_t t;

		len = duk_bd_decode(bd, 5);
		mode = 32;		/* 0 = uppercase, 32 = lowercase (= 'a' - 'A') */
		for (j = 0; j < len; j++) {
			t = duk_bd_decode(bd, 5);
			if (t < DUK__BITPACK_LETTER_LIMIT) {
				t = t + DUK_ASC_UC_A + mode;
			} else if (t == DUK__BITPACK_UNDERSCORE) {
				t = DUK_ASC_UNDERSCORE;
			} else if (t == DUK__BITPACK_FF) {
				/* Internal keys are prefixed with 0xFF in the stringtable
				 * (which makes them invalid UTF-8 on purpose).
				 */
				t = 0xff;
			} else if (t == DUK__BITPACK_SWITCH1) {
				t = duk_bd_decode(bd, 5);
				DUK_ASSERT_DISABLE(t >= 0);  /* unsigned */
				DUK_ASSERT(t <= 25);
				t = t + DUK_ASC_UC_A + (mode ^ 32);
			} else if (t == DUK__BITPACK_SWITCH) {
				mode = mode ^ 32;
				t = duk_bd_decode(bd, 5);
				DUK_ASSERT_DISABLE(t >= 0);
				DUK_ASSERT(t <= 25);
				t = t + DUK_ASC_UC_A + mode;
			} else if (t == DUK__BITPACK_SEVENBIT) {
				t = duk_bd_decode(bd, 7);
			}
			tmp[j] = (duk_uint8_t) t;
		}

		/* No need to length check string: it will never exceed even
		 * the 16-bit length maximum.
		 */
		DUK_ASSERT(len <= 0xffffUL);
		DUK_DDD(DUK_DDDPRINT("intern built-in string %ld", (long) i));
		h = duk_heap_string_intern(heap, tmp, len);
		if (!h) {
			goto error;
		}

		/* Special flags checks.  Since these strings are always
		 * reachable and a string cannot appear twice in the string
		 * table, there's no need to check/set these flags elsewhere.
		 * The 'internal' flag is set by string intern code.
		 */
		if (i == DUK_STRIDX_EVAL || i == DUK_STRIDX_LC_ARGUMENTS) {
			DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(h);
		}
		if (i >= DUK_STRIDX_START_RESERVED && i < DUK_STRIDX_END_RESERVED) {
			DUK_HSTRING_SET_RESERVED_WORD(h);
			if (i >= DUK_STRIDX_START_STRICT_RESERVED) {
				DUK_HSTRING_SET_STRICT_RESERVED_WORD(h);
			}
		}

		DUK_DDD(DUK_DDDPRINT("interned: %!O", (duk_heaphdr *) h));

		/* XXX: The incref macro takes a thread pointer but doesn't
		 * use it right now.
		 */
		DUK_HSTRING_INCREF(_never_referenced_, h);

#if defined(DUK_USE_HEAPPTR16)
		heap->strs16[i] = DUK_USE_HEAPPTR_ENC16((void *) h);
#else
		heap->strs[i] = h;
#endif
	}

	return 1;

 error:
	return 0;
}
Beispiel #2
0
/* intern built-in strings from precooked data (genstrings.py) */
static int duk__init_heap_strings(duk_heap *heap) {
	duk_bitdecoder_ctx bd_ctx;
	duk_bitdecoder_ctx *bd = &bd_ctx;  /* convenience */
	int i, j;

	DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
	bd->data = (const duk_uint8_t *) duk_strings_data;
	bd->length = (duk_size_t) DUK_STRDATA_DATA_LENGTH;

	for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
		duk_uint8_t tmp[DUK_STRDATA_MAX_STRLEN];
		duk_hstring *h;
		int len;
		int mode;
		int t;

		len = duk_bd_decode(bd, 5);
		mode = 32;		/* 0 = uppercase, 32 = lowercase (= 'a' - 'A') */
		for (j = 0; j < len; j++) {
			t = duk_bd_decode(bd, 5);
			if (t < DUK__BITPACK_LETTER_LIMIT) {
				t = t + 'A' + mode;
			} else if (t == DUK__BITPACK_UNDERSCORE) {
				t = (int) '_';
			} else if (t == DUK__BITPACK_FF) {
				/* Internal keys are prefixed with 0xFF in the stringtable
				 * (which makes them invalid UTF-8 on purpose).
				 */
				t = (int) 0xff;
			} else if (t == DUK__BITPACK_SWITCH1) {
				t = duk_bd_decode(bd, 5);
				DUK_ASSERT(t >= 0 && t <= 25);
				t = t + 'A' + (mode ^ 32);
			} else if (t == DUK__BITPACK_SWITCH) {
				mode = mode ^ 32;
				t = duk_bd_decode(bd, 5);
				DUK_ASSERT(t >= 0 && t <= 25);
				t = t + 'A' + mode;
			} else if (t == DUK__BITPACK_SEVENBIT) {
				t = duk_bd_decode(bd, 7);
			}
			tmp[j] = (duk_uint8_t) t;
		}

		DUK_DDD(DUK_DDDPRINT("intern built-in string %d", i));
		h = duk_heap_string_intern(heap, tmp, len);
		if (!h) {
			goto error;
		}

		/* special flags */

		if (len > 0 && tmp[0] == 0xff) {
			DUK_HSTRING_SET_INTERNAL(h);
		}
		if (i == DUK_STRIDX_EVAL || i == DUK_STRIDX_LC_ARGUMENTS) {
			DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(h);
		}
		if (i >= DUK_STRIDX_START_RESERVED && i < DUK_STRIDX_END_RESERVED) {
			DUK_HSTRING_SET_RESERVED_WORD(h);
			if (i >= DUK_STRIDX_START_STRICT_RESERVED) {
				DUK_HSTRING_SET_STRICT_RESERVED_WORD(h);
			}
		}

		DUK_DDD(DUK_DDDPRINT("interned: %!O", h));

		/* The incref macro takes a thread pointer but doesn't use it
		 * right now.
		 */
		DUK_HSTRING_INCREF(_never_referenced_, h);

		heap->strs[i] = h;
	}

	return 1;

 error:
	return 0;
}
Beispiel #3
0
DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_bool_t noblame_fileline) {
	duk_context *ctx = (duk_context *) thr;
	duk_small_uint_t depth;
	duk_int_t i, i_min;
	duk_int_t arr_size;
	duk_harray *a;
	duk_tval *tv;
	duk_hstring *s;
	duk_uint32_t u32;
	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.rst.
	 */

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

	/* Preallocate array to correct size, so that we can just write out
	 * the _Tracedata values into the array part.
	 */
	depth = DUK_USE_TRACEBACK_DEPTH;
	arr_size = (duk_int_t) (thr_callstack->callstack_top <= depth ? thr_callstack->callstack_top : depth) * 2;
	if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
		arr_size += 2;
	}
	if (c_filename) {
		/* We need the C filename to be interned before getting the
		 * array part pointer to avoid any GC interference while the
		 * array part is populated.
		 */
		duk_push_string(ctx, c_filename);
		arr_size += 2;
	}

	DUK_D(DUK_DPRINT("preallocated _Tracedata to %ld items", (long) arr_size));
	a = duk_push_harray_with_size(ctx, (duk_uint32_t) arr_size);  /* XXX: call which returns array part pointer directly */
	DUK_ASSERT(a != NULL);
	tv = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a);
	DUK_ASSERT(tv != NULL || arr_size == 0);

	/* Compiler SyntaxErrors (and other errors) come first, and are
	 * blamed by default (not flagged "noblame").
	 */
	if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
		s = thr->compile_ctx->h_filename;
		DUK_TVAL_SET_STRING(tv, s);
		DUK_HSTRING_INCREF(thr, s);
		tv++;

		u32 = (duk_uint32_t) thr->compile_ctx->curr_token.start_line;  /* (flags<<32) + (line), flags = 0 */
		DUK_TVAL_SET_U32(tv, u32);
		tv++;
	}

	/* 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.
	 */

	/* [ ... error c_filename? arr ] */

	if (c_filename) {
		DUK_ASSERT(DUK_TVAL_IS_STRING(thr->valstack_top - 2));
		s = DUK_TVAL_GET_STRING(thr->valstack_top - 2);  /* interned c_filename */
		DUK_ASSERT(s != NULL);
		DUK_TVAL_SET_STRING(tv, s);
		DUK_HSTRING_INCREF(thr, s);
		tv++;

		d = (noblame_fileline ? ((duk_double_t) DUK_TB_FLAG_NOBLAME_FILELINE) * DUK_DOUBLE_2TO32 : 0.0) +
		    (duk_double_t) c_line;
		DUK_TVAL_SET_DOUBLE(tv, d);
		tv++;
	}

	/* 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 c_filename? 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;
		duk_tval *tv_src;

		/*
		 *  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_DISABLE(thr_callstack->callstack[i].pc >= 0);  /* unsigned */

		/* Add function object. */
		tv_src = &(thr_callstack->callstack + i)->tv_func;  /* object (function) or lightfunc */
		DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_src) || DUK_TVAL_IS_LIGHTFUNC(tv_src));
		DUK_TVAL_SET_TVAL(tv, tv_src);
		DUK_TVAL_INCREF(thr, tv);
		tv++;

		/* Add a number containing: pc, activation flags.
		 *
		 * PC points to next instruction, find offending PC.  Note that
		 * PC == 0 for native code.
		 */
		pc = duk_hthread_get_act_prev_pc(thr_callstack, thr_callstack->callstack + i);
		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_TVAL_SET_DOUBLE(tv, d);
		tv++;
	}

	DUK_ASSERT((duk_uint32_t) (tv - DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a)) == a->length);
	DUK_ASSERT(a->length == (duk_uint32_t) arr_size);

	/* [ ... error c_filename? arr ] */

	if (c_filename) {
		duk_remove(ctx, -2);
	}

	/* [ ... error arr ] */

	duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INT_TRACEDATA);  /* -> [ ... error ] */
}