Browse Source

Direct valstack access for effective 'this' setup

Figuring out an effective 'this' value happens for every call.  The previous
implementation for non-strict functions used stack API calls.  The reworked
implementation accesses the value stack directly which matters for this
performance critical code path.
pull/397/head
Sami Vaarala 9 years ago
parent
commit
4d5abb129b
  1. 65
      src/duk_js_call.c

65
src/duk_js_call.c

@ -617,44 +617,45 @@ void duk__coerce_effective_this_binding(duk_hthread *thr,
duk_hobject *func,
duk_idx_t idx_this) {
duk_context *ctx = (duk_context *) thr;
duk_small_int_t strict;
duk_tval *tv_this;
duk_hobject *obj_global;
if (func) {
strict = DUK_HOBJECT_HAS_STRICT(func);
} else {
if (func == NULL || DUK_HOBJECT_HAS_STRICT(func)) {
/* Lightfuncs are always considered strict. */
strict = 1;
DUK_DDD(DUK_DDDPRINT("this binding: strict -> use directly"));
return;
}
if (strict) {
DUK_DDD(DUK_DDDPRINT("this binding: strict -> use directly"));
} else {
duk_tval *tv_this = duk_require_tval(ctx, idx_this);
duk_hobject *obj_global;
if (DUK_TVAL_IS_OBJECT(tv_this)) {
DUK_DDD(DUK_DDDPRINT("this binding: non-strict, object -> use directly"));
} else if (DUK_TVAL_IS_LIGHTFUNC(tv_this)) {
/* Lightfuncs are treated like objects and not coerced. */
DUK_DDD(DUK_DDDPRINT("this binding: non-strict, lightfunc -> use directly"));
} else if (DUK_TVAL_IS_UNDEFINED(tv_this) || DUK_TVAL_IS_NULL(tv_this)) {
DUK_DDD(DUK_DDDPRINT("this binding: non-strict, undefined/null -> use global object"));
obj_global = thr->builtins[DUK_BIDX_GLOBAL];
if (obj_global) {
duk_push_hobject(ctx, obj_global);
} else {
/*
* This may only happen if built-ins are being "torn down".
* This behavior is out of specification scope.
*/
DUK_D(DUK_DPRINT("this binding: wanted to use global object, but it is NULL -> using undefined instead"));
duk_push_undefined(ctx);
}
duk_replace(ctx, idx_this);
/* XXX: byte offset */
tv_this = thr->valstack_bottom + idx_this;
switch (DUK_TVAL_GET_TAG(tv_this)) {
case DUK_TAG_OBJECT:
case DUK_TAG_LIGHTFUNC: /* lightfuncs are treated like objects and not coerced */
DUK_DDD(DUK_DDDPRINT("this binding: non-strict, object -> use directly"));
break;
case DUK_TAG_UNDEFINED:
case DUK_TAG_NULL:
DUK_DDD(DUK_DDDPRINT("this binding: non-strict, undefined/null -> use global object"));
obj_global = thr->builtins[DUK_BIDX_GLOBAL];
/* XXX: avoid this check somehow */
if (DUK_LIKELY(obj_global != NULL)) {
DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_this)); /* no need to decref previous value */
DUK_TVAL_SET_OBJECT(tv_this, obj_global);
DUK_HOBJECT_INCREF(thr, obj_global);
} else {
DUK_DDD(DUK_DDDPRINT("this binding: non-strict, not object/undefined/null -> use ToObject(value)"));
duk_to_object(ctx, idx_this); /* may have side effects */
/* This may only happen if built-ins are being "torn down".
* This behavior is out of specification scope.
*/
DUK_D(DUK_DPRINT("this binding: wanted to use global object, but it is NULL -> using undefined instead"));
DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_this)); /* no need to decref previous value */
DUK_TVAL_SET_UNDEFINED(tv_this); /* nothing to incref */
}
break;
default:
DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_this));
DUK_DDD(DUK_DDDPRINT("this binding: non-strict, not object/undefined/null -> use ToObject(value)"));
duk_to_object(ctx, idx_this); /* may have side effects */
break;
}
}

Loading…
Cancel
Save