コード例 #1
0
ファイル: duk_api_call.c プロジェクト: OakLabsInc/duktape
DUK_EXTERNAL void duk_call(duk_context *ctx, duk_idx_t nargs) {
	duk_hthread *thr = (duk_hthread *) ctx;
	duk_small_uint_t call_flags;
	duk_idx_t idx_func;

	DUK_ASSERT_CTX_VALID(ctx);
	DUK_ASSERT(thr != NULL);

	idx_func = duk_get_top(ctx) - nargs - 1;
	if (idx_func < 0 || nargs < 0) {
		/* note that we can't reliably pop anything here */
		DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_CALL_ARGS);
	}

	/* XXX: awkward; we assume there is space for this, overwrite
	 * directly instead?
	 */
	duk_push_undefined(ctx);
	duk_insert(ctx, idx_func + 1);

	call_flags = 0;  /* not protected, respect reclimit, not constructor */

	duk_handle_call_unprotected(thr,           /* thread */
	                            nargs,         /* num_stack_args */
	                            call_flags);   /* call_flags */
}
コード例 #2
0
DUK_INTERNAL duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) {
	duk_hstring *res = duk_heap_string_intern(thr->heap, str, blen);
	if (!res) {
		DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "failed to intern string");
	}
	return res;
}
コード例 #3
0
ファイル: duk_hobject_alloc.c プロジェクト: BpLife/duktape
/* FIXME: unused now, remove */
duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, int hobject_flags) {
	duk_hobject *res = duk_hobject_alloc(thr->heap, hobject_flags);
	if (!res) {
		DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "failed to allocate an object");
	}
	return res;
}
コード例 #4
0
ファイル: duk_bi_number.c プロジェクト: cherry-wb/duktape
static duk_double_t duk__push_this_number_plain(duk_context *ctx) {
	duk_hobject *h;

	/* Number built-in accepts a plain number or a Number object (whose
	 * internal value is operated on).  Other types cause TypeError.
	 */

	duk_push_this(ctx);
	if (duk_is_number(ctx, -1)) {
		DUK_DDD(DUK_DDDPRINT("plain number value: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
		goto done;
	}
	h = duk_get_hobject(ctx, -1);
	if (!h || 
	    (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_NUMBER)) {
		DUK_DDD(DUK_DDDPRINT("unacceptable this value: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
		DUK_ERROR((duk_hthread *) ctx, DUK_ERR_TYPE_ERROR, "expected a number");
	}
	duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
	DUK_ASSERT(duk_is_number(ctx, -1));
	DUK_DDD(DUK_DDDPRINT("number object: %!T, internal value: %!T",
	                     (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
	duk_remove(ctx, -2);

 done:
	return duk_get_number(ctx, -1);
}
コード例 #5
0
ファイル: duk_api_call.c プロジェクト: OakLabsInc/duktape
DUK_EXTERNAL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t index) {
	duk_hthread *thr = (duk_hthread *) ctx;
	duk_tval *tv;
	duk_hobject *h;

	DUK_ASSERT_CTX_VALID(ctx);

	tv = duk_require_tval(ctx, index);
	if (DUK_TVAL_IS_OBJECT(tv)) {
		h = DUK_TVAL_GET_OBJECT(tv);
		DUK_ASSERT(h != NULL);
		if (!DUK_HOBJECT_HAS_NATIVEFUNCTION(h)) {
			goto type_error;
		}
		return (duk_int_t) ((duk_hnativefunction *) h)->magic;
	} else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
		duk_small_uint_t lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
		return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
	}

	/* fall through */
 type_error:
	DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_UNEXPECTED_TYPE);
	return 0;
}
コード例 #6
0
ファイル: duk_hthread_stacks.c プロジェクト: BpLife/duktape
void duk_hthread_catchstack_grow(duk_hthread *thr) {
	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, "catchstack limit");
	}

	DUK_DDPRINT("growing catchstack %d -> %d", old_size, new_size);

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

	thr->catchstack = (duk_catcher *) DUK_REALLOC_INDIRECT_CHECKED(thr, duk_hthread_get_catchstack_ptr, (void *) thr, sizeof(duk_catcher) * new_size);
	thr->catchstack_size = new_size;

	/* note: any entries above the catchstack top are garbage and not zeroed */
}
コード例 #7
0
DUK_INTERNAL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val) {
	duk_hstring *res = duk_heap_string_intern_u32(thr->heap, val);
	if (!res) {
		DUK_ERROR(thr, DUK_ERR_ALLOC_ERROR, "failed to intern string");
	}
	return res;
}
コード例 #8
0
ファイル: duk_api_buffer.c プロジェクト: iotcafe/duktape
DUK_EXTERNAL void *duk_steal_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
	duk_hthread *thr = (duk_hthread *) ctx;
	duk_hbuffer_dynamic *h;
	void *ptr;
	duk_size_t sz;

	DUK_ASSERT(ctx != NULL);

	h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, index);
	DUK_ASSERT(h != NULL);

	if (!DUK_HBUFFER_HAS_DYNAMIC(h)) {
		DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_BUFFER_NOT_DYNAMIC);
	}

	/* Forget the previous allocation, setting size to 0 and alloc to
	 * NULL.  Caller is responsible for freeing the previous allocation.
	 * Getting the allocation and clearing it is done in the same API
	 * call to avoid any chance of a realloc.
	 */
	ptr = DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h);
	sz = DUK_HBUFFER_DYNAMIC_GET_SIZE(h);
	if (out_size) {
		*out_size = sz;
	}
	DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(thr->heap, h);
	DUK_HBUFFER_DYNAMIC_SET_SIZE(h, 0);
	DUK_HBUFFER_DYNAMIC_SET_ALLOC_SIZE(h, 0);

	return ptr;
}
コード例 #9
0
ファイル: duk_bi_array.c プロジェクト: OakLabsInc/duktape
DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32_limited(duk_context *ctx) {
	/* Range limited to [0, 0x7fffffff] range, i.e. range that can be
	 * represented with duk_int32_t.  Use this when the method doesn't
	 * handle the full 32-bit unsigned range correctly.
	 */
	duk_uint32_t ret = duk__push_this_obj_len_u32(ctx);
	if (DUK_UNLIKELY(ret >= 0x80000000UL)) {
		DUK_ERROR((duk_hthread *) ctx, DUK_ERR_INTERNAL_ERROR, DUK_STR_ARRAY_LENGTH_OVER_2G);
	}
	return ret;
}
コード例 #10
0
/* Push 'this' binding, check that it is a Date object; then push the
 * internal time value.  At the end, stack is: [ ... this timeval ].
 * Returns the time value.  Local time adjustment is done if requested.
 */
