Beispiel #1
0
static int duk__resize_strtab(duk_heap *heap) {
	duk_uint32_t new_size;
	int ret;

	new_size = (duk_uint32_t) duk__count_used(heap);
	if (new_size >= 0x80000000U) {
		new_size = DUK_STRTAB_HIGHEST_32BIT_PRIME;
	} else {
		new_size = duk_util_get_hash_prime(DUK_STRTAB_GROW_ST_SIZE(new_size));
		new_size = duk_util_get_hash_prime(new_size);
	}
	DUK_ASSERT(new_size > 0);

	/* rehash even if old and new sizes are the same to get rid of
	 * DELETED entries.
	*/ 

	ret = duk__resize_strtab_raw(heap, new_size);

	return ret;
}
DUK_LOCAL void duk__remove_matching_hstring_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, duk_hstring *h) {
#else
DUK_LOCAL void duk__remove_matching_hstring_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, duk_hstring *h) {
#endif
	duk_uint32_t i;
	duk_uint32_t step;
	duk_uint32_t hash;
#if defined(DUK_USE_HEAPPTR16)
	duk_uint16_t null16 = heap->heapptr_null16;
	duk_uint16_t h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
#endif

	DUK_ASSERT(size > 0);

	hash = DUK_HSTRING_GET_HASH(h);
	i = DUK__HASH_INITIAL(hash, size);
	step = DUK__HASH_PROBE_STEP(hash);
	for (;;) {
#if defined(DUK_USE_HEAPPTR16)
		duk_uint16_t e16 = entries16[i];
#else
		duk_hstring *e = entries[i];
#endif

#if defined(DUK_USE_HEAPPTR16)
		if (e16 == null16) {
#else
		if (!e) {
#endif
			DUK_UNREACHABLE();
			break;
		}
#if defined(DUK_USE_HEAPPTR16)
		if (e16 == h16) {
#else
		if (e == h) {
#endif
			/* st_used remains the same, DELETED is counted as used */
			DUK_DDD(DUK_DDDPRINT("free matching hit: %ld", (long) i));
#if defined(DUK_USE_HEAPPTR16)
			entries16[i] = heap->heapptr_deleted16;
#else
			entries[i] = DUK__DELETED_MARKER(heap);
#endif
			break;
		}

		DUK_DDD(DUK_DDDPRINT("free matching miss: %ld", (long) i));
		i = (i + step) % size;

		/* looping should never happen */
		DUK_ASSERT(i != DUK__HASH_INITIAL(hash, size));
	}
}

DUK_LOCAL duk_bool_t duk__resize_strtab_raw_probe(duk_heap *heap, duk_uint32_t new_size) {
#ifdef DUK_USE_MARK_AND_SWEEP
	duk_small_uint_t prev_mark_and_sweep_base_flags;
#endif
#ifdef DUK_USE_DEBUG
	duk_uint32_t old_used = heap->st_used;
#endif
	duk_uint32_t old_size = heap->st_size;
#if defined(DUK_USE_HEAPPTR16)
	duk_uint16_t *old_entries = heap->strtable16;
	duk_uint16_t *new_entries = NULL;
#else
	duk_hstring **old_entries = heap->strtable;
	duk_hstring **new_entries = NULL;
#endif
	duk_uint32_t new_used = 0;
	duk_uint32_t i;

#ifdef DUK_USE_DEBUG
	DUK_UNREF(old_used);  /* unused with some debug level combinations */
#endif

#ifdef DUK_USE_DDDPRINT
	DUK_DDD(DUK_DDDPRINT("attempt to resize stringtable: %ld entries, %ld bytes, %ld used, %ld%% load -> %ld entries, %ld bytes, %ld used, %ld%% load",
	                     (long) old_size, (long) (sizeof(duk_hstring *) * old_size), (long) old_used,
	                     (long) (((double) old_used) / ((double) old_size) * 100.0),
	                     (long) new_size, (long) (sizeof(duk_hstring *) * new_size), (long) duk__count_used_probe(heap),
	                     (long) (((double) duk__count_used_probe(heap)) / ((double) new_size) * 100.0)));
#endif

	DUK_ASSERT(new_size > (duk_uint32_t) duk__count_used_probe(heap));  /* required for rehash to succeed, equality not that useful */
	DUK_ASSERT(old_entries);
#ifdef DUK_USE_MARK_AND_SWEEP
	DUK_ASSERT((heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE) == 0);
#endif

	/*
	 *  The attempt to allocate may cause a GC.  Such a GC must not attempt to resize
	 *  the stringtable (though it can be swept); finalizer execution and object
	 *  compaction must also be postponed to avoid the pressure to add strings to the
	 *  string table.
	 */

#ifdef DUK_USE_MARK_AND_SWEEP
	prev_mark_and_sweep_base_flags = heap->mark_and_sweep_base_flags;
	heap->mark_and_sweep_base_flags |= \
	        DUK_MS_FLAG_NO_STRINGTABLE_RESIZE |  /* avoid recursive call here */
	        DUK_MS_FLAG_NO_FINALIZERS |          /* avoid pressure to add/remove strings */
	        DUK_MS_FLAG_NO_OBJECT_COMPACTION;    /* avoid array abandoning which interns strings */
#endif

#if defined(DUK_USE_HEAPPTR16)
	new_entries = (duk_uint16_t *) DUK_ALLOC(heap, sizeof(duk_uint16_t) * new_size);
#else
	new_entries = (duk_hstring **) DUK_ALLOC(heap, sizeof(duk_hstring *) * new_size);
#endif

#ifdef DUK_USE_MARK_AND_SWEEP
	heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
#endif

	if (!new_entries) {
		goto resize_error;
	}

#ifdef DUK_USE_EXPLICIT_NULL_INIT
	for (i = 0; i < new_size; i++) {
#if defined(DUK_USE_HEAPPTR16)
		new_entries[i] = heap->heapptr_null16;
#else
		new_entries[i] = NULL;
#endif
	}
#else
#if defined(DUK_USE_HEAPPTR16)
	/* Relies on NULL encoding to zero. */
	DUK_MEMZERO(new_entries, sizeof(duk_uint16_t) * new_size);
#else
	DUK_MEMZERO(new_entries, sizeof(duk_hstring *) * new_size);
#endif
#endif

	/* Because new_size > duk__count_used_probe(heap), guaranteed to work */
	for (i = 0; i < old_size; i++) {
		duk_hstring *e;

#if defined(DUK_USE_HEAPPTR16)
		e = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, old_entries[i]);
#else
		e = old_entries[i];
#endif
		if (e == NULL || e == DUK__DELETED_MARKER(heap)) {
			continue;
		}
		/* checking for DUK__DELETED_MARKER is not necessary here, but helper does it now */
		duk__insert_hstring_probe(heap, new_entries, new_size, &new_used, e);
	}

#ifdef DUK_USE_DDPRINT
	DUK_DD(DUK_DDPRINT("resized stringtable: %ld entries, %ld bytes, %ld used, %ld%% load -> %ld entries, %ld bytes, %ld used, %ld%% load",
	                   (long) old_size, (long) (sizeof(duk_hstring *) * old_size), (long) old_used,
	                   (long) (((double) old_used) / ((double) old_size) * 100.0),
	                   (long) new_size, (long) (sizeof(duk_hstring *) * new_size), (long) new_used,
	                   (long) (((double) new_used) / ((double) new_size) * 100.0)));
#endif

#if defined(DUK_USE_HEAPPTR16)
	DUK_FREE(heap, heap->strtable16);
	heap->strtable16 = new_entries;
#else
	DUK_FREE(heap, heap->strtable);
	heap->strtable = new_entries;
#endif
	heap->st_size = new_size;
	heap->st_used = new_used;  /* may be less, since DELETED entries are NULLed by rehash */

	return 0;  /* OK */

 resize_error:
	DUK_FREE(heap, new_entries);
	return 1;  /* FAIL */
}

DUK_LOCAL duk_bool_t duk__resize_strtab_probe(duk_heap *heap) {
	duk_uint32_t new_size;
	duk_bool_t ret;

	new_size = (duk_uint32_t) duk__count_used_probe(heap);
	if (new_size >= 0x80000000UL) {
		new_size = DUK_STRTAB_HIGHEST_32BIT_PRIME;
	} else {
		new_size = duk_util_get_hash_prime(DUK_STRTAB_GROW_ST_SIZE(new_size));
		new_size = duk_util_get_hash_prime(new_size);
	}
	DUK_ASSERT(new_size > 0);

	/* rehash even if old and new sizes are the same to get rid of
	 * DELETED entries.
	*/

	ret = duk__resize_strtab_raw_probe(heap, new_size);

	return ret;
}