static duk_hstring *duk__alloc_init_hstring(duk_heap *heap, duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { duk_hstring *res = NULL; duk_uint8_t *data; duk_size_t alloc_size; duk_uarridx_t dummy; /* NUL terminate for convenient C access */ alloc_size = (duk_size_t) (sizeof(duk_hstring) + blen + 1); res = (duk_hstring *) DUK_ALLOC(heap, alloc_size); if (!res) { goto error; } DUK_MEMZERO(res, sizeof(duk_hstring)); #ifdef DUK_USE_EXPLICIT_NULL_INIT DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr); #endif DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, 0); if (duk_js_to_arrayindex_raw_string(str, blen, &dummy)) { DUK_HSTRING_SET_ARRIDX(res); } /* All strings beginning with 0xff are treated as "internal", * even strings interned by the user. This allows user code to * create internal properties too, and makes behavior consistent * in case user code happens to use a string also used by Duktape * (such as string has already been interned and has the 'internal' * flag set). */ if (blen > 0 && str[0] == (duk_uint8_t) 0xff) { DUK_HSTRING_SET_INTERNAL(res); } res->hash = strhash; res->blen = blen; res->clen = (duk_uint32_t) duk_unicode_unvalidated_utf8_length(str, (duk_size_t) blen); /* clen <= blen */ data = (duk_uint8_t *) (res + 1); DUK_MEMCPY(data, str, blen); data[blen] = (duk_uint8_t) 0; DUK_DDD(DUK_DDDPRINT("interned string, hash=0x%08lx, blen=%ld, clen=%ld, has_arridx=%ld", (unsigned long) DUK_HSTRING_GET_HASH(res), (long) DUK_HSTRING_GET_BYTELEN(res), (long) DUK_HSTRING_GET_CHARLEN(res), (long) DUK_HSTRING_HAS_ARRIDX(res) ? 1 : 0)); return res; error: DUK_FREE(heap, res); return NULL; }
DUK_LOCAL duk_hstring *duk__alloc_init_hstring(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash, const duk_uint8_t *extdata) { duk_hstring *res = NULL; duk_uint8_t *data; duk_size_t alloc_size; duk_uarridx_t dummy; duk_uint32_t clen; #if defined(DUK_USE_STRLEN16) /* If blen <= 0xffffUL, clen is also guaranteed to be <= 0xffffUL. */ if (blen > 0xffffUL) { DUK_D(DUK_DPRINT("16-bit string blen/clen active and blen over 16 bits, reject intern")); return NULL; } #endif if (extdata) { alloc_size = (duk_size_t) sizeof(duk_hstring_external); res = (duk_hstring *) DUK_ALLOC(heap, alloc_size); if (!res) { goto alloc_error; } DUK_MEMZERO(res, sizeof(duk_hstring_external)); #ifdef DUK_USE_EXPLICIT_NULL_INIT DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr); #endif DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, DUK_HSTRING_FLAG_EXTDATA); ((duk_hstring_external *) res)->extdata = extdata; } else { /* NUL terminate for convenient C access */ alloc_size = (duk_size_t) (sizeof(duk_hstring) + blen + 1); res = (duk_hstring *) DUK_ALLOC(heap, alloc_size); if (!res) { goto alloc_error; } DUK_MEMZERO(res, sizeof(duk_hstring)); #ifdef DUK_USE_EXPLICIT_NULL_INIT DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr); #endif DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, 0); data = (duk_uint8_t *) (res + 1); DUK_MEMCPY(data, str, blen); data[blen] = (duk_uint8_t) 0; } if (duk_js_to_arrayindex_raw_string(str, blen, &dummy)) { DUK_HSTRING_SET_ARRIDX(res); } /* All strings beginning with 0xff are treated as "internal", * even strings interned by the user. This allows user code to * create internal properties too, and makes behavior consistent * in case user code happens to use a string also used by Duktape * (such as string has already been interned and has the 'internal' * flag set). */ if (blen > 0 && str[0] == (duk_uint8_t) 0xff) { DUK_HSTRING_SET_INTERNAL(res); } DUK_HSTRING_SET_HASH(res, strhash); DUK_HSTRING_SET_BYTELEN(res, blen); clen = (duk_uint32_t) duk_unicode_unvalidated_utf8_length(str, (duk_size_t) blen); DUK_ASSERT(clen <= blen); DUK_HSTRING_SET_CHARLEN(res, clen); DUK_DDD(DUK_DDDPRINT("interned string, hash=0x%08lx, blen=%ld, clen=%ld, has_arridx=%ld, has_extdata=%ld", (unsigned long) DUK_HSTRING_GET_HASH(res), (long) DUK_HSTRING_GET_BYTELEN(res), (long) DUK_HSTRING_GET_CHARLEN(res), (long) (DUK_HSTRING_HAS_ARRIDX(res) ? 1 : 0), (long) (DUK_HSTRING_HAS_EXTDATA(res) ? 1 : 0))); return res; alloc_error: DUK_FREE(heap, res); return NULL; }
/* 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; }