static double push_this_and_get_timeval_tzoffset(duk_context *ctx, int flags, int *out_tzoffset) {
	duk_hthread *thr = (duk_hthread *) ctx;
	duk_hobject *h;
	double d;
	int tzoffset = 0;

	duk_push_this(ctx);
	h = duk_get_hobject(ctx, -1);  /* FIXME: getter with class check, useful in built-ins */
	if (h == NULL || DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_DATE) {
		DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "expected Date");
	}

	duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
	d = duk_to_number(ctx, -1);
	duk_pop(ctx);

	if (DUK_ISNAN(d)) {
		if (flags & FLAG_NAN_TO_ZERO) {
			d = 0.0;
		}
		if (flags & FLAG_NAN_TO_RANGE_ERROR) {
			DUK_ERROR(thr, DUK_ERR_RANGE_ERROR, "Invalid Date");
		}
	}
	/* if no NaN handling flag, may still be NaN here, but not Inf */
	DUK_ASSERT(!DUK_ISINF(d));

	if (flags & FLAG_LOCALTIME) {
		/* Note: DST adjustment is determined using UTC time.
		 * If 'd' is NaN, tzoffset will be 0.
		 */
		tzoffset = GET_LOCAL_TZOFFSET(d);  /* seconds */
		d += tzoffset * 1000;
	}
	if (out_tzoffset) {
		*out_tzoffset = tzoffset;
	}

	/* [ ... this ] */
	return d;
}
コード例 #11
0
ファイル: duk_js_ops.c プロジェクト: bihai/duk4vb
/*
 *  CheckObjectCoercible()  (E5 Section 9.10)
 *
 *  Note: no API equivalent now.
 */

