Source/JavaScriptCore:
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 29 Apr 2015 21:27:48 +0000 (21:27 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 29 Apr 2015 21:27:48 +0000 (21:27 +0000)
JSTypeInfo should have an inline type flag to indicate of getCallData() has been overridden
https://bugs.webkit.org/show_bug.cgi?id=144397

Reviewed by Andreas Kling.

Add the flag to JSTypeInfo. It's an inline flag so that it's fast to query. Slap the flag on
callback objects and internal functions. Modify the TypeOf operation to use this flag to avoid
making a getCallData() call if it isn't necessary.

* API/JSCallbackObject.h:
* runtime/InternalFunction.h:
* runtime/JSTypeInfo.h:
(JSC::TypeInfo::typeOfShouldCallGetCallData):
* runtime/Operations.cpp:
(JSC::jsTypeStringForValue):
* tests/stress/type-of-functions-and-objects.js: Added.
(foo):
(bar):
(baz):
(fuzz):
(expect):
(test):

Source/WebCore:
JSTypeInfo should have an inline type flag to indicate of getCallData() has been overridden
https://bugs.webkit.org/show_bug.cgi?id=144397

Reviewed by Andreas Kling.

If you override getCallData() and you want to be called a "function", then you need to use the
new TypeOfShouldCallGetCallData flag.

* bindings/scripts/CodeGeneratorJS.pm:
(GenerateHeader):
* bridge/objc/objc_runtime.h:
* bridge/runtime_method.h:
* bridge/runtime_object.h:

Source/WebKit2:
JSTypeInfo should have an inline type flag to indicate if getCallData() has been overridden
https://bugs.webkit.org/show_bug.cgi?id=144397

Reviewed by Andreas Kling.

If you override getCallData() and you want to be called a "function", then you need to use the
new TypeOfShouldCallGetCallData flag.

* WebProcess/Plugins/Netscape/JSNPObject.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@183575 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
Source/JavaScriptCore/API/JSCallbackObject.h
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/InternalFunction.h
Source/JavaScriptCore/runtime/JSTypeInfo.h
Source/JavaScriptCore/runtime/Operations.cpp
Source/JavaScriptCore/tests/stress/type-of-functions-and-objects.js [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/bridge/objc/objc_runtime.h
Source/WebCore/bridge/runtime_method.h
Source/WebCore/bridge/runtime_object.h
Source/WebKit2/ChangeLog
Source/WebKit2/WebProcess/Plugins/Netscape/JSNPObject.h

index c60c2ef..ea4cfaf 100644 (file)
@@ -125,7 +125,7 @@ protected:
 
 public:
     typedef Parent Base;
-    static const unsigned StructureFlags = Base::StructureFlags | ProhibitsPropertyCaching | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | ImplementsHasInstance | OverridesHasInstance | OverridesGetPropertyNames;
+    static const unsigned StructureFlags = Base::StructureFlags | ProhibitsPropertyCaching | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | ImplementsHasInstance | OverridesHasInstance | OverridesGetPropertyNames | TypeOfShouldCallGetCallData;
 
     ~JSCallbackObject();
 
index 6b4b42b..2e5eb87 100644 (file)
@@ -1,3 +1,28 @@
+2015-04-29  Filip Pizlo  <fpizlo@apple.com>
+
+        JSTypeInfo should have an inline type flag to indicate of getCallData() has been overridden
+        https://bugs.webkit.org/show_bug.cgi?id=144397
+
+        Reviewed by Andreas Kling.
+        
+        Add the flag to JSTypeInfo. It's an inline flag so that it's fast to query. Slap the flag on
+        callback objects and internal functions. Modify the TypeOf operation to use this flag to avoid
+        making a getCallData() call if it isn't necessary.
+
+        * API/JSCallbackObject.h:
+        * runtime/InternalFunction.h:
+        * runtime/JSTypeInfo.h:
+        (JSC::TypeInfo::typeOfShouldCallGetCallData):
+        * runtime/Operations.cpp:
+        (JSC::jsTypeStringForValue):
+        * tests/stress/type-of-functions-and-objects.js: Added.
+        (foo):
+        (bar):
+        (baz):
+        (fuzz):
+        (expect):
+        (test):
+
 2015-04-28  Geoffrey Garen  <ggaren@apple.com>
 
         It shouldn't take 1846 lines of code and 5 FIXMEs to sort an array.
index 79f4791..8b0d09f 100644 (file)
@@ -34,7 +34,7 @@ class FunctionPrototype;
 class InternalFunction : public JSDestructibleObject {
 public:
     typedef JSDestructibleObject Base;
-    static const unsigned StructureFlags = Base::StructureFlags | ImplementsHasInstance;
+    static const unsigned StructureFlags = Base::StructureFlags | ImplementsHasInstance | TypeOfShouldCallGetCallData;
 
     DECLARE_EXPORT_INFO;
 
index 62798c9..27863ab 100644 (file)
@@ -40,6 +40,7 @@ static const unsigned MasqueradesAsUndefined = 1; // WebCore uses MasqueradesAsU
 static const unsigned ImplementsHasInstance = 1 << 1;
 static const unsigned OverridesHasInstance = 1 << 2;
 static const unsigned ImplementsDefaultHasInstance = 1 << 3;
+static const unsigned TypeOfShouldCallGetCallData = 1 << 4; // Need this flag if you override getCallData() and you want typeof to use this to determine if it should say "function". Currently we always set this flag when we override getCallData().
 static const unsigned OverridesGetOwnPropertySlot = 1 << 5;
 static const unsigned InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero = 1 << 6;
 static const unsigned StructureIsImmortal = 1 << 7;
@@ -83,6 +84,7 @@ public:
     bool implementsHasInstance() const { return isSetOnFlags1(ImplementsHasInstance); }
     bool overridesHasInstance() const { return isSetOnFlags1(OverridesHasInstance); }
     bool implementsDefaultHasInstance() const { return isSetOnFlags1(ImplementsDefaultHasInstance); }
+    bool typeOfShouldCallGetCallData() const { return isSetOnFlags1(TypeOfShouldCallGetCallData); }
     bool overridesGetOwnPropertySlot() const { return overridesGetOwnPropertySlot(inlineTypeFlags()); }
     static bool overridesGetOwnPropertySlot(InlineTypeFlags flags) { return flags & OverridesGetOwnPropertySlot; }
     bool interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero() const { return isSetOnFlags1(InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero); }
index 5d6ad01..5732cfd 100644 (file)
@@ -68,14 +68,19 @@ JSValue jsTypeStringForValue(VM& vm, JSGlobalObject* globalObject, JSValue v)
     if (v.isSymbol())
         return vm.smallStrings.symbolString();
     if (v.isObject()) {
+        JSObject* object = asObject(v);
         // Return "undefined" for objects that should be treated
         // as null when doing comparisons.
-        if (asObject(v)->structure(vm)->masqueradesAsUndefined(globalObject))
+        if (object->structure(vm)->masqueradesAsUndefined(globalObject))
             return vm.smallStrings.undefinedString();
-        CallData callData;
-        JSObject* object = asObject(v);
-        if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone)
+        if (object->type() == JSFunctionType)
             return vm.smallStrings.functionString();
+        if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) {
+            CallData callData;
+            JSObject* object = asObject(v);
+            if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone)
+                return vm.smallStrings.functionString();
+        }
     }
     return vm.smallStrings.objectString();
 }
