Exemplo n.º 1
0
int duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr) {
	size_t alloc_size;
	int i;

	DUK_ASSERT(heap != NULL);
	DUK_ASSERT(thr != NULL);
	DUK_ASSERT(thr->valstack == NULL);
	DUK_ASSERT(thr->valstack_end == NULL);
	DUK_ASSERT(thr->valstack_bottom == NULL);
	DUK_ASSERT(thr->valstack_top == NULL);
	DUK_ASSERT(thr->callstack == NULL);
	DUK_ASSERT(thr->catchstack == NULL);

	/* valstack */
	alloc_size = sizeof(duk_tval) * DUK_VALSTACK_INITIAL_SIZE;
	thr->valstack = (duk_tval *) DUK_ALLOC(heap, alloc_size);
	if (!thr->valstack) {
		goto fail;
	}
	DUK_MEMSET(thr->valstack, 0, alloc_size);
	thr->valstack_end = thr->valstack + DUK_VALSTACK_INITIAL_SIZE;
	thr->valstack_bottom = thr->valstack;
	thr->valstack_top = thr->valstack;

	for (i = 0; i < DUK_VALSTACK_INITIAL_SIZE; i++) {
		DUK_TVAL_SET_UNDEFINED_UNUSED(&thr->valstack[i]);
	}

	/* callstack */
	alloc_size = sizeof(duk_activation) * DUK_CALLSTACK_INITIAL_SIZE;
	thr->callstack = (duk_activation *) DUK_ALLOC(heap, alloc_size);
	if (!thr->callstack) {
		goto fail;
	}
	DUK_MEMSET(thr->callstack, 0, alloc_size);
	thr->callstack_size = DUK_CALLSTACK_INITIAL_SIZE;
	DUK_ASSERT(thr->callstack_top == 0);

	/* catchstack */
	alloc_size = sizeof(duk_catcher) * DUK_CATCHSTACK_INITIAL_SIZE;
	thr->catchstack = (duk_catcher *) DUK_ALLOC(heap, alloc_size);
	if (!thr->catchstack) {
		goto fail;
	}
	DUK_MEMSET(thr->catchstack, 0, alloc_size);
	thr->catchstack_size = DUK_CATCHSTACK_INITIAL_SIZE;
	DUK_ASSERT(thr->catchstack_top == 0);

	return 1;

 fail:
	DUK_FREE(heap, thr->valstack);
	DUK_FREE(heap, thr->callstack);
	DUK_FREE(heap, thr->catchstack);

	thr->valstack = NULL;
	thr->callstack = NULL;
	thr->catchstack = NULL;
	return 0;
}
Exemplo n.º 2
0
DUK_EXTERNAL void *duk_alloc(duk_context *ctx, duk_size_t size) {
	duk_hthread *thr = (duk_hthread *) ctx;

	DUK_ASSERT_CTX_VALID(ctx);

	return DUK_ALLOC(thr->heap, size);
}
Exemplo n.º 3
0
DUK_INTERNAL duk_hcompfunc *duk_hcompfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
	duk_hcompfunc *res;

	res = (duk_hcompfunc *) DUK_ALLOC(heap, sizeof(duk_hcompfunc));
	if (DUK_UNLIKELY(res == NULL)) {
		return NULL;
	}
	DUK_MEMZERO(res, sizeof(duk_hcompfunc));

	duk__init_object_parts(heap, &res->obj, hobject_flags);

#if defined(DUK_USE_EXPLICIT_NULL_INIT)
#if defined(DUK_USE_HEAPPTR16)
	/* NULL pointer is required to encode to zero, so memset is enough. */
#else
	res->data = NULL;
	res->funcs = NULL;
	res->bytecode = NULL;
#endif
	res->lex_env = NULL;
	res->var_env = NULL;
