Title: [134813] trunk/Source/_javascript_Core
Revision
134813
Author
[email protected]
Date
2012-11-15 12:20:02 -0800 (Thu, 15 Nov 2012)

Log Message

Structure should be able to easily tell if the prototype chain might intercept a store
https://bugs.webkit.org/show_bug.cgi?id=102326

Reviewed by Geoffrey Garen.

This improves our ability to reason about the correctness of the more optimized
prototype chain walk in JSObject::put(), while also making it straight forward to
check if the prototype chain will do strange things to a property store by just
looking at the structure.

* runtime/JSObject.cpp:
(JSC::JSObject::put):
* runtime/Structure.cpp:
(JSC::Structure::prototypeChainMayInterceptStoreTo):
(JSC):
* runtime/Structure.h:
(Structure):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (134812 => 134813)


--- trunk/Source/_javascript_Core/ChangeLog	2012-11-15 20:04:21 UTC (rev 134812)
+++ trunk/Source/_javascript_Core/ChangeLog	2012-11-15 20:20:02 UTC (rev 134813)
@@ -1,3 +1,23 @@
+2012-11-14  Filip Pizlo  <[email protected]>
+
+        Structure should be able to easily tell if the prototype chain might intercept a store
+        https://bugs.webkit.org/show_bug.cgi?id=102326
+
+        Reviewed by Geoffrey Garen.
+
+        This improves our ability to reason about the correctness of the more optimized
+        prototype chain walk in JSObject::put(), while also making it straight forward to
+        check if the prototype chain will do strange things to a property store by just
+        looking at the structure.
+
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::put):
+        * runtime/Structure.cpp:
+        (JSC::Structure::prototypeChainMayInterceptStoreTo):
+        (JSC):
+        * runtime/Structure.h:
+        (Structure):
+
 2012-11-15  Thiago Marcos P. Santos  <[email protected]>
 
         [CMake] Do not regenerate LLIntAssembly.h on every incremental build

Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (134812 => 134813)


--- trunk/Source/_javascript_Core/runtime/JSObject.cpp	2012-11-15 20:04:21 UTC (rev 134812)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp	2012-11-15 20:20:02 UTC (rev 134813)
@@ -356,26 +356,30 @@
         putByIndex(thisObject, exec, i, value, slot.isStrictMode());
         return;
     }
-
+    
     // Check if there are any setters or getters in the prototype chain
     JSValue prototype;
     if (propertyName != exec->propertyNames().underscoreProto) {
         for (JSObject* obj = thisObject; !obj->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) {
             prototype = obj->prototype();
             if (prototype.isNull()) {
-                if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getCallableObject(value)) && slot.isStrictMode())
+                ASSERT(!thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->globalData(), propertyName));
+                if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getCallableObject(value))
+                    && slot.isStrictMode())
                     throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
                 return;
             }
         }
     }
 
-    for (JSObject* obj = thisObject; ; obj = asObject(prototype)) {
+    JSObject* obj;
+    for (obj = thisObject; ; obj = asObject(prototype)) {
         unsigned attributes;
         JSCell* specificValue;
         PropertyOffset offset = obj->structure()->get(globalData, propertyName, attributes, specificValue);
         if (isValidOffset(offset)) {
             if (attributes & ReadOnly) {
+                ASSERT(thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->globalData(), propertyName) || obj == thisObject);
                 if (slot.isStrictMode())
                     throwError(exec, createTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError)));
                 return;
@@ -383,6 +387,8 @@
 
             JSValue gs = obj->getDirectOffset(offset);
             if (gs.isGetterSetter()) {
+                ASSERT(attributes & Accessor);
+                ASSERT(thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->globalData(), propertyName) || obj == thisObject);
                 JSObject* setterFunc = asGetterSetter(gs)->setter();        
                 if (!setterFunc) {
                     if (slot.isStrictMode())
@@ -398,7 +404,8 @@
                 // If this is WebCore's global object then we need to substitute the shell.
                 call(exec, setterFunc, callType, callData, thisObject->methodTable()->toThisObject(thisObject, exec), args);
                 return;
-            }
+            } else
+                ASSERT(!(attributes & Accessor));
 
             // If there's an existing property on the object or one of its 
             // prototypes it should be replaced, so break here.
@@ -410,6 +417,7 @@
             break;
     }
     
+    ASSERT(!thisObject->structure()->prototypeChainMayInterceptStoreTo(exec->globalData(), propertyName) || obj == thisObject);
     if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getCallableObject(value)) && slot.isStrictMode())
         throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
     return;

Modified: trunk/Source/_javascript_Core/runtime/Structure.cpp (134812 => 134813)


--- trunk/Source/_javascript_Core/runtime/Structure.cpp	2012-11-15 20:04:21 UTC (rev 134812)
+++ trunk/Source/_javascript_Core/runtime/Structure.cpp	2012-11-15 20:20:02 UTC (rev 134813)
@@ -862,6 +862,32 @@
     visitor.append(&thisObject->m_objectToStringValue);
 }
 
+bool Structure::prototypeChainMayInterceptStoreTo(JSGlobalData& globalData, PropertyName propertyName)
+{
+    unsigned i = propertyName.asIndex();
+    if (i != PropertyName::NotAnIndex)
+        return anyObjectInChainMayInterceptIndexedAccesses();
+    
+    for (Structure* current = this; ;) {
+        JSValue prototype = current->storedPrototype();
+        if (prototype.isNull())
+            return false;
+        
+        current = prototype.asCell()->structure();
+        
+        unsigned attributes;
+        JSCell* specificValue;
+        PropertyOffset offset = current->get(globalData, propertyName, attributes, specificValue);
+        if (!JSC::isValidOffset(offset))
+            continue;
+        
+        if (attributes & (ReadOnly | Accessor))
+            return true;
+        
+        return false;
+    }
+}
+
 #if DO_PROPERTYMAP_CONSTENCY_CHECK
 
 void PropertyTable::checkConsistency()

Modified: trunk/Source/_javascript_Core/runtime/Structure.h (134812 => 134813)


--- trunk/Source/_javascript_Core/runtime/Structure.h	2012-11-15 20:04:21 UTC (rev 134812)
+++ trunk/Source/_javascript_Core/runtime/Structure.h	2012-11-15 20:20:02 UTC (rev 134813)
@@ -168,7 +168,10 @@
         JSValue prototypeForLookup(CodeBlock*) const;
         StructureChain* prototypeChain(ExecState*) const;
         static void visitChildren(JSCell*, SlotVisitor&);
-
+        
+        // Will just the prototype chain intercept this property access?
+        bool prototypeChainMayInterceptStoreTo(JSGlobalData&, PropertyName);
+        
         Structure* previousID() const
         {
             ASSERT(structure()->classInfo() == &s_info);
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to