diff --git a/Source/JavaScriptCore/tests/stress/type-of-functions-and-objects.js b/Source/JavaScriptCore/tests/stress/type-of-functions-and-objects.js
new file mode 100644 (file)
index 0000000..ad539fe
--- /dev/null
@@ -0,0 +1,73 @@
+function foo(v) {
+    return typeof v;
+}
+
+function bar(v) {
+    switch (typeof v) {
+    case "object":
+        return 1;
+    case "function":
+        return 2;
+    default:
+        return 3;
+    }
+}
+
+function baz(v) {
+    return typeof v == "function";
+}
+
+function fuzz(v) {
+    return typeof v == "object";
+}
+
+noInline(foo);
+noInline(bar);
+noInline(baz);
+noInline(fuzz);
+
+function expect(f, v, expected) {
+    var result = f(v);
+    if (result != expected)
+        throw "Error: " + f.name + "(" + v + ") returned " + result + " instead of " + expected;
+}
+
+function test(v, expected) {
+    switch (expected) {
+    case "function":
+        expect(foo, v, "function");
+        expect(bar, v, 2);
+        expect(baz, v, true);
+        expect(fuzz, v, false);
+        break;
+    case "object":
+        expect(foo, v, "object");
+        expect(bar, v, 1);
+        expect(baz, v, false);
+        expect(fuzz, v, true);
+        break;
+    case "other":
+        var result = foo(v);
+        if (result == "object" || result == "function")
+            throw "Error: foo(" + v + ") returned " + result + " but expected something other than object or function";
+        expect(bar, v, 3);
+        expect(baz, v, false);
+        expect(fuzz, v, false);
+        break;
+    default:
+        throw "Bad expected case";
+    }
+}
+
+for (var i = 0; i < 10000; ++i) {
+    test({}, "object");
+    test(function() { }, "function");
+    test("hello", "other");
+    test(42, "other");
+    test(null, "object");
+    test(void 0, "other");
+    test(42.5, "other");
+    test(Map, "function");
+    test(Date, "function");
+    test(Map.prototype, "object");
+}
index a1fe496..04a0a71 100644 (file)
@@ -1,3 +1,19 @@
+2015-04-29  Filip Pizlo  <fpizlo@apple.com>
+
+        JSTypeInfo should have an inline type flag to indicate of getCallData() has been overridden
+        https://bugs.webkit.org/show_bug.cgi?id=144397
+
+        Reviewed by Andreas Kling.
+
+        If you override getCallData() and you want to be called a "function", then you need to use the
+        new TypeOfShouldCallGetCallData flag.
+
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateHeader):
+        * bridge/objc/objc_runtime.h:
+        * bridge/runtime_method.h:
+        * bridge/runtime_object.h:
+
 2015-04-29  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r183553 and r183561.