#endif

	return res;
}
Exemplo n.º 4
0
void *duk_alloc(duk_context *ctx, size_t size) {
	duk_hthread *thr = (duk_hthread *) ctx;

	DUK_ASSERT(ctx != NULL);

	return DUK_ALLOC(thr->heap, size);
}
Exemplo n.º 5
0
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;
}
Exemplo n.º 6
0
DUK_LOCAL duk_bool_t duk__insert_hstring_chain(duk_heap *heap, duk_hstring *h) {
	duk_small_uint_t slotidx;
	duk_strtab_entry *e;
	duk_uint16_t *lst;
	duk_uint16_t *new_lst;
	duk_size_t i, n;
	duk_uint16_t null16 = heap->heapptr_null16;
	duk_uint16_t h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);

	DUK_ASSERT(heap != NULL);
	DUK_ASSERT(h != NULL);

	slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE;
	DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);

	e = heap->strtable + slotidx;
	if (e->listlen == 0) {
		if (e->u.str16 == null16) {
			e->u.str16 = h16;
		} else {
			/* Now two entries in the same slot, alloc list */
			lst = (duk_uint16_t *) DUK_ALLOC(heap, sizeof(duk_uint16_t) * 2);
			if (lst == NULL) {
				return 1;  /* fail */
			}
			lst[0] = e->u.str16;
			lst[1] = h16;
			e->u.strlist16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) lst);
			e->listlen = 2;
		}
	} else {
		DUK_ASSERT(e->u.strlist16 != null16);
		lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
		DUK_ASSERT(lst != NULL);
		for (i = 0, n = e->listlen; i < n; i++) {
			if (lst[i] == null16) {
				lst[i] = h16;
				return 0;
			}
		}

		if (e->listlen + 1 == 0) {
			/* Overflow, relevant mainly when listlen is 16 bits. */
			return 1;  /* fail */
		}

		new_lst = (duk_uint16_t *) DUK_REALLOC(heap, lst, sizeof(duk_uint16_t) * (e->listlen + 1));
		if (new_lst == NULL) {
			return 1;  /* fail */
		}
		new_lst[e->listlen++] = h16;
		e->u.strlist16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) new_lst);
	}
	return 0;
}
Exemplo n.º 7
0
DUK_INTERNAL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size) {
	void *res;

	DUK_ASSERT(heap != NULL);
	DUK_ASSERT_DISABLE(size >= 0);

	res = DUK_ALLOC(heap, size);
	if (DUK_LIKELY(res != NULL)) {
		duk_memzero(res, size);
	}
	return res;
}
Exemplo n.º 8
0
			/* Overflow, relevant mainly when listlen is 16 bits. */
			return 1;  /* fail */
		}

		new_lst = (duk_uint16_t *) DUK_REALLOC(heap, lst, sizeof(duk_uint16_t) * (e->listlen + 1));
		if (new_lst == NULL) {
			return 1;  /* fail */
		}
		new_lst[e->listlen++] = h16;
		e->u.strlist16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) new_lst);
	}
	return 0;
}
#else  /* DUK_USE_HEAPPTR16 */
DUK_LOCAL duk_bool_t duk__insert_hstring_chain(duk_heap *heap, duk_hstring *h) {
	duk_small_uint_t slotidx;
	duk_strtab_entry *e;
	duk_hstring **lst;
	duk_hstring **new_lst;
	duk_size_t i, n;

	DUK_ASSERT(heap != NULL);
	DUK_ASSERT(h != NULL);

	slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE;
	DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);

	e = heap->strtable + slotidx;
	if (e->listlen == 0) {
		if (e->u.str == NULL) {
			e->u.str = h;
		} else {
			/* Now two entries in the same slot, alloc list */
			lst = (duk_hstring **) DUK_ALLOC(heap, sizeof(duk_hstring *) * 2);
			if (lst == NULL) {
				return 1;  /* fail */
			}
			lst[0] = e->u.str;
			lst[1] = h;
			e->u.strlist = lst;
			e->listlen = 2;
		}
	} else {
		DUK_ASSERT(e->u.strlist != NULL);
		lst = e->u.strlist;
		for (i = 0, n = e->listlen; i < n; i++) {
			if (lst[i] == NULL) {
				lst[i] = h;
				return 0;
			}
		}

		if (e->listlen + 1 == 0) {
			/* Overflow, relevant mainly when listlen is 16 bits. */
			return 1;  /* fail */
		}

		new_lst = (duk_hstring **) DUK_REALLOC(heap, e->u.strlist, sizeof(duk_hstring *) * (e->listlen + 1));
		if (new_lst == NULL) {
			return 1;  /* fail */
		}
		new_lst[e->listlen++] = h;
		e->u.strlist = new_lst;
	}
	return 0;
}
Exemplo n.º 9
0
DUK_INTERNAL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size) {
	void *res;

	DUK_ASSERT(heap != NULL);
	DUK_ASSERT_DISABLE(size >= 0);

	res = DUK_ALLOC(heap, size);
	if (DUK_LIKELY(res != NULL)) {
		/* assume memset with zero size is OK */
		DUK_MEMZERO(res, size);
	}
	return res;
}
Exemplo n.º 10
0
DUK_INTERNAL duk_harray *duk_harray_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
	duk_harray *res;

	res = (duk_harray *) DUK_ALLOC(heap, sizeof(duk_harray));
	if (DUK_UNLIKELY(res == NULL)) {
		return NULL;
	}
	DUK_MEMZERO(res, sizeof(duk_harray));

	duk__init_object_parts(heap, &res->obj, hobject_flags);

	DUK_ASSERT(res->length == 0);

	return res;
}
Exemplo n.º 11
0
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_uint32_t alloc_size;
	duk_uint32_t dummy;

	/* NUL terminate for convenient C access */

	alloc_size = 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);
	}

	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%08x, blen=%d, clen=%d, arridx=%d",
	                     DUK_HSTRING_GET_HASH(res),
	                     DUK_HSTRING_GET_BYTELEN(res),
	                     DUK_HSTRING_GET_CHARLEN(res),
	                     DUK_HSTRING_HAS_ARRIDX(res) ? 1 : 0));

	return res;

 error:
	DUK_FREE(heap, res);
	return NULL;
}
Exemplo n.º 12
0
DUK_INTERNAL duk_hnatfunc *duk_hnatfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
	duk_hnatfunc *res;

	res = (duk_hnatfunc *) DUK_ALLOC(heap, sizeof(duk_hnatfunc));
	if (DUK_UNLIKELY(res == NULL)) {
		return NULL;
	}
	DUK_MEMZERO(res, sizeof(duk_hnatfunc));

	duk__init_object_parts(heap, &res->obj, hobject_flags);

