From 461c1ef24ea71a3994c931bda8c75c35c66968f5 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Tue, 22 Jan 2013 15:20:35 +0100 Subject: [PATCH] Fix thisObject for all builtin function calls Even when doing var v = Object.prototype.valueOf; v(); the thisObject must not be converted to the global object automatically, i.e. remain null. We previously implemented this lack of conversion for apply() and call(), but it does in fact apply to all built-in functions. Consequently we can get rid of callDirect and the virtual maybeAdjustThisObject function and instead just do the "tweak" with the help of a little boolean. Change-Id: I93bc37f4c6e896d6dcf169aa74953b0e460312ce Reviewed-by: Lars Knoll --- qv4functionobject.cpp | 34 ++++++++++------------------------ qv4functionobject.h | 4 ---- qv4managed.h | 7 ++++--- tests/TestExpectations | 1 - 4 files changed, 14 insertions(+), 32 deletions(-) diff --git a/qv4functionobject.cpp b/qv4functionobject.cpp index 7894888..e5501d8 100644 --- a/qv4functionobject.cpp +++ b/qv4functionobject.cpp @@ -118,18 +118,13 @@ Value FunctionObject::call(ExecutionContext *context, Value thisObject, Value *a ExecutionContext *ctx = needsActivation ? context->engine->newContext() : &k; ctx->initCallContext(context, thisObject, this, args, argc); - Value result = call(ctx); - ctx->leaveCallContext(); - return result; -} - -Value FunctionObject::callDirect(ExecutionContext *context, Value thisObject, Value *args, int argc) -{ - ExecutionContext k; - ExecutionContext *ctx = needsActivation ? context->engine->newContext() : &k; - - ctx->initCallContext(context, thisObject, this, args, argc); - maybeAdjustThisObjectForDirectCall(ctx, thisObject); + if (isBuiltinFunction) { + // Built-in functions allow for the this object to be null or undefined. This overrides + // the behaviour of changing thisObject to the global object if null/undefined and allows + // the built-in functions for example to throw a type error if null is passed. + if (thisObject.isNull() || thisObject.isUndefined()) + ctx->thisObject = thisObject; + } Value result = call(ctx); ctx->leaveCallContext(); return result; @@ -244,7 +239,7 @@ Value FunctionPrototype::method_apply(ExecutionContext *ctx) if (!o) ctx->throwTypeError(); - return o->callDirect(ctx, thisArg, args.data(), args.size()); + return o->call(ctx, thisArg, args.data(), args.size()); } Value FunctionPrototype::method_call(ExecutionContext *ctx) @@ -260,7 +255,7 @@ Value FunctionPrototype::method_call(ExecutionContext *ctx) if (!o) ctx->throwTypeError(); - return o->callDirect(ctx, thisArg, args.data(), args.size()); + return o->call(ctx, thisArg, args.data(), args.size()); } Value FunctionPrototype::method_bind(ExecutionContext *ctx) @@ -353,6 +348,7 @@ BuiltinFunction::BuiltinFunction(ExecutionContext *scope, String *name, Value (* , code(code) { this->name = name; + isBuiltinFunction = true; } Value BuiltinFunction::construct(ExecutionContext *ctx) @@ -361,16 +357,6 @@ Value BuiltinFunction::construct(ExecutionContext *ctx) return Value::undefinedValue(); } -void BuiltinFunction::maybeAdjustThisObjectForDirectCall(ExecutionContext *context, Value thisArg) -{ - // Built-in functions allow for the this object to be null or undefined. This overrides - // the behaviour of changing thisObject to the global object if null/undefined and allows - // the built-in functions for example to throw a type error if null is passed. - if (thisArg.isNull() || thisArg.isUndefined()) - context->thisObject = thisArg; -} - - BoundFunction::BoundFunction(ExecutionContext *scope, FunctionObject *target, Value boundThis, const QVector &boundArgs) : FunctionObject(scope) , target(target) diff --git a/qv4functionobject.h b/qv4functionobject.h index 727361f..912c103 100644 --- a/qv4functionobject.h +++ b/qv4functionobject.h @@ -152,9 +152,6 @@ struct FunctionObject: Object { virtual Value construct(ExecutionContext *context, Value *args, int argc); virtual Value call(ExecutionContext *context, Value thisObject, Value *args, int argc); - // Nothing to do in the default implementation, only _native_ functions might change context->thisObject. - virtual void maybeAdjustThisObjectForDirectCall(ExecutionContext* /*context*/, Value /*thisArg*/) { } - Value callDirect(ExecutionContext *context, Value thisObject, Value *args, int argc); virtual struct ScriptFunction *asScriptFunction() { return 0; } @@ -188,7 +185,6 @@ struct BuiltinFunction: FunctionObject { BuiltinFunction(ExecutionContext *scope, String *name, Value (*code)(ExecutionContext *)); virtual Value call(ExecutionContext *ctx) { return code(ctx); } virtual Value construct(ExecutionContext *ctx); - virtual void maybeAdjustThisObjectForDirectCall(ExecutionContext *context, Value thisArg); }; struct ScriptFunction: FunctionObject { diff --git a/qv4managed.h b/qv4managed.h index a0472cf..c7a5959 100644 --- a/qv4managed.h +++ b/qv4managed.h @@ -64,7 +64,7 @@ private: void operator = (const Managed &other); protected: - Managed() : markBit(0), inUse(1), extensible(true), isArray(false), isString(false), unused(0) { } + Managed() : markBit(0), inUse(1), extensible(true), isArray(false), isString(false), isBuiltinFunction(false), unused(0) { } virtual ~Managed(); public: @@ -82,13 +82,14 @@ protected: quintptr extensible : 1; // used by Object quintptr isArray : 1; // used by Object & Array quintptr isString : 1; // used by Object & StringObject + quintptr isBuiltinFunction : 1; // used by FunctionObject quintptr needsActivation : 1; // used by FunctionObject quintptr usesArgumentsObject : 1; // used by FunctionObject quintptr strictMode : 1; // used by FunctionObject #if CPU(X86_64) - quintptr unused : 56; + quintptr unused : 55; #elif CPU(X86) - quintptr unused : 24; + quintptr unused : 23; #else #error "implement me" #endif diff --git a/tests/TestExpectations b/tests/TestExpectations index dfdd99a..029387c 100644 --- a/tests/TestExpectations +++ b/tests/TestExpectations @@ -596,7 +596,6 @@ S12.9_A1_T7 failing S12.9_A1_T8 failing S12.9_A1_T9 failing S15.2.4.4_A14 failing -S15.2.4.4_A15 failing # Array regressions S15.4.4.4_A1_T2 failing -- 2.7.4