Title: [169853] trunk/Source/_javascript_Core
Revision
169853
Author
mhahnenb...@apple.com
Date
2014-06-11 15:55:34 -0700 (Wed, 11 Jun 2014)

Log Message

Inline caching should try to flatten uncacheable dictionaries
https://bugs.webkit.org/show_bug.cgi?id=133683

Reviewed by Geoffrey Garen.

There exists a body of JS code that deletes properties off of objects (especially function/constructor objects),
which puts them into an uncacheable dictionary state. This prevents all future inline caching for these objects.
If properties are deleted out of the object during its initialization, we can enable caching for that object by
attempting to flatten it when we see we're trying to do inline caching with that object. We then record that we
performed this flattening optimization in the object's Structure. If it ever re-enters the uncacheable dictionary
state then we can just give up on caching that object.

In refactoring some of the code in tryCacheGetById and tryBuildGetByIdList to reduce some duplication, I added
the InlineCacheAction enum, a new way to indicate the success or failure of an inline caching attempt. I changed
the other inline caching functions to return this enum rather than the opaque booleans that we were previously
returning.

* jit/Repatch.cpp:
(JSC::actionForCell):
(JSC::tryCacheGetByID):
(JSC::repatchGetByID):
(JSC::tryBuildGetByIDList):
(JSC::buildGetByIDList):
(JSC::tryCachePutByID):
(JSC::repatchPutByID):
(JSC::tryBuildPutByIdList):
(JSC::buildPutByIdList):
(JSC::tryRepatchIn):
(JSC::repatchIn):
* runtime/Structure.cpp:
(JSC::Structure::Structure):
(JSC::Structure::flattenDictionaryStructure):
* runtime/Structure.h:
(JSC::Structure::hasBeenFlattenedBefore):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (169852 => 169853)


--- trunk/Source/_javascript_Core/ChangeLog	2014-06-11 22:52:28 UTC (rev 169852)
+++ trunk/Source/_javascript_Core/ChangeLog	2014-06-11 22:55:34 UTC (rev 169853)
@@ -1,3 +1,40 @@
+2014-06-11  Mark Hahnenberg  <mhahnenb...@apple.com>
+
+        Inline caching should try to flatten uncacheable dictionaries
+        https://bugs.webkit.org/show_bug.cgi?id=133683
+
+        Reviewed by Geoffrey Garen.
+
+        There exists a body of JS code that deletes properties off of objects (especially function/constructor objects), 
+        which puts them into an uncacheable dictionary state. This prevents all future inline caching for these objects. 
+        If properties are deleted out of the object during its initialization, we can enable caching for that object by 
+        attempting to flatten it when we see we're trying to do inline caching with that object. We then record that we 
+        performed this flattening optimization in the object's Structure. If it ever re-enters the uncacheable dictionary 
+        state then we can just give up on caching that object.
+
+        In refactoring some of the code in tryCacheGetById and tryBuildGetByIdList to reduce some duplication, I added
+        the InlineCacheAction enum, a new way to indicate the success or failure of an inline caching attempt. I changed
+        the other inline caching functions to return this enum rather than the opaque booleans that we were previously 
+        returning.
+
+        * jit/Repatch.cpp:
+        (JSC::actionForCell):
+        (JSC::tryCacheGetByID):
+        (JSC::repatchGetByID):
+        (JSC::tryBuildGetByIDList):
+        (JSC::buildGetByIDList):
+        (JSC::tryCachePutByID):
+        (JSC::repatchPutByID):
+        (JSC::tryBuildPutByIdList):
+        (JSC::buildPutByIdList):
+        (JSC::tryRepatchIn):
+        (JSC::repatchIn):
+        * runtime/Structure.cpp:
+        (JSC::Structure::Structure):
+        (JSC::Structure::flattenDictionaryStructure):
+        * runtime/Structure.h:
+        (JSC::Structure::hasBeenFlattenedBefore):
+
 2014-06-11  Csaba Osztrogonác  <o...@webkit.org>
 
         [EFL] URTBF after r169823.

Modified: trunk/Source/_javascript_Core/jit/Repatch.cpp (169852 => 169853)


--- trunk/Source/_javascript_Core/jit/Repatch.cpp	2014-06-11 22:52:28 UTC (rev 169852)
+++ trunk/Source/_javascript_Core/jit/Repatch.cpp	2014-06-11 22:55:34 UTC (rev 169853)
@@ -594,10 +594,39 @@
         stubRoutine = createJITStubRoutine(code, *vm, codeBlock->ownerExecutable(), true);
 }
 