#if defined(DUK_USE_EXPLICIT_NULL_INIT)
	res->func = NULL;
#endif

	return res;
}
Exemplo n.º 13
0
duk_hnativefunction *duk_hnativefunction_alloc(duk_heap *heap, int hobject_flags) {
	duk_hnativefunction *res;

	res = (duk_hnativefunction *) DUK_ALLOC(heap, sizeof(duk_hnativefunction));
	if (!res) {
		return NULL;
	}
	DUK_MEMZERO(res, sizeof(duk_hnativefunction));

	duk__init_object_parts(heap, &res->obj, hobject_flags);

#ifdef DUK_USE_EXPLICIT_NULL_INIT
	res->func = NULL;
#endif

	return res;
}
Exemplo n.º 14
0
DUK_INTERNAL duk_hthread *duk_hthread_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
	duk_hthread *res;

	res = (duk_hthread *) DUK_ALLOC(heap, sizeof(duk_hthread));
	if (DUK_UNLIKELY(res == NULL)) {
		return NULL;
	}
	DUK_MEMZERO(res, sizeof(duk_hthread));

	duk__init_object_parts(heap, &res->obj, hobject_flags);

#if defined(DUK_USE_EXPLICIT_NULL_INIT)
	res->ptr_curr_pc = NULL;
	res->heap = NULL;
	res->valstack = NULL;
	res->valstack_end = NULL;
	res->valstack_bottom = NULL;
	res->valstack_top = NULL;
	res->callstack = NULL;
	res->catchstack = NULL;
	res->resumer = NULL;
	res->compile_ctx = NULL,
#if defined(DUK_USE_HEAPPTR16)
	res->strs16 = NULL;
#else
	res->strs = NULL;
#endif
	{
		int i;
		for (i = 0; i < DUK_NUM_BUILTINS; i++) {
			res->builtins[i] = NULL;
		}
	}
