Fix thisObject for all builtin function calls
authorSimon Hausmann <simon.hausmann@digia.com>
Tue, 22 Jan 2013 14:20:35 +0000 (15:20 +0100)
committerLars Knoll <lars.knoll@digia.com>
Tue, 22 Jan 2013 15:14:35 +0000 (16:14 +0100)
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 <lars.knoll@digia.com>
qv4functionobject.cpp
qv4functionobject.h
qv4managed.h
tests/TestExpectations

index 7894888..e5501d8 100644 (file)
@@ -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<Value> &boundArgs)
     : FunctionObject(scope)
     , target(target)
index 727361f..912c103 100644 (file)
@@ -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 {
index a0472cf..c7a5959 100644 (file)
@@ -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
index dfdd99a..029387c 100644 (file)
@@ -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