-static bool tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo& stubInfo)
+enum InlineCacheAction {
+    GiveUpOnCache,
+    RetryCacheLater,
+    AttemptToCache
+};
+
+static InlineCacheAction actionForCell(VM& vm, JSCell* cell)
 {
+    Structure* structure = cell->structure(vm);
+
+    TypeInfo typeInfo = structure->typeInfo();
+    if (typeInfo.prohibitsPropertyCaching())
+        return GiveUpOnCache;
+
+    if (structure->isUncacheableDictionary()) {
+        if (structure->hasBeenFlattenedBefore())
+            return GiveUpOnCache;
+        // Flattening could have changed the offset, so return early for another try.
+        asObject(cell)->flattenDictionaryObject(vm);
+        return RetryCacheLater;
+    }
+    ASSERT(!structure->isUncacheableDictionary());
+    
+    if (typeInfo.hasImpureGetOwnPropertySlot() && !typeInfo.newImpurePropertyFiresWatchpoints())
+        return GiveUpOnCache;
+
+    return AttemptToCache;
+}
+
+static InlineCacheAction tryCacheGetByID(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo& stubInfo)
+{
     if (Options::forceICFailure())
-        return false;
+        return GiveUpOnCache;
     
     // FIXME: Write a test that proves we need to check for recursion here just
     // like the interpreter does, then add a check for recursion.
@@ -663,7 +692,7 @@
             replaceWithJump(repatchBuffer, stubInfo, stubInfo.stubRoutine->code().code());
             repatchCall(repatchBuffer, stubInfo.callReturnLocation, operationGetById);
 
-            return true;
+            return RetryCacheLater;
         }
 
         // String.length case
@@ -694,22 +723,21 @@
         replaceWithJump(repatchBuffer, stubInfo, stubInfo.stubRoutine->code().code());
         repatchCall(repatchBuffer, stubInfo.callReturnLocation, operationGetById);
 
-        return true;
+        return RetryCacheLater;
     }
 
     // FIXME: Cache property access for immediates.
     if (!baseValue.isCell())
-        return false;
+        return GiveUpOnCache;
     JSCell* baseCell = baseValue.asCell();
     Structure* structure = baseCell->structure();
     if (!slot.isCacheable())
-        return false;
-    if (!structure->propertyAccessesAreCacheable())
-        return false;
-    TypeInfo typeInfo = structure->typeInfo();
-    if (typeInfo.hasImpureGetOwnPropertySlot() && !typeInfo.newImpurePropertyFiresWatchpoints())
-        return false;
+        return GiveUpOnCache;
 
+    InlineCacheAction action = "" baseCell);
+    if (action != AttemptToCache)
+        return action;
+
     // Optimize self access.
     if (slot.slotBase() == baseValue
         && slot.isCacheableValue()
@@ -717,19 +745,18 @@
         && MacroAssembler::isCompactPtrAlignedAddressOffset(maxOffsetRelativeToPatchedStorage(slot.cachedOffset()))) {
             repatchByIdSelfAccess(*vm, codeBlock, stubInfo, structure, propertyName, slot.cachedOffset(), operationGetByIdBuildList, true);
             stubInfo.initGetByIdSelf(*vm, codeBlock->ownerExecutable(), structure);
-            return true;
+            return RetryCacheLater;
     }
 
     repatchCall(codeBlock, stubInfo.callReturnLocation, operationGetByIdBuildList);
-    return true;
+    return RetryCacheLater;
 }
 
 void repatchGetByID(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo& stubInfo)
 {
     GCSafeConcurrentJITLocker locker(exec->codeBlock()->m_lock, exec->vm().heap);
     
-    bool cached = tryCacheGetByID(exec, baseValue, propertyName, slot, stubInfo);
-    if (!cached)
+    if (tryCacheGetByID(exec, baseValue, propertyName, slot, stubInfo) == GiveUpOnCache)
         repatchCall(exec->codeBlock(), stubInfo.callReturnLocation, operationGetById);
 }
 
@@ -748,11 +775,11 @@
     replaceWithJump(repatchBuffer, stubInfo, stubRoutine->code().code());
 }
 