#endif
	/* when nothing is running, API calls are in non-strict mode */
	DUK_ASSERT(res->strict == 0);

	res->heap = heap;
	res->valstack_max = DUK_VALSTACK_DEFAULT_MAX;
	res->callstack_max = DUK_CALLSTACK_DEFAULT_MAX;
	res->catchstack_max = DUK_CATCHSTACK_DEFAULT_MAX;

	return res;
}
Exemplo n.º 15
0
DUK_INTERNAL duk_hbufobj *duk_hbufobj_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
	duk_hbufobj *res;

	res = (duk_hbufobj *) DUK_ALLOC(heap, sizeof(duk_hbufobj));
	if (DUK_UNLIKELY(res == NULL)) {
		return NULL;
	}
	DUK_MEMZERO(res, sizeof(duk_hbufobj));

	duk__init_object_parts(heap, &res->obj, hobject_flags);

#if defined(DUK_USE_EXPLICIT_NULL_INIT)
	res->buf = NULL;
	res->buf_prop = NULL;
#endif

	DUK_ASSERT_HBUFOBJ_VALID(res);
	return res;
}
Exemplo n.º 16
0
void *duk_heap_mem_alloc_checked(duk_hthread *thr, size_t size, const char *filename, int line) {
#else
void *duk_heap_mem_alloc_checked(duk_hthread *thr, size_t size) {
#endif
	void *res;

	DUK_ASSERT(thr != NULL);
	DUK_ASSERT_DISABLE(size >= 0);

	res = DUK_ALLOC(thr->heap, size);
	if (!res) {
#ifdef DUK_USE_VERBOSE_ERRORS
		DUK_ERROR_RAW(filename, line, thr, DUK_ERR_ALLOC_ERROR, "memory alloc failed");
#else
		DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "memory alloc failed");
#endif
	}
	return res;
}
Exemplo n.º 17
0
duk_hobject *duk_hobject_alloc(duk_heap *heap, int hobject_flags) {
	duk_hobject *res;

	DUK_ASSERT(heap != NULL);

	/* different memory layout, alloc size, and init */
	DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_COMPILEDFUNCTION) == 0);
	DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_NATIVEFUNCTION) == 0);
	DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_THREAD) == 0);

	res = (duk_hobject *) DUK_ALLOC(heap, sizeof(duk_hobject));
	if (!res) {
		return NULL;
	}
	DUK_MEMZERO(res, sizeof(duk_hobject));

	duk__init_object_parts(heap, res, hobject_flags);

	return res;
}
Exemplo n.º 18
0
DUK_INTERNAL duk_hobject *duk_hobject_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
	duk_hobject *res;

	DUK_ASSERT(heap != NULL);

	/* different memory layout, alloc size, and init */
	DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_COMPFUNC) == 0);
	DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_NATFUNC) == 0);
	DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_THREAD) == 0);

	res = (duk_hobject *) DUK_ALLOC(heap, sizeof(duk_hobject));
	if (DUK_UNLIKELY(res == NULL)) {
		return NULL;
	}
	DUK_MEMZERO(res, sizeof(duk_hobject));

	duk__init_object_parts(heap, res, hobject_flags);

	return res;
}
Exemplo n.º 19
0
duk_hthread *duk_hthread_alloc(duk_heap *heap, int hobject_flags) {
	duk_hthread *res;

	res = (duk_hthread *) DUK_ALLOC(heap, sizeof(duk_hthread));
	if (!res) {
		return NULL;
	}
	DUK_MEMZERO(res, sizeof(duk_hthread));

	duk__init_object_parts(heap, &res->obj, hobject_flags);

#ifdef DUK_USE_EXPLICIT_NULL_INIT
	res->heap = NULL;
	res->valstack = NULL;
	res->valstack_end = NULL;
	res->valstack_bottom = NULL;
	res->valstack_top = NULL;
	res->callstack = NULL;
	res->catchstack = NULL;
	res->resumer = NULL;
	res->strs = NULL;
	{
		int i;
		for (i = 0; i < DUK_NUM_BUILTINS; i++) {
			res->builtins[i] = NULL;
		}
	}
#endif
	/* when nothing is running, API calls are in non-strict mode */
	DUK_ASSERT(res->strict == 0);

	res->heap = heap;
	res->valstack_max = DUK_VALSTACK_DEFAULT_MAX;
	res->callstack_max = DUK_CALLSTACK_DEFAULT_MAX;
	res->catchstack_max = DUK_CATCHSTACK_DEFAULT_MAX;

	return res;
}
Exemplo n.º 20
0
DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) {
	duk_context *ctx;
	duk_hobject *h1;
#if defined(DUK_USE_ROM_GLOBAL_CLONE)
	duk_hobject *h2;
	duk_uint8_t *props;
	duk_size_t alloc_size;
#endif

	ctx = (duk_context *) thr;

	/* XXX: refactor into internal helper, duk_clone_hobject() */

#if defined(DUK_USE_ROM_GLOBAL_INHERIT)
	/* Inherit from ROM-based global object: less RAM usage, less transparent. */
	duk_push_object_helper(ctx,
	                       DUK_HOBJECT_FLAG_EXTENSIBLE |
	                       DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
	                       DUK_BIDX_GLOBAL);
	h1 = duk_get_hobject(ctx, -1);
	DUK_ASSERT(h1 != NULL);
#elif defined(DUK_USE_ROM_GLOBAL_CLONE)
	/* Clone the properties of the ROM-based global object to create a
	 * fully RAM-based global object.  Uses more memory than the inherit
	 * model but more compliant.
	 */
	duk_push_object_helper(ctx,
	                       DUK_HOBJECT_FLAG_EXTENSIBLE |
	                       DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
	                       DUK_BIDX_OBJECT_PROTOTYPE);
	h1 = duk_get_hobject(ctx, -1);
	DUK_ASSERT(h1 != NULL);
	h2 = thr->builtins[DUK_BIDX_GLOBAL];
	DUK_ASSERT(h2 != NULL);

	/* Copy the property table verbatim; this handles attributes etc.
	 * For ROM objects it's not necessary (or possible) to update
	 * refcounts so leave them as is.
	 */
	alloc_size = DUK_HOBJECT_P_ALLOC_SIZE(h2);
	DUK_ASSERT(alloc_size > 0);
	props = DUK_ALLOC(thr->heap, alloc_size);
	if (!props) {
		DUK_ERROR_ALLOC_FAILED(thr);
		return;
	}
	DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h2) != NULL);
	DUK_MEMCPY((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h2), alloc_size);

	/* XXX: keep property attributes or tweak them here?
	 * Properties will now be non-configurable even when they're
	 * normally configurable for the global object.
	 */

	DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h1) == NULL);
	DUK_HOBJECT_SET_PROPS(thr->heap, h1, props);
	DUK_HOBJECT_SET_ESIZE(h1, DUK_HOBJECT_GET_ESIZE(h2));
	DUK_HOBJECT_SET_ENEXT(h1, DUK_HOBJECT_GET_ENEXT(h2));
	DUK_HOBJECT_SET_ASIZE(h1, DUK_HOBJECT_GET_ASIZE(h2));
	DUK_HOBJECT_SET_HSIZE(h1, DUK_HOBJECT_GET_HSIZE(h2));
