Title: [87586] trunk/Source/_javascript_Core
Revision
87586
Author
gga...@apple.com
Date
2011-05-27 16:53:36 -0700 (Fri, 27 May 2011)

Log Message

2011-05-27  Geoffrey Garen  <gga...@apple.com>

        Reviewed by Oliver Hunt.

        Property caching is too aggressive for API objects
        https://bugs.webkit.org/show_bug.cgi?id=61677

        * API/JSCallbackObject.h: Opt in to ProhibitsPropertyCaching, since our
        callback APIs allow the client to change its mind about our propertis at
        any time.

        * API/tests/testapi.c:
        (PropertyCatchalls_getProperty):
        (PropertyCatchalls_setProperty):
        (PropertyCatchalls_getPropertyNames):
        (PropertyCatchalls_class):
        (main):
        * API/tests/testapi.js: Some tests for dynamic API objects.

        * interpreter/Interpreter.cpp:
        (JSC::Interpreter::tryCachePutByID):
        (JSC::Interpreter::tryCacheGetByID):
        * jit/JITStubs.cpp:
        (JSC::JITThunks::tryCachePutByID):
        (JSC::JITThunks::tryCacheGetByID):
        (JSC::DEFINE_STUB_FUNCTION): Opt out of property caching if the client
        requires it.

        * runtime/JSTypeInfo.h:
        (JSC::TypeInfo::TypeInfo):
        (JSC::TypeInfo::isFinal):
        (JSC::TypeInfo::prohibitsPropertyCaching):
        (JSC::TypeInfo::flags): Added a flag to track opting out of property
        caching. Fixed an "&&" vs "&" typo that was previously harmless, but
        is now harmful since m_flags2 can have more than one bit set.

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/API/JSCallbackObject.h (87585 => 87586)


--- trunk/Source/_javascript_Core/API/JSCallbackObject.h	2011-05-27 23:34:03 UTC (rev 87585)
+++ trunk/Source/_javascript_Core/API/JSCallbackObject.h	2011-05-27 23:53:36 UTC (rev 87586)
@@ -149,7 +149,7 @@
     }
 
 protected:
-    static const unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | OverridesHasInstance | OverridesVisitChildren | OverridesGetPropertyNames | Base::StructureFlags;
+    static const unsigned StructureFlags = ProhibitsPropertyCaching | OverridesGetOwnPropertySlot | ImplementsHasInstance | OverridesHasInstance | OverridesVisitChildren | OverridesGetPropertyNames | Base::StructureFlags;
 
 private:
     virtual UString className() const;

Modified: trunk/Source/_javascript_Core/API/tests/testapi.c (87585 => 87586)


--- trunk/Source/_javascript_Core/API/tests/testapi.c	2011-05-27 23:34:03 UTC (rev 87585)
+++ trunk/Source/_javascript_Core/API/tests/testapi.c	2011-05-27 23:53:36 UTC (rev 87586)
@@ -355,6 +355,111 @@
     return jsClass;
 }
 