-static bool tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identifier& ident, const PropertySlot& slot, StructureStubInfo& stubInfo)
+static InlineCacheAction tryBuildGetByIDList(ExecState* exec, JSValue baseValue, const Identifier& ident, const PropertySlot& slot, StructureStubInfo& stubInfo)
 {
     if (!baseValue.isCell()
         || !slot.isCacheable())
-        return false;
+        return GiveUpOnCache;
 
     JSCell* baseCell = baseValue.asCell();
     bool loadTargetFromProxy = false;
@@ -764,21 +791,20 @@
 
     VM* vm = &exec->vm();
     CodeBlock* codeBlock = exec->codeBlock();
-    Structure* structure = baseCell->structure(*vm);
 
-    if (!structure->propertyAccessesAreCacheable())
-        return false;
+    InlineCacheAction action = "" baseCell);
+    if (action != AttemptToCache)
+        return action;
 
+    Structure* structure = baseCell->structure(*vm);
     TypeInfo typeInfo = structure->typeInfo();
-    if (typeInfo.hasImpureGetOwnPropertySlot() && !typeInfo.newImpurePropertyFiresWatchpoints())
-        return false;
 
     if (stubInfo.patch.spillMode == NeedToSpill) {
         // We cannot do as much inline caching if the registers were not flushed prior to this GetById. In particular,
         // non-Value cached properties require planting calls, which requires registers to have been flushed. Thus,
         // if registers were not flushed, don't do non-Value caching.
         if (!slot.isCacheableValue())
-            return false;
+            return GiveUpOnCache;
     }
     
     PropertyOffset offset = slot.cachedOffset();
@@ -787,19 +813,19 @@
     
     if (slot.slotBase() != baseValue) {
         if (typeInfo.prohibitsPropertyCaching() || structure->isDictionary())
-            return false;
+            return GiveUpOnCache;
         
         count = normalizePrototypeChainForChainAccess(
             exec, baseValue, slot.slotBase(), ident, offset);
         if (count == InvalidPrototypeChain)
-            return false;
+            return GiveUpOnCache;
         prototypeChain = structure->prototypeChain(exec);
     }
     
     PolymorphicGetByIdList* list = PolymorphicGetByIdList::from(stubInfo);
     if (list->isFull()) {
         // We need this extra check because of recursion.
-        return false;
+        return GiveUpOnCache;
     }
     
     RefPtr<JITStubRoutine> stubRoutine;
@@ -823,15 +849,14 @@
     
     patchJumpToGetByIdStub(codeBlock, stubInfo, stubRoutine.get());
     
-    return !list->isFull();
+    return list->isFull() ? GiveUpOnCache : RetryCacheLater;
 }
 
 void buildGetByIDList(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo& stubInfo)
 {
     GCSafeConcurrentJITLocker locker(exec->codeBlock()->m_lock, exec->vm().heap);
     
-    bool dontChangeCall = tryBuildGetByIDList(exec, baseValue, propertyName, slot, stubInfo);
-    if (!dontChangeCall)
+    if (tryBuildGetByIDList(exec, baseValue, propertyName, slot, stubInfo) == GiveUpOnCache)
         repatchCall(exec->codeBlock(), stubInfo.callReturnLocation, operationGetById);
 }
 
@@ -1136,47 +1161,47 @@
             structure);
 }
 
