Exemple #1
0
DUK_LOCAL void duk__init_object_parts(duk_heap *heap, duk_hobject *obj, duk_uint_t hobject_flags) {
#if defined(DUK_USE_EXPLICIT_NULL_INIT)
	DUK_HOBJECT_SET_PROPS(heap, obj, NULL);
#endif

	/* XXX: macro? sets both heaphdr and object flags */
	obj->hdr.h_flags = hobject_flags;
	DUK_HEAPHDR_SET_TYPE(&obj->hdr, DUK_HTYPE_OBJECT);  /* also goes into flags */

#if defined(DUK_USE_HEAPPTR16)
	/* Zero encoded pointer is required to match NULL */
	DUK_HEAPHDR_SET_NEXT(heap, &obj->hdr, NULL);
#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
	DUK_HEAPHDR_SET_PREV(heap, &obj->hdr, NULL);
#endif
#endif
	DUK_ASSERT_HEAPHDR_LINKS(heap, &obj->hdr);
	DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &obj->hdr);

	/*
	 *  obj->props is intentionally left as NULL, and duk_hobject_props.c must deal
	 *  with this properly.  This is intentional: empty objects consume a minimum
	 *  amount of memory.  Further, an initial allocation might fail and cause
	 *  'obj' to "leak" (require a mark-and-sweep) since it is not reachable yet.
	 */
}
DUK_LOCAL void duk__run_object_finalizers(duk_heap *heap, duk_small_uint_t flags) {
	duk_heaphdr *curr;
	duk_heaphdr *next;
#if defined(DUK_USE_DEBUG)
	duk_size_t count = 0;
#endif
	duk_hthread *thr;

	DUK_DD(DUK_DDPRINT("duk__run_object_finalizers: %p", (void *) heap));

	thr = duk__get_temp_hthread(heap);
	DUK_ASSERT(thr != NULL);

	curr = heap->finalize_list;
	while (curr) {
		DUK_DDD(DUK_DDDPRINT("mark-and-sweep finalize: %p", (void *) curr));

		DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT);  /* only objects have finalizers */
		DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr));                /* flags have been already cleared */
		DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(curr));
		DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
		DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
		DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr));  /* No finalizers for ROM objects */

		if (DUK_LIKELY((flags & DUK_MS_FLAG_SKIP_FINALIZERS) == 0)) {
			/* Run the finalizer, duk_hobject_run_finalizer() sets FINALIZED.
			 * Next mark-and-sweep will collect the object unless it has
			 * become reachable (i.e. rescued).  FINALIZED prevents the
			 * finalizer from being executed again before that.
			 */
			duk_hobject_run_finalizer(thr, (duk_hobject *) curr);  /* must never longjmp */
			DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(curr));
		} else {
			/* Used during heap destruction: don't actually run finalizers
			 * because we're heading into forced finalization.  Instead,
			 * queue finalizable objects back to the heap_allocated list.
			 */
			DUK_D(DUK_DPRINT("skip finalizers flag set, queue object to heap_allocated without finalizing"));
			DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
		}

		/* queue back to heap_allocated */
		next = DUK_HEAPHDR_GET_NEXT(heap, curr);
		DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr);

		curr = next;
#if defined(DUK_USE_DEBUG)
		count++;
#endif
	}

	/* finalize_list will always be processed completely */
	heap->finalize_list = NULL;

#if defined(DUK_USE_DEBUG)
	DUK_D(DUK_DPRINT("mark-and-sweep finalize objects: %ld finalizers called", (long) count));
#endif
}
duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, size_t size, int dynamic) {
	duk_hbuffer *res = NULL;
	size_t alloc_size;

	DUK_DDDPRINT("allocate hbuffer");

	if (dynamic) {
		alloc_size = sizeof(duk_hbuffer_dynamic);
	} else {
		/* FIXME: maybe remove safety NUL term for buffers? */
		alloc_size = sizeof(duk_hbuffer_fixed) + size + 1;  /* +1 for a safety nul term */
	}

	/* zero everything */
	res = (duk_hbuffer *) DUK_ALLOC_ZEROED(heap, alloc_size);
	if (!res) {
		goto error;
	}

	if (dynamic) {
		duk_hbuffer_dynamic *h = (duk_hbuffer_dynamic *) res;
		void *ptr;
		if (size > 0) {
			/* FIXME: maybe remove safety NUL term for buffers? */
			DUK_DDDPRINT("dynamic buffer with nonzero size, alloc actual buffer");
			ptr = DUK_ALLOC_ZEROED(heap, size + 1);  /* +1 for a safety nul term */
			if (!ptr) {
				goto error;
			}

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

	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_DDDPRINT("allocated hbuffer: %p", res);
	return res;

 error:
	DUK_DDPRINT("hbuffer allocation failed");

	DUK_FREE(heap, res);
	return NULL;
}
static void duk__run_object_finalizers(duk_heap *heap) {
	duk_heaphdr *curr;
	duk_heaphdr *next;
#ifdef DUK_USE_DEBUG
	int count = 0;
#endif
	duk_hthread *thr;

	DUK_DD(DUK_DDPRINT("duk__run_object_finalizers: %p", (void *) heap));

	thr = duk__get_temp_hthread(heap);
	DUK_ASSERT(thr != NULL);

	curr = heap->finalize_list;
	while (curr) {
		DUK_DDD(DUK_DDDPRINT("mark-and-sweep finalize: %p", (void *) curr));

		DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT);  /* only objects have finalizers */
		DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr));                /* flags have been already cleared */
		DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(curr));
		DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
		DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));

		/* run the finalizer */
		duk_hobject_run_finalizer(thr, (duk_hobject *) curr);  /* must never longjmp */

		/* mark FINALIZED, for next mark-and-sweep (will collect unless has become reachable;
		 * prevent running finalizer again if reachable)
		 */
		DUK_HEAPHDR_SET_FINALIZED(curr);

		/* queue back to heap_allocated */
		next = DUK_HEAPHDR_GET_NEXT(curr);
		DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr);

		curr = next;
#ifdef DUK_USE_DEBUG
		count++;
#endif
	}

	/* finalize_list will always be processed completely */
	heap->finalize_list = NULL;

#ifdef DUK_USE_DEBUG
	DUK_D(DUK_DPRINT("mark-and-sweep finalize objects: %d finalizers called", count));
#endif
}
Exemple #5
0
static void duk__init_object_parts(duk_heap *heap, duk_hobject *obj, int hobject_flags) {
#ifdef DUK_USE_EXPLICIT_NULL_INIT
	obj->p = NULL;
#endif

	/* FIXME: macro? sets both heaphdr and object flags */
	obj->hdr.h_flags = hobject_flags;
	DUK_HEAPHDR_SET_TYPE(&obj->hdr, DUK_HTYPE_OBJECT);  /* also goes into flags */

        DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &obj->hdr);

	/*
	 *  obj->p is intentionally left as NULL, and duk_hobject_props.c must deal
	 *  with this properly.  This is intentional: empty objects consume a minimum
	 *  amount of memory.  Further, an initial allocation might fail and cause
	 *  'obj' to "leak" (require a mark-and-sweep) since it is not reachable yet.
	 */
}
Exemple #6
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' */
}
Exemple #7
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;
}
Exemple #8
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;
}