Esempio n. 1
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_TYPE(thr, "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_RANGE(thr, 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 ] */

	DUK_ASSERT(val != NULL);

#if defined(DUK_USE_ES6_PROXY)
	val = duk_hobject_resolve_proxy_target(thr, val);
	DUK_ASSERT(val != NULL);
#endif

	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.
		 */

		DUK_ASSERT(val != NULL);
		val = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, val);

		if (!val) {
			goto pop_and_false;
		}

		DUK_ASSERT(val != NULL);
#if defined(DUK_USE_ES6_PROXY)
		val = duk_hobject_resolve_proxy_target(thr, val);
#endif

		if (val == proto) {
			goto pop_and_true;
		}

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

	if (sanity == 0) {
		DUK_ERROR_RANGE(thr, 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;
}
Esempio n. 2
0
DUK_LOCAL void duk__refcount_finalize_hobject(duk_hthread *thr, duk_hobject *h) {
	duk_uint_fast32_t i;

	DUK_ASSERT(h);
	DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h) == DUK_HTYPE_OBJECT);

	/* XXX: better to get base and walk forwards? */

	for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
		duk_hstring *key = DUK_HOBJECT_E_GET_KEY(thr->heap, h, i);
		if (!key) {
			continue;
		}
		duk_heaphdr_decref(thr, (duk_heaphdr *) key);
		if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h, i)) {
			duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, h, i));
			duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, h, i));
		} else {
			duk_tval_decref(thr, DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h, i));
		}
	}

	for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
		duk_tval_decref(thr, DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, h, i));
	}

	/* hash part is a 'weak reference' and does not contribute */

	duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h));

	if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
		duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
		duk_tval *tv, *tv_end;
		duk_hobject **funcs, **funcs_end;

		DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, f) != NULL);  /* compiled functions must be created 'atomically' */

		tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, f);
		tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, f);
		while (tv < tv_end) {
			duk_tval_decref(thr, tv);
			tv++;
		}

		funcs = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, f);
		funcs_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, f);
		while (funcs < funcs_end) {
			duk_heaphdr_decref(thr, (duk_heaphdr *) *funcs);
			funcs++;
		}

		duk_heaphdr_decref(thr, (duk_heaphdr *) DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, f));
	} else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
		duk_hnativefunction *f = (duk_hnativefunction *) h;
		DUK_UNREF(f);
		/* nothing to finalize */
	} else if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
		duk_hbufferobject *b = (duk_hbufferobject *) h;
		if (b->buf) {
			duk_heaphdr_decref(thr, (duk_heaphdr *) b->buf);
		}
	} else if (DUK_HOBJECT_IS_THREAD(h)) {
		duk_hthread *t = (duk_hthread *) h;
		duk_tval *tv;

		tv = t->valstack;
		while (tv < t->valstack_top) {
			duk_tval_decref(thr, tv);
			tv++;
		}

		for (i = 0; i < (duk_uint_fast32_t) t->callstack_top; i++) {
			duk_activation *act = t->callstack + i;
			duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_ACT_GET_FUNC(act));
			duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) act->var_env);
			duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) act->lex_env);
#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
			duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) act->prev_caller);
#endif
		}

#if 0  /* nothing now */
		for (i = 0; i < (duk_uint_fast32_t) t->catchstack_top; i++) {
			duk_catcher *cat = t->catchstack + i;
		}
#endif

		for (i = 0; i < DUK_NUM_BUILTINS; i++) {
			duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) t->builtins[i]);
		}

		duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) t->resumer);
	}
}