+static JSValueRef PropertyCatchalls_getProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
+{
+    UNUSED_PARAM(context);
+    UNUSED_PARAM(object);
+    UNUSED_PARAM(propertyName);
+    UNUSED_PARAM(exception);
+
+    if (JSStringIsEqualToUTF8CString(propertyName, "x")) {
+        static size_t count;
+        if (count++ < 5)
+            return NULL;
+
+        // Swallow all .x gets after 5, returning null.
+        return JSValueMakeNull(context);
+    }
+
+    if (JSStringIsEqualToUTF8CString(propertyName, "y")) {
+        static size_t count;
+        if (count++ < 5)
+            return NULL;
+
+        // Swallow all .y gets after 5, returning null.
+        return JSValueMakeNull(context);
+    }
+    
+    if (JSStringIsEqualToUTF8CString(propertyName, "z")) {
+        static size_t count;
+        if (count++ < 5)
+            return NULL;
+
+        // Swallow all .y gets after 5, returning null.
+        return JSValueMakeNull(context);
+    }
+
+    return NULL;
+}
+
+static bool PropertyCatchalls_setProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception)
+{
+    UNUSED_PARAM(context);
+    UNUSED_PARAM(object);
+    UNUSED_PARAM(propertyName);
+    UNUSED_PARAM(value);
+    UNUSED_PARAM(exception);
+
+    if (JSStringIsEqualToUTF8CString(propertyName, "x")) {
+        static size_t count;
+        if (count++ < 5)
+            return false;
+
+        // Swallow all .x sets after 4.
+        return true;
+    }
+
+    return false;
+}
+
+static void PropertyCatchalls_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames)
+{
+    UNUSED_PARAM(context);
+    UNUSED_PARAM(object);
+
+    static size_t count;
+    static const char* numbers[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+    
+    // Provide a property of a different name every time.
+    JSStringRef propertyName = JSStringCreateWithUTF8CString(numbers[count++ % 10]);
+    JSPropertyNameAccumulatorAddName(propertyNames, propertyName);
+    JSStringRelease(propertyName);
+}
+
+JSClassDefinition PropertyCatchalls_definition = {
+    0,
+    kJSClassAttributeNone,
+    
+    "PropertyCatchalls",
+    NULL,
+    
+    NULL,
+    NULL,
+    
+    NULL,
+    NULL,
+    NULL,
+    PropertyCatchalls_getProperty,
+    PropertyCatchalls_setProperty,
+    NULL,
+    PropertyCatchalls_getPropertyNames,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+};
+
+static JSClassRef PropertyCatchalls_class(JSContextRef context)
+{
+    UNUSED_PARAM(context);
+
+    static JSClassRef jsClass;
+    if (!jsClass)
+        jsClass = JSClassCreate(&PropertyCatchalls_definition);
+    
+    return jsClass;
+}
+
 static bool EvilExceptionObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception)
 {
     UNUSED_PARAM(context);
@@ -922,6 +1027,11 @@
     ASSERT(JSValueGetType(context, jsCFEmptyString) == kJSTypeString);
     ASSERT(JSValueGetType(context, jsCFEmptyStringWithCharacters) == kJSTypeString);
 
+    JSObjectRef propertyCatchalls = JSObjectMake(context, PropertyCatchalls_class(context), NULL);
+    JSStringRef propertyCatchallsString = JSStringCreateWithUTF8CString("PropertyCatchalls");
+    JSObjectSetProperty(context, globalObject, propertyCatchallsString, propertyCatchalls, kJSPropertyAttributeNone, NULL);
+    JSStringRelease(propertyCatchallsString);
+
     JSObjectRef myObject = JSObjectMake(context, MyObject_class(context), NULL);
     JSStringRef myObjectIString = JSStringCreateWithUTF8CString("MyObject");
     JSObjectSetProperty(context, globalObject, myObjectIString, myObject, kJSPropertyAttributeNone, NULL);

Modified: trunk/Source/_javascript_Core/API/tests/testapi.js (87585 => 87586)


--- trunk/Source/_javascript_Core/API/tests/testapi.js	2011-05-27 23:34:03 UTC (rev 87585)
+++ trunk/Source/_javascript_Core/API/tests/testapi.js	2011-05-27 23:53:36 UTC (rev 87586)
@@ -246,6 +246,32 @@
 
 shouldBe("EmptyObject", "[object CallbackObject]");
 
+for (var i = 0; i < 6; ++i)
+    PropertyCatchalls.x = i;
+shouldBe("PropertyCatchalls.x", 4);
+
+for (var i = 0; i < 6; ++i)
+    var x = PropertyCatchalls.x;
+shouldBe("x", null);
+
+for (var i = 0; i < 10; ++i) {
+    for (var p in PropertyCatchalls) {
+        if (p == "x")
+            continue;
+        shouldBe("p", i % 10);
+        break;
+    }
+}
+
+PropertyCatchalls.__proto__ = { y: 1 };
+for (var i = 0; i < 6; ++i)
+    var y = PropertyCatchalls.y;
+shouldBe("y", null);
+
+var o = { __proto__: PropertyCatchalls };
+for (var i = 0; i < 6; ++i)
+    var z = PropertyCatchalls.z;
+shouldBe("z", null);
+
 if (failed)
     throw "Some tests failed";
-

Modified: trunk/Source/_javascript_Core/ChangeLog (87585 => 87586)


--- trunk/Source/_javascript_Core/ChangeLog	2011-05-27 23:34:03 UTC (rev 87585)
+++ trunk/Source/_javascript_Core/ChangeLog	2011-05-27 23:53:36 UTC (rev 87586)
@@ -1,3 +1,39 @@
+2011-05-27  Geoffrey Garen  <gga...@apple.com>
+
+        Reviewed by Oliver Hunt.
+
+        Property caching is too aggressive for API objects
+        https://bugs.webkit.org/show_bug.cgi?id=61677
+
+        * API/JSCallbackObject.h: Opt in to ProhibitsPropertyCaching, since our
+        callback APIs allow the client to change its mind about our propertis at
+        any time.
+
+        * API/tests/testapi.c:
+        (PropertyCatchalls_getProperty):
+        (PropertyCatchalls_setProperty):
+        (PropertyCatchalls_getPropertyNames):
+        (PropertyCatchalls_class):
+        (main):
+        * API/tests/testapi.js: Some tests for dynamic API objects.
+
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::tryCachePutByID):
+        (JSC::Interpreter::tryCacheGetByID):
+        * jit/JITStubs.cpp:
+        (JSC::JITThunks::tryCachePutByID):
+        (JSC::JITThunks::tryCacheGetByID):
+        (JSC::DEFINE_STUB_FUNCTION): Opt out of property caching if the client
+        requires it.
+
+        * runtime/JSTypeInfo.h:
+        (JSC::TypeInfo::TypeInfo):
+        (JSC::TypeInfo::isFinal):
+        (JSC::TypeInfo::prohibitsPropertyCaching):
+        (JSC::TypeInfo::flags): Added a flag to track opting out of property
+        caching. Fixed an "&&" vs "&" typo that was previously harmless, but
+        is now harmful since m_flags2 can have more than one bit set.
+
 2011-05-27  Stephanie Lewis  <sle...@apple.com>
 
         Unreviewed.

Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.cpp (87585 => 87586)