index 515da75..16af889 100644 (file)
@@ -900,6 +900,9 @@ sub GenerateHeader
     if ($interface->extendedAttributes->{"NewImpurePropertyFiresWatchpoints"}) {
         $structureFlags{"JSC::NewImpurePropertyFiresWatchpoints"} = 1;
     }
+    if ($interface->extendedAttributes->{"CustomCall"}) {
+        $structureFlags{"JSC::TypeOfShouldCallGetCallData"} = 1;
+    }
 
     # Getters
     if ($hasGetter) {
index f55116e..7f3a5d9 100644 (file)
@@ -93,7 +93,7 @@ private:
 class ObjcFallbackObjectImp : public JSDestructibleObject {
 public:
     typedef JSDestructibleObject Base;
-    static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+    static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | TypeOfShouldCallGetCallData;
 
     static ObjcFallbackObjectImp* create(ExecState* exec, JSGlobalObject* globalObject, ObjcInstance* instance, const String& propertyName)
     {
index 8ad2743..e3227be 100644 (file)
@@ -35,7 +35,7 @@ namespace JSC {
 class WEBCORE_EXPORT RuntimeMethod : public InternalFunction {
 public:
     typedef InternalFunction Base;
-    static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
+    static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | TypeOfShouldCallGetCallData;
 
     static RuntimeMethod* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, const String& name, Bindings::Method* method)
     {
index 14394c2..69a0628 100644 (file)
@@ -35,7 +35,7 @@ namespace Bindings {
 class WEBCORE_EXPORT RuntimeObject : public JSDestructibleObject {
 public:
     typedef JSDestructibleObject Base;
-    static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames;
+    static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetPropertyNames | TypeOfShouldCallGetCallData;
 
     static RuntimeObject* create(VM& vm, Structure* structure, PassRefPtr<Instance> instance)
     {
index 20f4d78..d7db74d 100644 (file)
@@ -1,3 +1,15 @@
+2015-04-29  Filip Pizlo  <fpizlo@apple.com>
+
+        JSTypeInfo should have an inline type flag to indicate if getCallData() has been overridden
+        https://bugs.webkit.org/show_bug.cgi?id=144397
+
+        Reviewed by Andreas Kling.
+
+        If you override getCallData() and you want to be called a "function", then you need to use the
+        new TypeOfShouldCallGetCallData flag.
+
+        * WebProcess/Plugins/Netscape/JSNPObject.h:
+
 2015-04-29  Antti Koivisto  <antti@apple.com>
 
         ResourceLoadPriority should be enum class
index 757ffbe..f20735c 100644 (file)
@@ -44,7 +44,7 @@ class NPRuntimeObjectMap;
 class JSNPObject : public JSC::JSDestructibleObject {
 public:
     typedef JSC::JSDestructibleObject Base;
-    static const unsigned StructureFlags = Base::StructureFlags | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames;
+    static const unsigned StructureFlags = Base::StructureFlags | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | JSC::TypeOfShouldCallGetCallData;
 
     static JSNPObject* create(JSC::JSGlobalObject* globalObject, NPRuntimeObjectMap* objectMap, NPObject* npObject)
     {