-static bool tryCachePutByID(ExecState* exec, JSValue baseValue, const Identifier& ident, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)
+static InlineCacheAction tryCachePutByID(ExecState* exec, JSValue baseValue, const Identifier& ident, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)
 {
     if (Options::forceICFailure())
-        return false;
+        return GiveUpOnCache;
     
     CodeBlock* codeBlock = exec->codeBlock();
     VM* vm = &exec->vm();
 
     if (!baseValue.isCell())
-        return false;
+        return GiveUpOnCache;
     JSCell* baseCell = baseValue.asCell();
     Structure* structure = baseCell->structure();
     Structure* oldStructure = structure->previousID();
     
     if (!slot.isCacheablePut() && !slot.isCacheableCustom() && !slot.isCacheableSetter())
-        return false;
+        return GiveUpOnCache;
     if (!structure->propertyAccessesAreCacheable())
-        return false;
+        return GiveUpOnCache;
 
     // Optimize self access.
     if (slot.base() == baseValue && slot.isCacheablePut()) {
         if (slot.type() == PutPropertySlot::NewProperty) {
             if (structure->isDictionary())
-                return false;
+                return GiveUpOnCache;
             
             // Skip optimizing the case where we need a realloc, if we don't have
             // enough registers to make it happen.
             if (GPRInfo::numberOfRegisters < 6
                 && oldStructure->outOfLineCapacity() != structure->outOfLineCapacity()
                 && oldStructure->outOfLineCapacity())
-                return false;
+                return GiveUpOnCache;
             
             // Skip optimizing the case where we need realloc, and the structure has
             // indexing storage.
             // FIXME: We shouldn't skip this!  Implement it!
             // https://bugs.webkit.org/show_bug.cgi?id=130914
             if (oldStructure->couldHaveIndexingHeader())
-                return false;
+                return GiveUpOnCache;
             
             if (normalizePrototypeChain(exec, baseCell) == InvalidPrototypeChain)
-                return false;
+                return GiveUpOnCache;
             
             StructureChain* prototypeChain = structure->prototypeChain(exec);
             
@@ -1195,15 +1220,15 @@
             
             stubInfo.initPutByIdTransition(*vm, codeBlock->ownerExecutable(), oldStructure, structure, prototypeChain, putKind == Direct);
             
-            return true;
+            return RetryCacheLater;
         }
 
         if (!MacroAssembler::isPtrAlignedAddressOffset(offsetRelativeToPatchedStorage(slot.cachedOffset())))
-            return false;
+            return GiveUpOnCache;
 
         repatchByIdSelfAccess(*vm, codeBlock, stubInfo, structure, ident, slot.cachedOffset(), appropriateListBuildingPutByIdFunction(slot, putKind), false);
         stubInfo.initPutByIdReplace(*vm, codeBlock->ownerExecutable(), structure);
-        return true;
+        return RetryCacheLater;
     }
     if ((slot.isCacheableCustom() || slot.isCacheableSetter())
         && stubInfo.patch.spillMode == DontSpill) {
@@ -1215,7 +1240,7 @@
         if (baseValue != slot.base()) {
             count = normalizePrototypeChainForChainAccess(exec, baseCell, slot.base(), ident, offset);
             if (count == InvalidPrototypeChain)
-                return false;
+                return GiveUpOnCache;
 
             prototypeChain = structure->prototypeChain(exec);
         }
@@ -1238,38 +1263,37 @@
         repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.deltaCallToJump), CodeLocationLabel(stubRoutine->code().code()));
         repatchCall(repatchBuffer, stubInfo.callReturnLocation, appropriateListBuildingPutByIdFunction(slot, putKind));
         RELEASE_ASSERT(!list->isFull());
-        return true;
+        return RetryCacheLater;
     }
 
-    return false;
+    return GiveUpOnCache;
 }
 
 void repatchPutByID(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)
 {
     GCSafeConcurrentJITLocker locker(exec->codeBlock()->m_lock, exec->vm().heap);
     
-    bool cached = tryCachePutByID(exec, baseValue, propertyName, slot, stubInfo, putKind);
-    if (!cached)
+    if (tryCachePutByID(exec, baseValue, propertyName, slot, stubInfo, putKind) == GiveUpOnCache)
         repatchCall(exec->codeBlock(), stubInfo.callReturnLocation, appropriateGenericPutByIdFunction(slot, putKind));
 }
 