#if 0  /* unused */
DUK_INTERNAL void duk_js_checkobjectcoercible(duk_hthread *thr, duk_tval *tv_x) {
	duk_small_uint_t tag = DUK_TVAL_GET_TAG(tv_x);

	/* Note: this must match ToObject() behavior */

	if (tag == DUK_TAG_UNDEFINED ||
	    tag == DUK_TAG_NULL ||
	    tag == DUK_TAG_POINTER ||
	    tag == DUK_TAG_BUFFER) {
		DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "not object coercible");
	}
}
コード例 #12
0
ファイル: duk_hthread_stacks.c プロジェクト: 3009420/civetweb
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 */
}
コード例 #13
0
/* Get current Ecmascript time (= UNIX/Posix time, but in milliseconds). */
static double get_now_timeval_gettimeofday(duk_context *ctx) {
	duk_hthread *thr = (duk_hthread *) ctx;
	struct timeval tv;
	double d;

	if (gettimeofday(&tv, NULL) != 0) {
		DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "gettimeofday failed");
	}

	d = ((double) tv.tv_sec) * 1000.0 +
	    ((double) (tv.tv_usec / 1000));
	DUK_ASSERT(floor(d) == d);  /* no fractions */

	return d;
}
コード例 #14
0
ファイル: duk_bi_date_unix.c プロジェクト: janneo/duktape
/* Get current Ecmascript time (= UNIX/Posix time, but in milliseconds). */
DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx) {
	duk_hthread *thr = (duk_hthread *) ctx;
	struct timeval tv;
	duk_double_t d;

	if (gettimeofday(&tv, NULL) != 0) {
		DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "gettimeofday failed");
	}

	d = ((duk_double_t) tv.tv_sec) * 1000.0 +
	    ((duk_double_t) (tv.tv_usec / 1000));
	DUK_ASSERT(DUK_FLOOR(d) == d);  /* no fractions */

	return d;
}
コード例 #15
0
DUK_LOCAL duk_uint32_t duk__parse_regexp_flags(duk_hthread *thr, duk_hstring *h) {
	const duk_uint8_t *p;
	const duk_uint8_t *p_end;
	duk_uint32_t flags = 0;

	p = DUK_HSTRING_GET_DATA(h);
	p_end = p + DUK_HSTRING_GET_BYTELEN(h);

	/* Note: can be safely scanned as bytes (undecoded) */

	while (p < p_end) {
		duk_uint8_t c = *p++;
		switch ((int) c) {
		case (int) 'g': {
			if (flags & DUK_RE_FLAG_GLOBAL) {
				goto error;
			}
			flags |= DUK_RE_FLAG_GLOBAL;
			break;
		}
		case (int) 'i': {
			if (flags & DUK_RE_FLAG_IGNORE_CASE) {
				goto error;
			}
			flags |= DUK_RE_FLAG_IGNORE_CASE;
			break;
		}
		case (int) 'm': {
			if (flags & DUK_RE_FLAG_MULTILINE) {
				goto error;
			}
			flags |= DUK_RE_FLAG_MULTILINE;
			break;
		}
		default: {
			goto error;
		}
		}
	}

	return flags;

 error:
	DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, DUK_STR_INVALID_REGEXP_FLAGS);
	return 0;  /* never here */
}
コード例 #16
0
ファイル: duk_heap_memory.c プロジェクト: andoma/duktape
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;
}
コード例 #17
0
ファイル: duk_api_buffer.c プロジェクト: BpLife/duktape
void *duk_resize_buffer(duk_context *ctx, duk_idx_t index, duk_size_t new_size) {
	duk_hthread *thr = (duk_hthread *) ctx;
	duk_hbuffer_dynamic *h;

	DUK_ASSERT(ctx != NULL);

	h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, index);
	DUK_ASSERT(h != NULL);

	if (!DUK_HBUFFER_HAS_DYNAMIC(h)) {
		DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "buffer is not dynamic");
	}

	/* maximum size check is handled by callee */
	duk_hbuffer_resize(thr, h, new_size, new_size);  /* snug */

	return DUK_HBUFFER_DYNAMIC_GET_CURR_DATA_PTR(h);
}
コード例 #18
0
ファイル: duk_heap_memory.c プロジェクト: andoma/duktape
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;
}
コード例 #19
0
ファイル: duk_api_call.c プロジェクト: OakLabsInc/duktape
DUK_EXTERNAL void duk_call_method(duk_context *ctx, duk_idx_t nargs) {
	duk_hthread *thr = (duk_hthread *) ctx;
	duk_small_uint_t call_flags;
	duk_idx_t idx_func;

	DUK_ASSERT_CTX_VALID(ctx);
	DUK_ASSERT(thr != NULL);

	idx_func = duk_get_top(ctx) - nargs - 2;  /* must work for nargs <= 0 */
	if (idx_func < 0 || nargs < 0) {
		/* note that we can't reliably pop anything here */
		DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_CALL_ARGS);
	}

	call_flags = 0;  /* not protected, respect reclimit, not constructor */

	duk_handle_call_unprotected(thr,           /* thread */
	                            nargs,         /* num_stack_args */
	                            call_flags);   /* call_flags */
}
コード例 #20
0
ファイル: duk_api_call.c プロジェクト: OakLabsInc/duktape
DUK_EXTERNAL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function func, duk_idx_t nargs, duk_idx_t nrets) {
	duk_hthread *thr = (duk_hthread *) ctx;
	duk_int_t rc;

	DUK_ASSERT_CTX_VALID(ctx);
	DUK_ASSERT(thr != NULL);

	if (duk_get_top(ctx) < nargs || nrets < 0) {
		/* See comments in duk_pcall(). */
		DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_CALL_ARGS);
		return DUK_EXEC_ERROR;  /* unreachable */
	}

	rc = duk_handle_safe_call(thr,           /* thread */
	                          func,          /* func */
	                          nargs,         /* num_stack_args */
	                          nrets);        /* num_stack_res */

	return rc;
}
コード例 #21
0
ファイル: duk_api_bytecode.c プロジェクト: smalleric/duktape
DUK_EXTERNAL void duk_load_function(duk_context *ctx) {
	duk_hthread *thr;
	duk_uint8_t *p_buf, *p, *p_end;
	duk_size_t sz;

	DUK_ASSERT(ctx != NULL);
	thr = (duk_hthread *) ctx;
	DUK_UNREF(ctx);

	p_buf = (duk_uint8_t *) duk_require_buffer(ctx, -1, &sz);
	DUK_ASSERT(p_buf != NULL);

	/* The caller is responsible for being sure that bytecode being loaded
	 * is valid and trusted.  Invalid bytecode can cause memory unsafe
	 * behavior directly during loading or later during bytecode execution
	 * (instruction validation would be quite complex to implement).
	 *
	 * This signature check is the only sanity check for detecting
	 * accidental invalid inputs.  The initial 0xFF byte ensures no
	 * ordinary string will be accepted by accident.
	 */
	p = p_buf;
	p_end = p_buf + sz;
	if (sz < 2 || p[0] != DUK__SER_MARKER || p[1] != DUK__SER_VERSION) {
		goto format_error;
	}
	p += 2;

	p = duk__load_func(ctx, p, p_end);
	if (p == NULL) {
		goto format_error;
	}

	duk_remove(ctx, -2);  /* [ ... buf func ] -> [ ... func ] */
	return;

 format_error:
	DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_DECODE_FAILED);
}
コード例 #22
0
ファイル: duk_api_call.c プロジェクト: OakLabsInc/duktape
DUK_EXTERNAL duk_int_t duk_pcall(duk_context *ctx, duk_idx_t nargs) {
	duk_hthread *thr = (duk_hthread *) ctx;
	duk_small_uint_t call_flags;
	duk_idx_t idx_func;
	duk_int_t rc;

	DUK_ASSERT_CTX_VALID(ctx);
	DUK_ASSERT(thr != NULL);

	idx_func = duk_get_top(ctx) - nargs - 1;  /* must work for nargs <= 0 */
	if (idx_func < 0 || nargs < 0) {
		/* We can't reliably pop anything here because the stack input
		 * shape is incorrect.  So we throw an error; if the caller has
		 * no catch point for this, a fatal error will occur.  Another
		 * alternative would be to just return an error.  But then the
		 * stack would be in an unknown state which might cause some
		 * very hard to diagnose problems later on.  Also note that even
		 * if we did not throw an error here, the underlying call handler
		 * might STILL throw an out-of-memory error or some other internal
		 * fatal error.
		 */
		DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_CALL_ARGS);
		return DUK_EXEC_ERROR;  /* unreachable */
	}

	/* awkward; we assume there is space for this */
	duk_push_undefined(ctx);
	duk_insert(ctx, idx_func + 1);

	call_flags = 0;  /* respect reclimit, not constructor */

	rc = duk_handle_call_protected(thr,           /* thread */
	                               nargs,         /* num_stack_args */
	                               call_flags);   /* call_flags */

	return rc;
}
コード例 #23
0
ファイル: duk_api_call.c プロジェクト: OakLabsInc/duktape
DUK_EXTERNAL duk_int_t duk_pcall_method(duk_context *ctx, duk_idx_t nargs) {
	duk_hthread *thr = (duk_hthread *) ctx;
	duk_small_uint_t call_flags;
	duk_idx_t idx_func;
	duk_int_t rc;

	DUK_ASSERT_CTX_VALID(ctx);
	DUK_ASSERT(thr != NULL);

	idx_func = duk_get_top(ctx) - nargs - 2;  /* must work for nargs <= 0 */
	if (idx_func < 0 || nargs < 0) {
		/* See comments in duk_pcall(). */
		DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_INVALID_CALL_ARGS);
		return DUK_EXEC_ERROR;  /* unreachable */
	}

	call_flags = 0;  /* respect reclimit, not constructor */

	rc = duk_handle_call_protected(thr,           /* thread */
	                               nargs,         /* num_stack_args */
	                               call_flags);   /* call_flags */

	return rc;
}
コード例 #24
0
ファイル: duk_api_compile.c プロジェクト: bihai/duk4vb
/* Helper which can be called both directly and with duk_safe_call(). */
DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx) {
	duk_hthread *thr = (duk_hthread *) ctx;
	duk__compile_raw_args *comp_args;
	duk_uint_t flags;
	duk_small_uint_t comp_flags;
	duk_hcompiledfunction *h_templ;

	/* Note: strictness is not inherited from the current Duktape/C
	 * context.  Otherwise it would not be possible to compile
	 * non-strict code inside a Duktape/C activation (which is
	 * always strict now).  See api-testcases/test-eval-strictness.c
	 * for discussion.
	 */

	/* [ ... source? filename &comp_args ] (depends on flags) */

	comp_args = (duk__compile_raw_args *) duk_require_pointer(ctx, -1);
	flags = comp_args->flags;
	duk_pop(ctx);

	/* [ ... source? filename ] */

	if (!comp_args->src_buffer) {
		duk_hstring *h_sourcecode;

		h_sourcecode = duk_get_hstring(ctx, -2);
		if ((flags & DUK_COMPILE_NOSOURCE) ||  /* args incorrect */
		    (h_sourcecode == NULL)) {          /* e.g. duk_push_file_string_raw() pushed undefined */
			/* XXX: when this error is caused by a nonexistent
			 * file given to duk_peval_file() or similar, the
			 * error message is not the best possible.
			 */
			DUK_ERROR(thr, DUK_ERR_API_ERROR, DUK_STR_NO_SOURCECODE);
		}
		DUK_ASSERT(h_sourcecode != NULL);
		comp_args->src_buffer = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode);
		comp_args->src_length = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode);
	}
	DUK_ASSERT(comp_args->src_buffer != NULL);

	/* XXX: unnecessary translation of flags */
	comp_flags = 0;
	if (flags & DUK_COMPILE_EVAL) {
		comp_flags |= DUK_JS_COMPILE_FLAG_EVAL;
	}
	if (flags & DUK_COMPILE_FUNCTION) {
		comp_flags |= DUK_JS_COMPILE_FLAG_EVAL |
		              DUK_JS_COMPILE_FLAG_FUNCEXPR;
	}
	if (flags & DUK_COMPILE_STRICT) {
		comp_flags |= DUK_JS_COMPILE_FLAG_STRICT;
	}

	/* [ ... source? filename ] */

	duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, comp_flags);

	/* [ ... source? func_template ] */

	if (flags & DUK_COMPILE_NOSOURCE) {
		;
	} else {
		duk_remove(ctx, -2);
	}

	/* [ ... func_template ] */

	h_templ = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
	DUK_ASSERT(h_templ != NULL);
	duk_js_push_closure(thr,
	                   h_templ,
	                   thr->builtins[DUK_BIDX_GLOBAL_ENV],
	                   thr->builtins[DUK_BIDX_GLOBAL_ENV]);
	duk_remove(ctx, -2);   /* -> [ ... closure ] */

	/* [ ... closure ] */

	return 1;
}
コード例 #25
0
DUK_INTERNAL void duk_regexp_compile(duk_hthread *thr) {
	duk_context *ctx = (duk_context *) thr;
	duk_re_compiler_ctx re_ctx;
	duk_lexer_point lex_point;
	duk_hstring *h_pattern;
	duk_hstring *h_flags;
	duk__re_disjunction_info ign_disj;

	DUK_ASSERT(thr != NULL);
	DUK_ASSERT(ctx != NULL);

	/*
	 *  Args validation
	 */

	/* TypeError if fails */
	h_pattern = duk_require_hstring(ctx, -2);
	h_flags = duk_require_hstring(ctx, -1);

	/*
	 *  Create normalized 'source' property (E5 Section 15.10.3).
	 */

	/* [ ... pattern flags ] */

	duk__create_escaped_source(thr, -2);

	/* [ ... pattern flags escaped_source ] */

	/*
	 *  Init compilation context
	 */

	/* [ ... pattern flags escaped_source buffer ] */

	DUK_MEMZERO(&re_ctx, sizeof(re_ctx));
	DUK_LEXER_INITCTX(&re_ctx.lex);  /* duplicate zeroing, expect for (possible) NULL inits */
	re_ctx.thr = thr;
	re_ctx.lex.thr = thr;
	re_ctx.lex.input = DUK_HSTRING_GET_DATA(h_pattern);
	re_ctx.lex.input_length = DUK_HSTRING_GET_BYTELEN(h_pattern);
	re_ctx.lex.token_limit = DUK_RE_COMPILE_TOKEN_LIMIT;
	re_ctx.recursion_limit = DUK_USE_REGEXP_COMPILER_RECLIMIT;
	re_ctx.re_flags = duk__parse_regexp_flags(thr, h_flags);

	DUK_BW_INIT_PUSHBUF(thr, &re_ctx.bw, DUK__RE_INITIAL_BUFSIZE);

	DUK_DD(DUK_DDPRINT("regexp compiler ctx initialized, flags=0x%08lx, recursion_limit=%ld",
	                   (unsigned long) re_ctx.re_flags, (long) re_ctx.recursion_limit));

	/*
	 *  Init lexer
	 */

	lex_point.offset = 0;  /* expensive init, just want to fill window */
	lex_point.line = 1;
	DUK_LEXER_SETPOINT(&re_ctx.lex, &lex_point);

	/*
	 *  Compilation
	 */

	DUK_D(DUK_DPRINT("starting regexp compilation"));

	duk__append_u32(&re_ctx, DUK_REOP_SAVE);
	duk__append_u32(&re_ctx, 0);
	duk__parse_disjunction(&re_ctx, 1 /*expect_eof*/, &ign_disj);
	duk__append_u32(&re_ctx, DUK_REOP_SAVE);
	duk__append_u32(&re_ctx, 1);
	duk__append_u32(&re_ctx, DUK_REOP_MATCH);

	/*
	 *  Check for invalid backreferences; note that it is NOT an error
	 *  to back-reference a capture group which has not yet been introduced
	 *  in the pattern (as in /\1(foo)/); in fact, the backreference will
	 *  always match!  It IS an error to back-reference a capture group
	 *  which will never be introduced in the pattern.  Thus, we can check
	 *  for such references only after parsing is complete.
	 */

	if (re_ctx.highest_backref > re_ctx.captures) {
		DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, DUK_STR_INVALID_BACKREFS);
	}

	/*
	 *  Emit compiled regexp header: flags, ncaptures
	 *  (insertion order inverted on purpose)
	 */

	duk__insert_u32(&re_ctx, 0, (re_ctx.captures + 1) * 2);
	duk__insert_u32(&re_ctx, 0, re_ctx.re_flags);

	/* [ ... pattern flags escaped_source buffer ] */

	DUK_BW_COMPACT(thr, &re_ctx.bw);
	duk_to_string(ctx, -1);  /* coerce to string */

	/* [ ... pattern flags escaped_source bytecode ] */

	/*
	 *  Finalize stack
	 */

	duk_remove(ctx, -4);     /* -> [ ... flags escaped_source bytecode ] */
	duk_remove(ctx, -3);     /* -> [ ... escaped_source bytecode ] */

	DUK_D(DUK_DPRINT("regexp compilation successful, bytecode: %!T, escaped source: %!T",
	                 (duk_tval *) duk_get_tval(ctx, -1), (duk_tval *) duk_get_tval(ctx, -2)));
}
コード例 #26
0
ファイル: duk_js_ops.c プロジェクト: bihai/duk4vb
DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
	duk_context *ctx = (duk_context *) thr;
	duk_hobject *func;
	duk_hobject *val;
	duk_hobject *proto;
	duk_uint_t sanity;

	/*
	 *  Get the values onto the stack first.  It would be possible to cover
	 *  some normal cases without resorting to the value stack.
	 *
	 *  The right hand side could be a light function (as they generally
	 *  behave like objects).  Light functions never have a 'prototype'
	 *  property so E5.1 Section 15.3.5.3 step 3 always throws a TypeError.
	 *  Using duk_require_hobject() is thus correct (except for error msg).
	 */

	duk_push_tval(ctx, tv_x);
	duk_push_tval(ctx, tv_y);
	func = duk_require_hobject(ctx, -1);

	/*
	 *  For bound objects, [[HasInstance]] just calls the target function
	 *  [[HasInstance]].  If that is again a bound object, repeat until
	 *  we find a non-bound Function object.
	 */

	/* XXX: this bound function resolution also happens elsewhere,
	 * move into a shared helper.
	 */

	sanity = DUK_HOBJECT_BOUND_CHAIN_SANITY;
	do {
		/* check func supports [[HasInstance]] (this is checked for every function
		 * in the bound chain, including the final one)
		 */

		if (!DUK_HOBJECT_IS_CALLABLE(func)) {
			/*
			 *  Note: of native Ecmascript objects, only Function instances
			 *  have a [[HasInstance]] internal property.  Custom objects might
			 *  also have it, but not in current implementation.
			 *
			 *  XXX: add a separate flag, DUK_HOBJECT_FLAG_ALLOW_INSTANCEOF?
			 */
			DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, "invalid instanceof rval");
		}

		if (!DUK_HOBJECT_HAS_BOUND(func)) {
			break;
		}

		/* [ ... lval rval ] */

		duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET);         /* -> [ ... lval rval new_rval ] */
		duk_replace(ctx, -1);                                        /* -> [ ... lval new_rval ] */
		func = duk_require_hobject(ctx, -1);

		/* func support for [[HasInstance]] checked in the beginning of the loop */
	} while (--sanity > 0);

	if (sanity == 0) {
		DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, DUK_STR_BOUND_CHAIN_LIMIT);
	}

	/*
	 *  'func' is now a non-bound object which supports [[HasInstance]]
	 *  (which here just means DUK_HOBJECT_FLAG_CALLABLE).  Move on
	 *  to execute E5 Section 15.3.5.3.
	 */

	DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
	DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(func));

	/* [ ... lval rval(func) ] */

	/* Handle lightfuncs through object coercion for now. */
	/* XXX: direct implementation */
	val = duk_get_hobject_or_lfunc_coerce(ctx, -2);
	if (!val) {
		goto pop_and_false;
	}

	duk_get_prop_stridx(ctx, -1, DUK_STRIDX_PROTOTYPE);  /* -> [ ... lval rval rval.prototype ] */
	proto = duk_require_hobject(ctx, -1);
	duk_pop(ctx);  /* -> [ ... lval rval ] */

	sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
	do {
		/*
		 *  Note: prototype chain is followed BEFORE first comparison.  This
		 *  means that the instanceof lval is never itself compared to the
		 *  rval.prototype property.  This is apparently intentional, see E5
		 *  Section 15.3.5.3, step 4.a.
		 *
		 *  Also note:
		 *
		 *      js> (function() {}) instanceof Function
		 *      true
		 *      js> Function instanceof Function
		 *      true
		 *
		 *  For the latter, h_proto will be Function.prototype, which is the
		 *  built-in Function prototype.  Because Function.[[Prototype]] is
		 *  also the built-in Function prototype, the result is true.
		 */

		val = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, val);

		if (!val) {
			goto pop_and_false;
		} else if (val == proto) {
			goto pop_and_true;
		}

		/* follow prototype chain */
	} while (--sanity > 0);

	if (sanity == 0) {
		DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
	}
	DUK_UNREACHABLE();

 pop_and_false:
	duk_pop_2(ctx);
	return 0;

 pop_and_true:
	duk_pop_2(ctx);
	return 1;
}
コード例 #27
0
DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset) {
    duk_heap *heap;
    duk_strcache *sce;
    duk_uint_fast32_t byte_offset;
    duk_small_int_t i;
    duk_bool_t use_cache;
    duk_uint_fast32_t dist_start, dist_end, dist_sce;
    duk_uint8_t *p_start;
    duk_uint8_t *p_end;
    duk_uint8_t *p_found;

    if (char_offset > DUK_HSTRING_GET_CHARLEN(h)) {
        goto error;
    }

    /*
     *  For ASCII strings, the answer is simple.
     */

    if (DUK_HSTRING_IS_ASCII(h)) {
        /* clen == blen -> pure ascii */
        return char_offset;
    }

    /*
     *  For non-ASCII strings, we need to scan forwards or backwards
     *  from some starting point.  The starting point may be the start
     *  or end of the string, or some cached midpoint in the string
     *  cache.
     *
     *  For "short" strings we simply scan without checking or updating
     *  the cache.  For longer strings we check and update the cache as
     *  necessary, inserting a new cache entry if none exists.
     */

    DUK_DDD(DUK_DDDPRINT("non-ascii string %p, char_offset=%ld, clen=%ld, blen=%ld",
                         (void *) h, (long) char_offset,
                         (long) DUK_HSTRING_GET_CHARLEN(h),
                         (long) DUK_HSTRING_GET_BYTELEN(h)));

    heap = thr->heap;
    sce = NULL;
    use_cache = (DUK_HSTRING_GET_CHARLEN(h) > DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT);

    if (use_cache) {
#ifdef DUK_USE_DDDPRINT
        DUK_DDD(DUK_DDDPRINT("stringcache before char2byte (using cache):"));
        for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
            duk_strcache *c = heap->strcache + i;
            DUK_DDD(DUK_DDDPRINT("  [%ld] -> h=%p, cidx=%ld, bidx=%ld",
                                 (long) i, (void *) c->h, (long) c->cidx, (long) c->bidx));
        }
#endif

        for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
            duk_strcache *c = heap->strcache + i;

            if (c->h == h) {
                sce = c;
                break;
            }
        }
    }

    /*
     *  Scan from shortest distance:
     *    - start of string
     *    - end of string
     *    - cache entry (if exists)
     */

    DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h) >= char_offset);
    dist_start = char_offset;
    dist_end = DUK_HSTRING_GET_CHARLEN(h) - char_offset;
    dist_sce = 0;
    DUK_UNREF(dist_sce);  /* initialize for debug prints, needed if sce==NULL */

    p_start = (duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
    p_end = (duk_uint8_t *) (p_start + DUK_HSTRING_GET_BYTELEN(h));
    p_found = NULL;

    if (sce) {
        if (char_offset >= sce->cidx) {
            dist_sce = char_offset - sce->cidx;
            if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) {
                DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
                                     "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
                                     "scan forwards from sce",
                                     (long) use_cache, (void *) (sce ? sce->h : NULL),
                                     (sce ? (long) sce->cidx : (long) -1),
                                     (sce ? (long) sce->bidx : (long) -1),
                                     (long) dist_start, (long) dist_end, (long) dist_sce));

                p_found = duk__scan_forwards(p_start + sce->bidx,
                                             p_end,
                                             dist_sce);
                goto scan_done;
            }
        } else {
            dist_sce = sce->cidx - char_offset;
            if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) {
                DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
                                     "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
                                     "scan backwards from sce",
                                     (long) use_cache, (void *) (sce ? sce->h : NULL),
                                     (sce ? (long) sce->cidx : (long) -1),
                                     (sce ? (long) sce->bidx : (long) -1),
                                     (long) dist_start, (long) dist_end, (long) dist_sce));

                p_found = duk__scan_backwards(p_start + sce->bidx,
                                              p_start,
                                              dist_sce);
                goto scan_done;
            }
        }
    }

    /* no sce, or sce scan not best */

    if (dist_start <= dist_end) {
        DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
                             "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
                             "scan forwards from string start",
                             (long) use_cache, (void *) (sce ? sce->h : NULL),
                             (sce ? (long) sce->cidx : (long) -1),
                             (sce ? (long) sce->bidx : (long) -1),
                             (long) dist_start, (long) dist_end, (long) dist_sce));

        p_found = duk__scan_forwards(p_start,
                                     p_end,
                                     dist_start);
    } else {
        DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
                             "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
                             "scan backwards from string end",
                             (long) use_cache, (void *) (sce ? sce->h : NULL),
                             (sce ? (long) sce->cidx : (long) -1),
                             (sce ? (long) sce->bidx : (long) -1),
                             (long) dist_start, (long) dist_end, (long) dist_sce));

        p_found = duk__scan_backwards(p_end,
                                      p_start,
                                      dist_end);
    }

