diff --git a/src/duk_js_call.c b/src/duk_js_call.c index 513303c7..080b031d 100644 --- a/src/duk_js_call.c +++ b/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; } }