#else
#error internal error in defines
#endif

	duk_hobject_compact_props(thr, h1);
	DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
	DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL]));  /* no need to decref */
	thr->builtins[DUK_BIDX_GLOBAL] = h1;
	DUK_HOBJECT_INCREF(thr, h1);
	DUK_D(DUK_DPRINT("duplicated global object: %!O", h1));


	/* Create a fresh object environment for the global scope.  This is
	 * needed so that the global scope points to the newly created RAM-based
	 * global object.
	 */
	duk_push_object_helper(ctx,
	                       DUK_HOBJECT_FLAG_EXTENSIBLE |
	                       DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV),
	                       -1);  /* no prototype */
	h1 = duk_get_hobject(ctx, -1);
	DUK_ASSERT(h1 != NULL);
	duk_dup(ctx, -2);
	duk_dup(ctx, -1);  /* -> [ ... new_global new_globalenv new_global new_global ] */
	duk_xdef_prop_stridx(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
	duk_xdef_prop_stridx(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE);  /* always provideThis=true */

	duk_hobject_compact_props(thr, h1);
	DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL);
	DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL_ENV]));  /* no need to decref */
	thr->builtins[DUK_BIDX_GLOBAL_ENV] = h1;
	DUK_HOBJECT_INCREF(thr, h1);
	DUK_D(DUK_DPRINT("duplicated global env: %!O", h1));

	duk_pop_2(ctx);
}
Exemplo n.º 21
0
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;
}
Exemplo n.º 22
0
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;
}
Exemplo n.º 23
0
duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, size_t size, int dynamic) {
	duk_hbuffer *res = NULL;
	size_t alloc_size;

	DUK_DDD(DUK_DDDPRINT("allocate hbuffer"));

	if (dynamic) {
		alloc_size = sizeof(duk_hbuffer_dynamic);
	} else {
		alloc_size = sizeof(duk_hbuffer_fixed) + size;
	}

#ifdef DUK_USE_ZERO_BUFFER_DATA
	/* zero everything */
	res = (duk_hbuffer *) DUK_ALLOC_ZEROED(heap, alloc_size);
#else
	res = (duk_hbuffer *) DUK_ALLOC(heap, alloc_size);
#endif
	if (!res) {
		goto error;
	}

#ifndef DUK_USE_ZERO_BUFFER_DATA
	/* if no buffer zeroing, zero the header anyway */
	DUK_MEMZERO((void *) res, dynamic ? sizeof(duk_hbuffer_dynamic) : sizeof(duk_hbuffer_fixed));
#endif

	if (dynamic) {
		duk_hbuffer_dynamic *h = (duk_hbuffer_dynamic *) res;
		void *ptr;
		if (size > 0) {
			DUK_DDD(DUK_DDDPRINT("dynamic buffer with nonzero size, alloc actual buffer"));
#ifdef DUK_USE_ZERO_BUFFER_DATA
			ptr = DUK_ALLOC_ZEROED(heap, size);
#else
			ptr = DUK_ALLOC(heap, size);
#endif
			if (!ptr) {
				/* Because size > 0, NULL check is correct */
				goto error;
			}

			h->curr_alloc = ptr;
			h->usable_size = size;  /* snug */
		} else {
#ifdef DUK_USE_EXPLICIT_NULL_INIT
			h->curr_alloc = NULL;
#endif
			DUK_ASSERT(h->usable_size == 0);
		}
	}

	res->size = size;

	DUK_HEAPHDR_SET_TYPE(&res->hdr, DUK_HTYPE_BUFFER);
	if (dynamic) {
		DUK_HBUFFER_SET_DYNAMIC(res);
	}
        DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &res->hdr);

	DUK_DDD(DUK_DDDPRINT("allocated hbuffer: %p", res));
	return res;

 error:
	DUK_DD(DUK_DDPRINT("hbuffer allocation failed"));

	DUK_FREE(heap, res);
	return NULL;
}
Exemplo n.º 24
0
DUK_INTERNAL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk_small_uint_t flags) {
	duk_hbuffer *res = NULL;
	duk_size_t alloc_size;

	DUK_DDD(DUK_DDDPRINT("allocate hbuffer"));

	/* Size sanity check.  Should not be necessary because caller is
	 * required to check this, but we don't want to cause a segfault
	 * if the size wraps either in duk_size_t computation or when
	 * storing the size in a 16-bit field.
	 */
	if (size > DUK_HBUFFER_MAX_BYTELEN) {
		DUK_D(DUK_DPRINT("hbuffer alloc failed: size too large: %ld", (long) size));
		return NULL;
	}

	if (flags & DUK_BUF_FLAG_DYNAMIC) {
		alloc_size = sizeof(duk_hbuffer_dynamic);
	} else {
		alloc_size = sizeof(duk_hbuffer_fixed) + size;
		DUK_ASSERT(alloc_size >= sizeof(duk_hbuffer_fixed));  /* no wrapping */
	}

	res = (duk_hbuffer *) DUK_ALLOC(heap, alloc_size);
	if (!res) {
		goto error;
	}

	/* zero everything unless requested not to do so */
#if defined(DUK_USE_ZERO_BUFFER_DATA)
	DUK_MEMZERO((void *) res,
	            (flags & DUK_BUF_FLAG_NOZERO) ?
	                ((flags & DUK_BUF_FLAG_DYNAMIC) ?
	                     sizeof(duk_hbuffer_dynamic) :
	                     sizeof(duk_hbuffer_fixed)) :
	                alloc_size);
#else
	DUK_MEMZERO((void *) res,
	            (flags & DUK_BUF_FLAG_DYNAMIC) ? sizeof(duk_hbuffer_dynamic) : sizeof(duk_hbuffer_fixed));
#endif

	if (flags & DUK_BUF_FLAG_DYNAMIC) {
		duk_hbuffer_dynamic *h = (duk_hbuffer_dynamic *) res;
		void *ptr;
		if (size > 0) {
			DUK_DDD(DUK_DDDPRINT("dynamic buffer with nonzero size, alloc actual buffer"));
#ifdef DUK_USE_ZERO_BUFFER_DATA
			ptr = DUK_ALLOC_ZEROED(heap, size);
#else
			ptr = DUK_ALLOC(heap, size);
#endif
			if (!ptr) {
				/* Because size > 0, NULL check is correct */
				goto error;
			}

			DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, ptr);
			DUK_HBUFFER_DYNAMIC_SET_ALLOC_SIZE(h, size);  /* snug */
		} else {
#ifdef DUK_USE_EXPLICIT_NULL_INIT
			h->curr_alloc = NULL;
#endif
			DUK_ASSERT(DUK_HBUFFER_DYNAMIC_GET_ALLOC_SIZE(h) == 0);
		}
	}

	DUK_HBUFFER_SET_SIZE(res, size);

	DUK_HEAPHDR_SET_TYPE(&res->hdr, DUK_HTYPE_BUFFER);
	if (flags & DUK_BUF_FLAG_DYNAMIC) {
		DUK_HBUFFER_SET_DYNAMIC(res);
	}
        DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &res->hdr);

	DUK_DDD(DUK_DDDPRINT("allocated hbuffer: %p", (void *) res));
	return res;

 error:
	DUK_DD(DUK_DDPRINT("hbuffer allocation failed"));

	DUK_FREE(heap, res);
	return NULL;
}
Exemplo n.º 25
0
static int duk__resize_strtab_raw(duk_heap *heap, duk_uint32_t new_size) {
#ifdef DUK_USE_MARK_AND_SWEEP
	int 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;
	duk_hstring **old_entries = heap->st;
	duk_hstring **new_entries = NULL;
	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: %d entries, %d bytes, %d used, %d%% load -> %d entries, %d bytes, %d used, %d%% load",
	                     (int) old_size, (int) (sizeof(duk_hstring *) * old_size), (int) old_used,
	                     (int) (((double) old_used) / ((double) old_size) * 100.0),
	                     (int) new_size, (int) (sizeof(duk_hstring *) * new_size), (int) duk__count_used(heap),
	                     (int) (((double) duk__count_used(heap)) / ((double) new_size) * 100.0)));