scan_done:

    if (!p_found) {
        /* Scan error: this shouldn't normally happen; it could happen if
         * string is not valid UTF-8 data, and clen/blen are not consistent
         * with the scanning algorithm.
         */
        goto error;
    }

    DUK_ASSERT(p_found >= p_start);
    DUK_ASSERT(p_found <= p_end);  /* may be equal */
    byte_offset = (duk_uint32_t) (p_found - p_start);

    DUK_DDD(DUK_DDDPRINT("-> string %p, cidx %ld -> bidx %ld",
                         (void *) h, (long) char_offset, (long) byte_offset));

    /*
     *  Update cache entry (allocating if necessary), and move the
     *  cache entry to the first place (in an "LRU" policy).
     */

    if (use_cache) {
        /* update entry, allocating if necessary */
        if (!sce) {
            sce = heap->strcache + DUK_HEAP_STRCACHE_SIZE - 1;  /* take last entry */
            sce->h = h;
        }
        DUK_ASSERT(sce != NULL);
        sce->bidx = (duk_uint32_t) (p_found - p_start);
        sce->cidx = (duk_uint32_t) char_offset;

        /* LRU: move our entry to first */
        if (sce > &heap->strcache[0]) {
            /*
             *   A                  C
             *   B                  A
             *   C <- sce    ==>    B
             *   D                  D
             */
            duk_strcache tmp;

            tmp = *sce;
            DUK_MEMMOVE((void *) (&heap->strcache[1]),
                        (void *) (&heap->strcache[0]),
                        (size_t) (((char *) sce) - ((char *) &heap->strcache[0])));
            heap->strcache[0] = tmp;

            /* 'sce' points to the wrong entry here, but is no longer used */
        }
#ifdef DUK_USE_DDDPRINT
        DUK_DDD(DUK_DDDPRINT("stringcache after char2byte (using cache):"));
        for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
            duk_strcache *c = heap->strcache + i;
            DUK_DDD(DUK_DDDPRINT("  [%ld] -> h=%p, cidx=%ld, bidx=%ld",
                                 (long) i, (void *) c->h, (long) c->cidx, (long) c->bidx));
        }
