DUK_LOCAL duk_hstring *duk__do_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { duk_hstring *res; const duk_uint8_t *extdata; #if defined(DUK_USE_STRTAB_PROBE) if (duk__recheck_strtab_size_probe(heap, heap->st_used + 1)) { return NULL; } #endif /* For manual testing only. */ #if 0 { duk_size_t i; DUK_PRINTF("INTERN: \""); for (i = 0; i < blen; i++) { duk_uint8_t x = str[i]; if (x >= 0x20 && x <= 0x7e && x != '"' && x != '\\') { DUK_PRINTF("%c", (int) x); /* char: use int cast */ } else { DUK_PRINTF("\\x%02lx", (long) x); } } DUK_PRINTF("\"\n"); } #endif #if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) extdata = (const duk_uint8_t *) DUK_USE_EXTSTR_INTERN_CHECK(heap->heap_udata, (void *) str, (duk_size_t) blen); #else extdata = (const duk_uint8_t *) NULL; #endif res = duk__alloc_init_hstring(heap, str, blen, strhash, extdata); if (!res) { return NULL; } #if defined(DUK_USE_STRTAB_CHAIN) if (duk__insert_hstring_chain(heap, res)) { /* failed */ DUK_FREE(heap, res); return NULL; } #elif defined(DUK_USE_STRTAB_PROBE) /* guaranteed to succeed */ duk__insert_hstring_probe(heap, #if defined(DUK_USE_HEAPPTR16) heap->strtable16, #else heap->strtable, #endif heap->st_size, &heap->st_used, res); #else #error internal error, invalid strtab options #endif /* Note: hstring is in heap but has refcount zero and is not strongly reachable. * Caller should increase refcount and make the hstring reachable before any * operations which require allocation (and possible gc). */ return res; }
DUK_LOCAL duk_hstring *duk__do_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) { duk_hstring *res; const duk_uint8_t *extdata; #if defined(DUK_USE_MARK_AND_SWEEP) duk_small_uint_t prev_mark_and_sweep_base_flags; #endif /* Prevent any side effects on the string table and the caller provided * str/blen arguments while interning is in progress. For example, if * the caller provided str/blen from a dynamic buffer, a finalizer might * resize that dynamic buffer, invalidating the call arguments. */ #if defined(DUK_USE_MARK_AND_SWEEP) DUK_ASSERT((heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE) == 0); prev_mark_and_sweep_base_flags = heap->mark_and_sweep_base_flags; DUK__PREVENT_MS_SIDE_EFFECTS(heap); #endif #if defined(DUK_USE_STRTAB_PROBE) if (duk__recheck_strtab_size_probe(heap, heap->st_used + 1)) { goto failed; } #endif /* For manual testing only. */ #if 0 { duk_size_t i; DUK_PRINTF("INTERN: \""); for (i = 0; i < blen; i++) { duk_uint8_t x = str[i]; if (x >= 0x20 && x <= 0x7e && x != '"' && x != '\\') { DUK_PRINTF("%c", (int) x); /* char: use int cast */ } else { DUK_PRINTF("\\x%02lx", (long) x); } } DUK_PRINTF("\"\n"); } #endif #if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK) extdata = (const duk_uint8_t *) DUK_USE_EXTSTR_INTERN_CHECK(heap->heap_udata, (void *) DUK_LOSE_CONST(str), (duk_size_t) blen); #else extdata = (const duk_uint8_t *) NULL; #endif res = duk__alloc_init_hstring(heap, str, blen, strhash, extdata); if (!res) { goto failed; } #if defined(DUK_USE_STRTAB_CHAIN) if (duk__insert_hstring_chain(heap, res)) { /* failed */ DUK_FREE(heap, res); goto failed; } #elif defined(DUK_USE_STRTAB_PROBE) /* guaranteed to succeed */ duk__insert_hstring_probe(heap, #if defined(DUK_USE_HEAPPTR16) heap->strtable16, #else heap->strtable, #endif heap->st_size, &heap->st_used, res); #else #error internal error, invalid strtab options #endif /* Note: hstring is in heap but has refcount zero and is not strongly reachable. * Caller should increase refcount and make the hstring reachable before any * operations which require allocation (and possible gc). */ done: #if defined(DUK_USE_MARK_AND_SWEEP) heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags; #endif return res; failed: res = NULL; goto done; }