Beispiel #1
0
void duk_hthread_callstack_shrink_check(duk_hthread *thr) {
	duk_size_t new_size;
	duk_activation *p;

	DUK_ASSERT(thr != NULL);
	DUK_ASSERT_DISABLE(thr->callstack_top >= 0);  /* avoid warning (unsigned) */
	DUK_ASSERT(thr->callstack_size >= thr->callstack_top);

	if (thr->callstack_size - thr->callstack_top < DUK_CALLSTACK_SHRINK_THRESHOLD) {
		return;
	}

	new_size = thr->callstack_top + DUK_CALLSTACK_SHRINK_SPARE;
	DUK_ASSERT(new_size >= thr->callstack_top);

	DUK_DDPRINT("shrinking callstack %d -> %d", thr->callstack_size, new_size);

	/*
	 *  Note: must use indirect variant of DUK_REALLOC() because underlying
	 *  pointer may be changed by mark-and-sweep.
	 */

	/* shrink failure is not fatal */
	p = (duk_activation *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_callstack_ptr, (void *) thr, sizeof(duk_activation) * new_size);
	if (p) {
		thr->callstack = p;
		thr->callstack_size = new_size;
	} else {
		DUK_DPRINT("callstack shrink failed, ignoring");
	}

	/* note: any entries above the callstack top are garbage and not zeroed */
}
Beispiel #2
0
void *duk_heap_mem_realloc_indirect_checked(duk_hthread *thr, duk_mem_getptr cb, void *ud, size_t newsize, const char *filename, int line) {
#else
void *duk_heap_mem_realloc_indirect_checked(duk_hthread *thr, duk_mem_getptr cb, void *ud, size_t newsize) {
#endif
	void *res;
	DUK_ASSERT(thr != NULL);
	DUK_ASSERT_DISABLE(newsize >= 0);

	res = DUK_REALLOC_INDIRECT(thr->heap, cb, ud, newsize);
	if (!res) {
#ifdef DUK_USE_VERBOSE_ERRORS
		DUK_ERROR_RAW(filename, line, thr, DUK_ERR_ALLOC_ERROR, "memory realloc failed");
#else
		DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "memory realloc failed");
#endif
	}
	return res;
}
Beispiel #3
0
DUK_INTERNAL void duk_hthread_catchstack_grow(duk_hthread *thr) {
	duk_catcher *new_ptr;
	duk_size_t old_size;
	duk_size_t new_size;

	DUK_ASSERT(thr != NULL);
	DUK_ASSERT_DISABLE(thr->catchstack_top);  /* avoid warning (unsigned) */
	DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top);

	if (thr->catchstack_top < thr->catchstack_size) {
		return;
	}

	old_size = thr->catchstack_size;
	new_size = old_size + DUK_CATCHSTACK_GROW_STEP;

	/* this is a bit approximate (errors out before max is reached); this is OK */
	if (new_size >= thr->catchstack_max) {
		DUK_ERROR(thr, DUK_ERR_RANGE_ERROR, DUK_STR_CATCHSTACK_LIMIT);
	}

	DUK_DD(DUK_DDPRINT("growing catchstack %ld -> %ld", (long) old_size, (long) new_size));

	/*
	 *  Note: must use indirect variant of DUK_REALLOC() because underlying
	 *  pointer may be changed by mark-and-sweep.
	 */

	DUK_ASSERT(new_size > 0);
	new_ptr = (duk_catcher *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_catchstack_ptr, (void *) thr, sizeof(duk_catcher) * new_size);
	if (!new_ptr) {
		/* No need for a NULL/zero-size check because new_size > 0) */
		DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, DUK_STR_REALLOC_FAILED);
	}
	thr->catchstack = new_ptr;
	thr->catchstack_size = new_size;

	/* note: any entries above the catchstack top are garbage and not zeroed */
}
Beispiel #4
0
DUK_INTERNAL void duk_hthread_catchstack_shrink_check(duk_hthread *thr) {
	duk_size_t new_size;
	duk_catcher *p;

	DUK_ASSERT(thr != NULL);
	DUK_ASSERT_DISABLE(thr->catchstack_top >= 0);  /* avoid warning (unsigned) */
	DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top);

	if (thr->catchstack_size - thr->catchstack_top < DUK_CATCHSTACK_SHRINK_THRESHOLD) {
		return;
	}

	new_size = thr->catchstack_top + DUK_CATCHSTACK_SHRINK_SPARE;
	DUK_ASSERT(new_size >= thr->catchstack_top);

	DUK_DD(DUK_DDPRINT("shrinking catchstack %ld -> %ld", (long) thr->catchstack_size, (long) new_size));

	/*
	 *  Note: must use indirect variant of DUK_REALLOC() because underlying
	 *  pointer may be changed by mark-and-sweep.
	 */

	/* shrink failure is not fatal */
	p = (duk_catcher *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_catchstack_ptr, (void *) thr, sizeof(duk_catcher) * new_size);
	if (p) {
		thr->catchstack = p;
		thr->catchstack_size = new_size;
	} else {
		/* Because new_size != 0, if condition doesn't need to be
		 * (p != NULL || new_size == 0).
		 */
		DUK_ASSERT(new_size != 0);
		DUK_D(DUK_DPRINT("catchstack shrink failed, ignoring"));
	}

	/* note: any entries above the catchstack top are garbage and not zeroed */
}
Beispiel #5
0
void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t new_size, size_t new_usable_size) {
	size_t new_alloc_size;
	void *res;

	DUK_ASSERT(thr != NULL);
	DUK_ASSERT(buf != NULL);
	DUK_ASSERT(new_usable_size >= new_size);
	DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));

	/*
	 *  Maximum size check
	 *
	 *  XXX: check against usable size?
	 */

	if (new_size > DUK_HBUFFER_MAX_BYTELEN) {
		DUK_ERROR(thr, DUK_ERR_RANGE_ERROR, "buffer too long");
	}

	/*
	 *  Note: use indirect realloc variant just in case mark-and-sweep
	 *  (finalizers) might resize this same buffer during garbage
	 *  collection.
	 */

	/* FIXME: maybe remove safety NUL term for buffers? */
	new_alloc_size = new_usable_size + 1;  /* +1 for safety nul term */
	res = DUK_REALLOC_INDIRECT(thr->heap, duk_hbuffer_get_dynalloc_ptr, (void *) buf, new_alloc_size);
	if (res) {
		DUK_DDDPRINT("resized dynamic buffer %p:%d:%d -> %p:%d:%d",
		             buf->curr_alloc, buf->size, buf->usable_size,
		             res, new_size, new_usable_size);

		/*
		 *  The entire allocated buffer area, regardless of actual used size,
		 *  is kept zeroed in resizes for simplicity.  If the buffer is grown,
		 *  zero the new part (the safety NUL byte is re-zeroed every time).
		 *  Another policy would be to ensure data is zeroed as the used part
		 *  is extended (with one safety NUL byte) this is much more simple,
		 *  and not a big deal because the spart part is relatively small.
		 */

		if (new_alloc_size > buf->usable_size) {
			/* When new_usable_size == old_usable_size, one byte will
			 * be rezeroed (the safety NUL byte).
			 */
			DUK_ASSERT(new_alloc_size - buf->usable_size > 0);
#ifdef DUK_USE_ZERO_BUFFER_DATA
			DUK_MEMZERO((void *) ((char *) res + buf->usable_size),
			            new_alloc_size - buf->usable_size);
#endif
		}

		buf->size = new_size;
		buf->usable_size = new_usable_size;
		buf->curr_alloc = res;
	} else {
		DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "failed to resize buffer from %d:%d to %d:%d",
		          buf->size, buf->usable_size, new_size, new_usable_size);
	}

	DUK_ASSERT(res != NULL);
}
Beispiel #6
0
void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, size_t new_size, size_t new_usable_size) {
	size_t new_alloc_size;
	void *res;

	DUK_ASSERT(thr != NULL);
	DUK_ASSERT(buf != NULL);
	DUK_ASSERT(new_usable_size >= new_size);
	DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));

	/*
	 *  Maximum size check
	 *
	 *  XXX: check against usable size?
	 */

	if (new_size > DUK_HBUFFER_MAX_BYTELEN) {
		DUK_ERROR(thr, DUK_ERR_RANGE_ERROR, "buffer too long");
	}

	/*
	 *  Note: use indirect realloc variant just in case mark-and-sweep
	 *  (finalizers) might resize this same buffer during garbage
	 *  collection.
	 */

	new_alloc_size = new_usable_size;
	res = DUK_REALLOC_INDIRECT(thr->heap, duk_hbuffer_get_dynalloc_ptr, (void *) buf, new_alloc_size);
	if (res || new_alloc_size == 0) {
		/* 'res' may be NULL if new allocation size is 0. */

		DUK_DDD(DUK_DDDPRINT("resized dynamic buffer %p:%d:%d -> %p:%d:%d",
		                     buf->curr_alloc, buf->size, buf->usable_size,
		                     res, new_size, new_usable_size));

		/*
		 *  The entire allocated buffer area, regardless of actual used
		 *  size, is kept zeroed in resizes for simplicity.  If the buffer
		 *  is grown, zero the new part.  Another policy would be to
		 *  ensure data is zeroed as the used part is extended.  The
		 *  current approach is much more simple and is not a big deal
		 *  because the spare part is relatively small.
		 */

		if (new_alloc_size > buf->usable_size) {
			DUK_ASSERT(new_alloc_size - buf->usable_size > 0);
#ifdef DUK_USE_ZERO_BUFFER_DATA
			DUK_MEMZERO((void *) ((char *) res + buf->usable_size),
			            new_alloc_size - buf->usable_size);
#endif
		}

		buf->size = new_size;
		buf->usable_size = new_usable_size;
		buf->curr_alloc = res;
	} else {
		DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "failed to resize buffer from %d:%d to %d:%d",
		          buf->size, buf->usable_size, new_size, new_usable_size);
	}

	DUK_ASSERT(res != NULL || new_alloc_size == 0);
}