#endif
    }

    return byte_offset;

error:
    DUK_ERROR(thr, DUK_ERR_INTERNAL_ERROR, "string scan error");
    return 0;
}
コード例 #28
0
ファイル: duk_hbuffer_ops.c プロジェクト: BpLife/duktape
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);
}
コード例 #29
0
ファイル: duk_api_call.c プロジェクト: OakLabsInc/duktape
DUK_EXTERNAL void duk_new(duk_context *ctx, duk_idx_t nargs) {
	/*
	 *  There are two [[Construct]] operations in the specification:
	 *
	 *    - E5 Section 13.2.2: for Function objects
	 *    - E5 Section 15.3.4.5.2: for "bound" Function objects
	 *
	 *  The chain of bound functions is resolved in Section 15.3.4.5.2,
	 *  with arguments "piling up" until the [[Construct]] internal
	 *  method is called on the final, actual Function object.  Note
	 *  that the "prototype" property is looked up *only* from the
	 *  final object, *before* calling the constructor.
	 *
	 *  Currently we follow the bound function chain here to get the
	 *  "prototype" property value from the final, non-bound function.
	 *  However, we let duk_handle_call() handle the argument "piling"
	 *  when the constructor is called.  The bound function chain is
	 *  thus now processed twice.
	 *
	 *  When constructing new Array instances, an unnecessary object is
	 *  created and discarded now: the standard [[Construct]] creates an
	 *  object, and calls the Array constructor.  The Array constructor
	 *  returns an Array instance, which is used as the result value for
	 *  the "new" operation; the object created before the Array constructor
	 *  call is discarded.
	 *
	 *  This would be easy to fix, e.g. by knowing that the Array constructor
	 *  will always create a replacement object and skip creating the fallback
	 *  object in that case.
	 *
	 *  Note: functions called via "new" need to know they are called as a
	 *  constructor.  For instance, built-in constructors behave differently
	 *  depending on how they are called.
	 */

	/* XXX: merge this with duk_js_call.c, as this function implements
	 * core semantics (or perhaps merge the two files altogether).
	 */

	duk_hthread *thr = (duk_hthread *) ctx;
	duk_hobject *proto;
	duk_hobject *cons;
	duk_hobject *fallback;
	duk_idx_t idx_cons;
	duk_small_uint_t call_flags;

	DUK_ASSERT_CTX_VALID(ctx);

	/* [... constructor arg1 ... argN] */

	idx_cons = duk_require_normalize_index(ctx, -nargs - 1);

	DUK_DDD(DUK_DDDPRINT("top=%ld, nargs=%ld, idx_cons=%ld",
	                     (long) duk_get_top(ctx), (long) nargs, (long) idx_cons));

	/* XXX: code duplication */

	/*
	 *  Figure out the final, non-bound constructor, to get "prototype"
	 *  property.
	 */

	duk_dup(ctx, idx_cons);
	for (;;) {
		cons = duk_get_hobject(ctx, -1);
		if (cons == NULL || !DUK_HOBJECT_HAS_CONSTRUCTABLE(cons)) {
			/* Checking constructability from anything else than the
			 * initial constructor is not strictly necessary, but a
			 * nice sanity check.
			 */
			goto not_constructable;
		}
		if (!DUK_HOBJECT_HAS_BOUND(cons)) {
			break;
		}
		duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET);  /* -> [... cons target] */
		duk_remove(ctx, -2);                                  /* -> [... target] */
	}
	DUK_ASSERT(cons != NULL && !DUK_HOBJECT_HAS_BOUND(cons));

	/* [... constructor arg1 ... argN final_cons] */

	/*
	 *  Create "fallback" object to be used as the object instance,
	 *  unless the constructor returns a replacement value.
	 *  Its internal prototype needs to be set based on "prototype"
	 *  property of the constructor.
	 */

	duk_push_object(ctx);  /* class Object, extensible */

	/* [... constructor arg1 ... argN final_cons fallback] */

	duk_get_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE);
	proto = duk_get_hobject(ctx, -1);
	if (!proto) {
		DUK_DDD(DUK_DDDPRINT("constructor has no 'prototype' property, or value not an object "
		                     "-> leave standard Object prototype as fallback prototype"));
	} else {
		DUK_DDD(DUK_DDDPRINT("constructor has 'prototype' property with object value "
		                     "-> set fallback prototype to that value: %!iO", (duk_heaphdr *) proto));
		fallback = duk_get_hobject(ctx, -2);
		DUK_ASSERT(fallback != NULL);
		DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, fallback, proto);
	}
	duk_pop(ctx);

	/* [... constructor arg1 ... argN final_cons fallback] */

	/*
	 *  Manipulate callstack for the call.
	 */

	duk_dup_top(ctx);
	duk_insert(ctx, idx_cons + 1);  /* use fallback as 'this' value */
	duk_insert(ctx, idx_cons);      /* also stash it before constructor,
	                                 * in case we need it (as the fallback value)
	                                 */
	duk_pop(ctx);                   /* pop final_cons */


	/* [... fallback constructor fallback(this) arg1 ... argN];
	 * Note: idx_cons points to first 'fallback', not 'constructor'.
	 */

	DUK_DDD(DUK_DDDPRINT("before call, idx_cons+1 (constructor) -> %!T, idx_cons+2 (fallback/this) -> %!T, "
	                     "nargs=%ld, top=%ld",
	                     (duk_tval *) duk_get_tval(ctx, idx_cons + 1),
	                     (duk_tval *) duk_get_tval(ctx, idx_cons + 2),
	                     (long) nargs,
	                     (long) duk_get_top(ctx)));

	/*
	 *  Call the constructor function (called in "constructor mode").
	 */

	call_flags = DUK_CALL_FLAG_CONSTRUCTOR_CALL;  /* not protected, respect reclimit, is a constructor call */

	duk_handle_call_unprotected(thr,           /* thread */
	                            nargs,         /* num_stack_args */
	                            call_flags);   /* call_flags */

	/* [... fallback retval] */

	DUK_DDD(DUK_DDDPRINT("constructor call finished, fallback=%!iT, retval=%!iT",
	                     (duk_tval *) duk_get_tval(ctx, -2),
	                     (duk_tval *) duk_get_tval(ctx, -1)));

	/*
	 *  Determine whether to use the constructor return value as the created
	 *  object instance or not.
	 */

	if (duk_is_object(ctx, -1)) {
		duk_remove(ctx, -2);
	} else {
		duk_pop(ctx);
	}

	/*
	 *  Augment created errors upon creation (not when they are thrown or
	 *  rethrown).  __FILE__ and __LINE__ are not desirable here; the call
	 *  stack reflects the caller which is correct.
	 */

