Example #1
0
/* 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;
}
Example #2
0
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;
}