Esempio n. 1
0
/* Shared helper to implement ES6 Object.setPrototypeOf and
 * Object.prototype.__proto__ setter.
 *
 * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-get-object.prototype.__proto__
 * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.setprototypeof
 */
duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx) {
	duk_hthread *thr = (duk_hthread *) ctx;
	duk_hobject *h_obj;
	duk_hobject *h_new_proto;
	duk_hobject *h_curr;
	duk_ret_t ret_success = 1;  /* retval for success path */

	/* Preliminaries for __proto__ and setPrototypeOf (E6 19.1.2.18 steps 1-4);
	 * magic: 0=setter call, 1=Object.setPrototypeOf
	 */
	if (duk_get_current_magic(ctx) == 0) {
		duk_push_this_check_object_coercible(ctx);
		duk_insert(ctx, 0);
		if (!duk_check_type_mask(ctx, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT)) {
			return 0;
		}

		/* __proto__ setter returns 'undefined' on success unlike the
		 * setPrototypeOf() call which returns the target object.
		 */
		ret_success = 0;
	} else {
		duk_require_object_coercible(ctx, 0);
		duk_require_type_mask(ctx, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT);
	}
	h_obj = duk_get_hobject(ctx, 0);
	if (!h_obj) {
		goto skip;
	}
	h_new_proto = duk_get_hobject(ctx, 1);
	DUK_ASSERT(h_obj != NULL);
	/* h_new_proto may be NULL */

	/* [[SetPrototypeOf]] standard behavior, E6 9.1.2 */
	/* NOTE: steps 7-8 seem to be a cut-paste bug in the E6 draft */
	/* TODO: implement Proxy object support here */

	if (h_new_proto == h_obj->prototype) {
		goto skip;
	}
	if (!DUK_HOBJECT_HAS_EXTENSIBLE(h_obj)) {
		goto fail_nonextensible;
	}
	for (h_curr = h_new_proto; h_curr != NULL; h_curr = h_curr->prototype) {
		/* Loop prevention */
		if (h_curr == h_obj) {
			goto fail_loop;
		}
	}
	DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h_obj, h_new_proto);
	/* fall thru */

 skip:
	duk_set_top(ctx, 1);
	return ret_success;

 fail_nonextensible:
 fail_loop:
	return DUK_RET_TYPE_ERROR;
}
Esempio n. 2
0
/* Shared helper to implement ES2015 Object.setPrototypeOf,
 * Object.prototype.__proto__ setter, and Reflect.setPrototypeOf.
 *
 * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__
 * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-object.setprototypeof
 */
DUK_INTERNAL duk_ret_t duk_bi_object_setprototype_shared(duk_hthread *thr) {
	/*
	 *  magic = 0: __proto__ setter
	 *  magic = 1: Object.setPrototypeOf()
	 *  magic = 2: Reflect.setPrototypeOf()
	 */

	duk_hobject *h_obj;
	duk_hobject *h_new_proto;
	duk_hobject *h_curr;
	duk_ret_t ret_success = 1;  /* retval for success path */
	duk_uint_t mask;
	duk_int_t magic;

	/* Preliminaries for __proto__ and setPrototypeOf (E6 19.1.2.18 steps 1-4). */
	magic = duk_get_current_magic(thr);
	if (magic == 0) {
		duk_push_this_check_object_coercible(thr);
		duk_insert(thr, 0);
		if (!duk_check_type_mask(thr, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT)) {
			return 0;
		}

		/* __proto__ setter returns 'undefined' on success unlike the
		 * setPrototypeOf() call which returns the target object.
		 */
		ret_success = 0;
	} else {
		if (magic == 1) {
			duk_require_object_coercible(thr, 0);
		} else {
			duk_require_hobject_accept_mask(thr, 0,
			                                DUK_TYPE_MASK_LIGHTFUNC |
			                                DUK_TYPE_MASK_BUFFER);
		}
		duk_require_type_mask(thr, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT);
	}

	h_new_proto = duk_get_hobject(thr, 1);
	/* h_new_proto may be NULL */

	mask = duk_get_type_mask(thr, 0);
	if (mask & (DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER)) {
		duk_hobject *curr_proto;
		curr_proto = thr->builtins[(mask & DUK_TYPE_MASK_LIGHTFUNC) ?
		                               DUK_BIDX_FUNCTION_PROTOTYPE :
		                               DUK_BIDX_UINT8ARRAY_PROTOTYPE];
		if (h_new_proto == curr_proto) {
			goto skip;
		}
		goto fail_nonextensible;
	}
	h_obj = duk_get_hobject(thr, 0);
	if (h_obj == NULL) {
		goto skip;
	}
	DUK_ASSERT(h_obj != NULL);

	/* [[SetPrototypeOf]] standard behavior, E6 9.1.2. */
	/* TODO: implement Proxy object support here */

	if (h_new_proto == DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_obj)) {
		goto skip;
	}
	if (!DUK_HOBJECT_HAS_EXTENSIBLE(h_obj)) {
		goto fail_nonextensible;
	}
	for (h_curr = h_new_proto; h_curr != NULL; h_curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_curr)) {
		/* Loop prevention. */
		if (h_curr == h_obj) {
			goto fail_loop;
		}
	}
	DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h_obj, h_new_proto);
	/* fall thru */

 skip:
	duk_set_top(thr, 1);
	if (magic == 2) {
		duk_push_true(thr);
	}
	return ret_success;

 fail_nonextensible:
 fail_loop:
	if (magic != 2) {
		DUK_DCERROR_TYPE_INVALID_ARGS(thr);
	} else {
		duk_push_false(thr);
		return 1;
	}
}