#ifdef DUK_USE_AUGMENT_ERROR_CREATE
	duk_hthread_sync_currpc(thr);
	duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/);
#endif

	/* [... retval] */

	return;

 not_constructable:
	DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_CONSTRUCTABLE);
}
コード例 #30
0
ファイル: duk_api_object.c プロジェクト: 3009420/civetweb
/* Object.defineProperty() equivalent C binding. */
DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t flags) {
	duk_hthread *thr = (duk_hthread *) ctx;
	duk_idx_t idx_base;
	duk_hobject *obj;
	duk_hstring *key;
	duk_idx_t idx_value;
	duk_hobject *get;
	duk_hobject *set;
	duk_uint_t is_data_desc;
	duk_uint_t is_acc_desc;

	DUK_ASSERT_CTX_VALID(ctx);

	obj = duk_require_hobject(ctx, obj_index);

	is_data_desc = flags & (DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE);
	is_acc_desc = flags & (DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER);
	if (is_data_desc && is_acc_desc) {
		/* "Have" flags must not be conflicting so that they would
		 * apply to both a plain property and an accessor at the same
		 * time.
		 */
		goto fail_invalid_desc;
	}

	idx_base = duk_get_top_index(ctx);
	if (flags & DUK_DEFPROP_HAVE_SETTER) {
		duk_require_type_mask(ctx, idx_base, DUK_TYPE_MASK_UNDEFINED |
		                                     DUK_TYPE_MASK_OBJECT |
		                                     DUK_TYPE_MASK_LIGHTFUNC);
		set = duk_get_hobject_or_lfunc_coerce(ctx, idx_base);
		if (set != NULL && !DUK_HOBJECT_IS_CALLABLE(set)) {
			goto fail_not_callable;
		}
		idx_base--;
	} else {
		set = NULL;
	}
	if (flags & DUK_DEFPROP_HAVE_GETTER) {
		duk_require_type_mask(ctx, idx_base, DUK_TYPE_MASK_UNDEFINED |
		                                     DUK_TYPE_MASK_OBJECT |
		                                     DUK_TYPE_MASK_LIGHTFUNC);
		get = duk_get_hobject_or_lfunc_coerce(ctx, idx_base);
		if (get != NULL && !DUK_HOBJECT_IS_CALLABLE(get)) {
			goto fail_not_callable;
		}
		idx_base--;
	} else {
		get = NULL;
	}
	if (flags & DUK_DEFPROP_HAVE_VALUE) {
		idx_value = idx_base;
		idx_base--;
	} else {
		idx_value = (duk_idx_t) -1;
	}
	key = duk_require_hstring(ctx, idx_base);

	duk_require_valid_index(ctx, idx_base);

	duk_hobject_define_property_helper(ctx,
	                                   flags /*defprop_flags*/,
	                                   obj,
	                                   key,
	                                   idx_value,
	                                   get,
	                                   set);

	/* Clean up stack */

	duk_set_top(ctx, idx_base);

	/* [ ... obj ... ] */

	return;

 fail_invalid_desc:
	DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_DESCRIPTOR);
	return;

 fail_not_callable:
	DUK_ERROR(thr, DUK_ERR_TYPE_ERROR, DUK_STR_NOT_CALLABLE);
	return;
}