#endif

	DUK_ASSERT(new_size > (duk_uint32_t) duk__count_used(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

	new_entries = (duk_hstring **) DUK_ALLOC(heap, sizeof(duk_hstring *) * new_size);

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

	if (!new_entries) {
		goto error;
	}

#ifdef DUK_USE_EXPLICIT_NULL_INIT
	for (i = 0; i < new_size; i++) {
		new_entries[i] = NULL;
	}
#else
	DUK_MEMZERO(new_entries, sizeof(duk_hstring *) * new_size);
#endif

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

		e = old_entries[i];
		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(heap, new_entries, new_size, &new_used, e);
	}

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

	DUK_FREE(heap, heap->st);
	heap->st = new_entries;
	heap->st_size = new_size;
	heap->st_used = new_used;  /* may be less, since DELETED entries are NULLed by rehash */

	return 0;  /* OK */

 error:
	DUK_FREE(heap, new_entries);
	return 1;  /* FAIL */
}
Exemplo n.º 26
0
/* Allocate a new duk_hbuffer of a certain type and return a pointer to it
 * (NULL on error).  Write buffer data pointer to 'out_bufdata' (only if
 * allocation successful).
 */
DUK_INTERNAL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk_small_uint_t flags, void **out_bufdata) {
	duk_hbuffer *res = NULL;
	duk_size_t header_size;
	duk_size_t alloc_size;

	DUK_ASSERT(heap != NULL);
	DUK_ASSERT(out_bufdata != NULL);

	DUK_DDD(DUK_DDDPRINT("allocate hbuffer"));

	/* Size sanity check.  Should not be necessary because caller is
	 * required to check this, but we don't want to cause a segfault
	 * if the size wraps either in duk_size_t computation or when
	 * storing the size in a 16-bit field.
	 */
	if (size > DUK_HBUFFER_MAX_BYTELEN) {
		DUK_D(DUK_DPRINT("hbuffer alloc failed: size too large: %ld", (long) size));
		return NULL;  /* no need to write 'out_bufdata' */
	}

	if (flags & DUK_BUF_FLAG_EXTERNAL) {
		header_size = sizeof(duk_hbuffer_external);
		alloc_size = sizeof(duk_hbuffer_external);
	} else if (flags & DUK_BUF_FLAG_DYNAMIC) {
		header_size = sizeof(duk_hbuffer_dynamic);
		alloc_size = sizeof(duk_hbuffer_dynamic);
	} else {
		header_size = sizeof(duk_hbuffer_fixed);
		alloc_size = sizeof(duk_hbuffer_fixed) + size;
		DUK_ASSERT(alloc_size >= sizeof(duk_hbuffer_fixed));  /* no wrapping */
	}

	res = (duk_hbuffer *) DUK_ALLOC(heap, alloc_size);
	if (DUK_UNLIKELY(res == NULL)) {
		goto alloc_error;
	}

	/* zero everything unless requested not to do so */
#if defined(DUK_USE_ZERO_BUFFER_DATA)
	DUK_MEMZERO((void *) res,
	            (flags & DUK_BUF_FLAG_NOZERO) ? header_size : alloc_size);
#else
	DUK_MEMZERO((void *) res, header_size);
#endif

	if (flags & DUK_BUF_FLAG_EXTERNAL) {
		duk_hbuffer_external *h;
		h = (duk_hbuffer_external *) res;
		DUK_UNREF(h);
		*out_bufdata = NULL;
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
#if defined(DUK_USE_HEAPPTR16)
/* the compressed pointer is zeroed which maps to NULL, so nothing to do. */
#else
		DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap, h, NULL);
#endif
#endif
		DUK_ASSERT(DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap, h) == NULL);
	} else if (flags & DUK_BUF_FLAG_DYNAMIC) {
		duk_hbuffer_dynamic *h = (duk_hbuffer_dynamic *) res;
		void *ptr;

		if (size > 0) {
			DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL));  /* alloc external with size zero */
			DUK_DDD(DUK_DDDPRINT("dynamic buffer with nonzero size, alloc actual buffer"));