--- trunk/Source/_javascript_Core/interpreter/Interpreter.cpp	2011-05-27 23:34:03 UTC (rev 87585)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.cpp	2011-05-27 23:53:36 UTC (rev 87586)
@@ -1239,7 +1239,7 @@
     JSCell* baseCell = baseValue.asCell();
     Structure* structure = baseCell->structure();
 
-    if (structure->isUncacheableDictionary()) {
+    if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching()) {
         vPC[0] = getOpcode(op_put_by_id_generic);
         return;
     }
@@ -1327,7 +1327,7 @@
 
     Structure* structure = baseValue.asCell()->structure();
 
-    if (structure->isUncacheableDictionary()) {
+    if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching()) {
         vPC[0] = getOpcode(op_get_by_id_generic);
         return;
     }

Modified: trunk/Source/_javascript_Core/jit/JITStubs.cpp (87585 => 87586)


--- trunk/Source/_javascript_Core/jit/JITStubs.cpp	2011-05-27 23:34:03 UTC (rev 87585)
+++ trunk/Source/_javascript_Core/jit/JITStubs.cpp	2011-05-27 23:53:36 UTC (rev 87586)
@@ -819,7 +819,7 @@
     JSCell* baseCell = baseValue.asCell();
     Structure* structure = baseCell->structure();
 
-    if (structure->isUncacheableDictionary()) {
+    if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching()) {
         ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic));
         return;
     }
@@ -887,7 +887,7 @@
     JSCell* baseCell = baseValue.asCell();
     Structure* structure = baseCell->structure();
 
-    if (structure->isUncacheableDictionary()) {
+    if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching()) {
         ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic));
         return;
     }
@@ -1722,7 +1722,7 @@
 
     CHECK_FOR_EXCEPTION();
 
-    if (!baseValue.isCell() || !slot.isCacheable() || baseValue.asCell()->structure()->isDictionary()) {
+    if (!baseValue.isCell() || !slot.isCacheable() || baseValue.asCell()->structure()->isDictionary() || baseValue.asCell()->structure()->typeInfo().prohibitsPropertyCaching()) {
         ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail));
         return JSValue::encode(result);
     }

Modified: trunk/Source/_javascript_Core/runtime/JSTypeInfo.h (87585 => 87586)


--- trunk/Source/_javascript_Core/runtime/JSTypeInfo.h	2011-05-27 23:34:03 UTC (rev 87585)
+++ trunk/Source/_javascript_Core/runtime/JSTypeInfo.h	2011-05-27 23:53:36 UTC (rev 87586)
@@ -34,8 +34,7 @@
 
 namespace JSC {
 
-    // WebCore uses MasqueradesAsUndefined to make document.all and style.filter undetectable.
-    static const unsigned MasqueradesAsUndefined = 1;
+    static const unsigned MasqueradesAsUndefined = 1; // WebCore uses MasqueradesAsUndefined to make document.all and style.filter undetectable.
     static const unsigned ImplementsHasInstance = 1 << 1;
     static const unsigned OverridesHasInstance = 1 << 2;
     static const unsigned ImplementsDefaultHasInstance = 1 << 3;
@@ -44,16 +43,17 @@
     static const unsigned OverridesVisitChildren = 1 << 6;
     static const unsigned OverridesGetPropertyNames = 1 << 7;
     static const unsigned IsJSFinalObject = 1 << 8;
+    static const unsigned ProhibitsPropertyCaching = 1 << 9;
 
     class TypeInfo {
     public:
         TypeInfo(JSType type, unsigned flags = 0)
             : m_type(type)
-            , m_flags(flags & 0xFF)
+            , m_flags(flags & 0xff)
             , m_flags2(flags >> 8)
         {
-            ASSERT(flags <= 0x1FF);
-            ASSERT(type <= 0xFF);
+            ASSERT(flags <= 0x3ff);
+            ASSERT(type <= 0xff);
             ASSERT(type >= CompoundType || !(flags & OverridesVisitChildren));
             // ImplementsDefaultHasInstance means (ImplementsHasInstance & !OverridesHasInstance)
             if ((m_flags & (ImplementsHasInstance | OverridesHasInstance)) == ImplementsHasInstance)
@@ -69,8 +69,9 @@
         bool overridesGetOwnPropertySlot() const { return m_flags & OverridesGetOwnPropertySlot; }
         bool overridesVisitChildren() const { return m_flags & OverridesVisitChildren; }
         bool overridesGetPropertyNames() const { return m_flags & OverridesGetPropertyNames; }
+        unsigned isFinal() const { return m_flags2 & (IsJSFinalObject >> 8); }
+        unsigned prohibitsPropertyCaching() const { return m_flags2 & (ProhibitsPropertyCaching >> 8); }
         unsigned flags() const { return m_flags; }
-        unsigned isFinal() const { return m_flags2 && (IsJSFinalObject >> 8); }
 
         static ptrdiff_t flagsOffset()
         {
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to