-static bool tryBuildPutByIdList(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)
+static InlineCacheAction tryBuildPutByIdList(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)
 {
     CodeBlock* codeBlock = exec->codeBlock();
     VM* vm = &exec->vm();
 
     if (!baseValue.isCell())
-        return false;
+        return GiveUpOnCache;
     JSCell* baseCell = baseValue.asCell();
     Structure* structure = baseCell->structure();
     Structure* oldStructure = structure->previousID();
     
     
     if (!slot.isCacheablePut() && !slot.isCacheableCustom() && !slot.isCacheableSetter())
-        return false;
+        return GiveUpOnCache;
 
     if (!structure->propertyAccessesAreCacheable())
-        return false;
+        return GiveUpOnCache;
 
     // Optimize self access.
     if (slot.base() == baseValue && slot.isCacheablePut()) {
@@ -1278,28 +1302,28 @@
         
         if (slot.type() == PutPropertySlot::NewProperty) {
             if (structure->isDictionary())
-                return false;
+                return GiveUpOnCache;
             
             // Skip optimizing the case where we need a realloc, if we don't have
             // enough registers to make it happen.
             if (GPRInfo::numberOfRegisters < 6
                 && oldStructure->outOfLineCapacity() != structure->outOfLineCapacity()
                 && oldStructure->outOfLineCapacity())
-                return false;
+                return GiveUpOnCache;
             
             // Skip optimizing the case where we need realloc, and the structure has
             // indexing storage.
             if (oldStructure->couldHaveIndexingHeader())
-                return false;
+                return GiveUpOnCache;
             
             if (normalizePrototypeChain(exec, baseCell) == InvalidPrototypeChain)
-                return false;
+                return GiveUpOnCache;
             
             StructureChain* prototypeChain = structure->prototypeChain(exec);
             
             list = PolymorphicPutByIdList::from(putKind, stubInfo);
             if (list->isFull())
-                return false; // Will get here due to recursion.
+                return GiveUpOnCache; // Will get here due to recursion.
             
             // We're now committed to creating the stub. Mogrify the meta-data accordingly.
             emitPutTransitionStub(
@@ -1316,7 +1340,7 @@
         } else {
             list = PolymorphicPutByIdList::from(putKind, stubInfo);
             if (list->isFull())
-                return false; // Will get here due to recursion.
+                return GiveUpOnCache; // Will get here due to recursion.
             
             // We're now committed to creating the stub. Mogrify the meta-data accordingly.
             emitPutReplaceStub(
@@ -1335,7 +1359,7 @@
         if (list->isFull())
             repatchCall(repatchBuffer, stubInfo.callReturnLocation, appropriateGenericPutByIdFunction(slot, putKind));
         
-        return true;
+        return RetryCacheLater;
     }
 
     if ((slot.isCacheableCustom() || slot.isCacheableSetter())
@@ -1347,7 +1371,7 @@
         if (baseValue != slot.base()) {
             count = normalizePrototypeChainForChainAccess(exec, baseCell, slot.base(), propertyName, offset);
             if (count == InvalidPrototypeChain)
-                return false;
+                return GiveUpOnCache;
 
             prototypeChain = structure->prototypeChain(exec);
         }
@@ -1371,33 +1395,32 @@
         if (list->isFull())
             repatchCall(repatchBuffer, stubInfo.callReturnLocation, appropriateGenericPutByIdFunction(slot, putKind));
 
-        return true;
+        return RetryCacheLater;
     }
-    return false;
+    return GiveUpOnCache;
 }
 
 void buildPutByIdList(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)
 {
     GCSafeConcurrentJITLocker locker(exec->codeBlock()->m_lock, exec->vm().heap);
     
-    bool cached = tryBuildPutByIdList(exec, baseValue, propertyName, slot, stubInfo, putKind);
-    if (!cached)
+    if (tryBuildPutByIdList(exec, baseValue, propertyName, slot, stubInfo, putKind) == GiveUpOnCache)
         repatchCall(exec->codeBlock(), stubInfo.callReturnLocation, appropriateGenericPutByIdFunction(slot, putKind));
 }
 
-static bool tryRepatchIn(
+static InlineCacheAction tryRepatchIn(
     ExecState* exec, JSCell* base, const Identifier& ident, bool wasFound,
     const PropertySlot& slot, StructureStubInfo& stubInfo)
 {
     if (Options::forceICFailure())
-        return false;
+        return GiveUpOnCache;
     
     if (!base->structure()->propertyAccessesAreCacheable())
-        return false;
+        return GiveUpOnCache;
     
     if (wasFound) {
         if (!slot.isCacheable())
-            return false;
+            return GiveUpOnCache;
     }
     
     CodeBlock* codeBlock = exec->codeBlock();
@@ -1407,7 +1430,7 @@
     PropertyOffset offsetIgnored;
     size_t count = normalizePrototypeChainForChainAccess(exec, base, wasFound ? slot.slotBase() : JSValue(), ident, offsetIgnored);
     if (count == InvalidPrototypeChain)
-        return false;
+        return GiveUpOnCache;
     
     PolymorphicAccessStructureList* polymorphicStructureList;
     int listIndex;
@@ -1428,7 +1451,7 @@
         slowCaseLabel = CodeLocationLabel(polymorphicStructureList->list[listIndex - 1].stubRoutine->code().code());
         
         if (listIndex == POLYMORPHIC_LIST_CACHE_SIZE)
-            return false;
+            return GiveUpOnCache;
     }
     
     StructureChain* chain = structure->prototypeChain(exec);
@@ -1502,16 +1525,15 @@
     RepatchBuffer repatchBuffer(codeBlock);
     repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.deltaCallToJump), CodeLocationLabel(stubRoutine->code().code()));
     
-    return listIndex < (POLYMORPHIC_LIST_CACHE_SIZE - 1);
+    return listIndex < (POLYMORPHIC_LIST_CACHE_SIZE - 1) ? RetryCacheLater : GiveUpOnCache;
 }
 
 void repatchIn(
     ExecState* exec, JSCell* base, const Identifier& ident, bool wasFound,
     const PropertySlot& slot, StructureStubInfo& stubInfo)
 {
-    if (tryRepatchIn(exec, base, ident, wasFound, slot, stubInfo))
-        return;
-    repatchCall(exec->codeBlock(), stubInfo.callReturnLocation, operationIn);
+    if (tryRepatchIn(exec, base, ident, wasFound, slot, stubInfo) == GiveUpOnCache)
+        repatchCall(exec->codeBlock(), stubInfo.callReturnLocation, operationIn);
 }
 
 static void linkSlowFor(

Modified: trunk/Source/_javascript_Core/runtime/Structure.cpp (169852 => 169853)


--- trunk/Source/_javascript_Core/runtime/Structure.cpp	2014-06-11 22:52:28 UTC (rev 169852)
+++ trunk/Source/_javascript_Core/runtime/Structure.cpp	2014-06-11 22:55:34 UTC (rev 169853)
@@ -158,6 +158,7 @@
     , m_offset(invalidOffset)
     , m_inlineCapacity(inlineCapacity)
     , m_dictionaryKind(NoneDictionaryKind)
+    , m_hasBeenFlattenedBefore(false)
     , m_isPinnedPropertyTable(false)
     , m_hasGetterSetterProperties(classInfo->hasStaticSetterOrReadonlyProperties(vm))
     , m_hasCustomGetterSetterProperties(false)
@@ -186,6 +187,7 @@
     , m_offset(invalidOffset)
     , m_inlineCapacity(0)
     , m_dictionaryKind(NoneDictionaryKind)
+    , m_hasBeenFlattenedBefore(false)
     , m_isPinnedPropertyTable(false)
     , m_hasGetterSetterProperties(m_classInfo->hasStaticSetterOrReadonlyProperties(vm))
     , m_hasCustomGetterSetterProperties(false)
@@ -213,6 +215,7 @@
     , m_offset(invalidOffset)
     , m_inlineCapacity(previous->m_inlineCapacity)
     , m_dictionaryKind(previous->m_dictionaryKind)
+    , m_hasBeenFlattenedBefore(previous->m_hasBeenFlattenedBefore)
     , m_isPinnedPropertyTable(false)
     , m_hasGetterSetterProperties(previous->m_hasGetterSetterProperties)
     , m_hasCustomGetterSetterProperties(previous->m_hasCustomGetterSetterProperties)
@@ -740,6 +743,7 @@
     }
 
     m_dictionaryKind = NoneDictionaryKind;
+    m_hasBeenFlattenedBefore = true;
 
     // If the object had a Butterfly but after flattening/compacting we no longer have need of it,
     // we need to zero it out because the collector depends on the Structure to know the size for copying.

Modified: trunk/Source/_javascript_Core/runtime/Structure.h (169852 => 169853)


--- trunk/Source/_javascript_Core/runtime/Structure.h	2014-06-11 22:52:28 UTC (rev 169852)
+++ trunk/Source/_javascript_Core/runtime/Structure.h	2014-06-11 22:55:34 UTC (rev 169853)
@@ -146,6 +146,8 @@
     bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; }
     bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; }
 
+    bool hasBeenFlattenedBefore() const { return m_hasBeenFlattenedBefore; }
+
     bool propertyAccessesAreCacheable() { return m_dictionaryKind != UncachedDictionaryKind && !typeInfo().prohibitsPropertyCaching(); }
 
     // We use SlowPath in GetByIdStatus for structures that may get new impure properties later to prevent
@@ -536,6 +538,7 @@
     ConcurrentJITLock m_lock;
     
     unsigned m_dictionaryKind : 2;
+    bool m_hasBeenFlattenedBefore : 1;
     bool m_isPinnedPropertyTable : 1;
     bool m_hasGetterSetterProperties : 1;
     bool m_hasCustomGetterSetterProperties : 1;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to