#if defined(DUK_USE_ZERO_BUFFER_DATA)
			ptr = DUK_ALLOC_ZEROED(heap, size);
#else
			ptr = DUK_ALLOC(heap, size);
#endif
			if (DUK_UNLIKELY(ptr == NULL)) {
				/* Because size > 0, NULL check is correct */
				goto alloc_error;
			}
			*out_bufdata = ptr;

			DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, ptr);
		} else {
			*out_bufdata = NULL;
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
#if defined(DUK_USE_HEAPPTR16)
/* the compressed pointer is zeroed which maps to NULL, so nothing to do. */
#else
			DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, NULL);
#endif
#endif
			DUK_ASSERT(DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, h) == NULL);
		}
	} else {
		*out_bufdata = (void *) ((duk_hbuffer_fixed *) res + 1);
	}

	DUK_HBUFFER_SET_SIZE(res, size);

	DUK_HEAPHDR_SET_TYPE(&res->hdr, DUK_HTYPE_BUFFER);
	if (flags & DUK_BUF_FLAG_DYNAMIC) {
		DUK_HBUFFER_SET_DYNAMIC(res);
		if (flags & DUK_BUF_FLAG_EXTERNAL) {
			DUK_HBUFFER_SET_EXTERNAL(res);
		}
	} else {
		DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL));
	}
        DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &res->hdr);

	DUK_DDD(DUK_DDDPRINT("allocated hbuffer: %p", (void *) res));
	return res;

 alloc_error:
	DUK_DD(DUK_DDPRINT("hbuffer allocation failed"));

	DUK_FREE(heap, res);
	return NULL;  /* no need to write 'out_bufdata' */
}