示例#1
0
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_TYPE_INVALID_ARGS(thr);
		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;
}
示例#2
0
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_TYPE_INVALID_ARGS(thr);
		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;
}
示例#3
0
DUK_LOCAL void duk__err_augment_user(duk_hthread *thr, duk_small_uint_t stridx_cb) {
	duk_context *ctx = (duk_context *) thr;
	duk_tval *tv_hnd;
	duk_small_uint_t call_flags;
	duk_int_t rc;

	DUK_ASSERT(thr != NULL);
	DUK_ASSERT(thr->heap != NULL);
	DUK_ASSERT_DISABLE(stridx_cb >= 0);  /* unsigned */
	DUK_ASSERT(stridx_cb < DUK_HEAP_NUM_STRINGS);

	if (DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap)) {
		DUK_DD(DUK_DDPRINT("recursive call to error handler, ignore"));
		return;
	}

	/*
	 *  Check whether or not we have an error handler.
	 *
	 *  We must be careful of not triggering an error when looking up the
	 *  property.  For instance, if the property is a getter, we don't want
	 *  to call it, only plain values are allowed.  The value, if it exists,
	 *  is not checked.  If the value is not a function, a TypeError happens
	 *  when it is called and that error replaces the original one.
	 */

	DUK_ASSERT_VALSTACK_SPACE(thr, 4);  /* 3 entries actually needed below */

	/* [ ... errval ] */

	if (thr->builtins[DUK_BIDX_DUKTAPE] == NULL) {
		/* When creating built-ins, some of the built-ins may not be set
		 * and we want to tolerate that when throwing errors.
		 */
		DUK_DD(DUK_DDPRINT("error occurred when DUK_BIDX_DUKTAPE is NULL, ignoring"));
		return;
	}
	tv_hnd = duk_hobject_find_existing_entry_tval_ptr(thr->heap,
	                                                  thr->builtins[DUK_BIDX_DUKTAPE],
	                                                  DUK_HTHREAD_GET_STRING(thr, stridx_cb));
	if (tv_hnd == NULL) {
		DUK_DD(DUK_DDPRINT("error handler does not exist or is not a plain value: %!T",
		                   (duk_tval *) tv_hnd));
		return;
	}
	DUK_DDD(DUK_DDDPRINT("error handler dump (callability not checked): %!T",
	                     (duk_tval *) tv_hnd));
	duk_push_tval(ctx, tv_hnd);

	/* [ ... errval errhandler ] */

	duk_insert(ctx, -2);  /* -> [ ... errhandler errval ] */
	duk_push_undefined(ctx);
	duk_insert(ctx, -2);  /* -> [ ... errhandler undefined(= this) errval ] */

	/* [ ... errhandler undefined errval ] */

	/*
	 *  DUK_CALL_FLAG_IGNORE_RECLIMIT causes duk_handle_call() to ignore C
	 *  recursion depth limit (and won't increase it either).  This is
	 *  dangerous, but useful because it allows the error handler to run
	 *  even if the original error is caused by C recursion depth limit.
	 *
	 *  The heap level DUK_HEAP_FLAG_ERRHANDLER_RUNNING is set for the
	 *  duration of the error handler and cleared afterwards.  This flag
	 *  prevents the error handler from running recursively.  The flag is
	 *  heap level so that the flag properly controls even coroutines
	 *  launched by an error handler.  Since the flag is heap level, it is
	 *  critical to restore it correctly.
	 *
	 *  We ignore errors now: a success return and an error value both
	 *  replace the original error value.  (This would be easy to change.)
	 */

	DUK_ASSERT(!DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap));  /* since no recursive error handler calls */
	DUK_HEAP_SET_ERRHANDLER_RUNNING(thr->heap);

	call_flags = DUK_CALL_FLAG_IGNORE_RECLIMIT;  /* ignore reclimit, not constructor */

	rc = duk_handle_call_protected(thr,
	                               1,            /* num args */
	                               call_flags);  /* call_flags */
	DUK_UNREF(rc);  /* no need to check now: both success and error are OK */

	DUK_ASSERT(DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap));
	DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(thr->heap);

	/* [ ... errval ] */
}