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);