Title: [178441] trunk/Source/_javascript_Core
Revision
178441
Author
mmir...@apple.com
Date
2015-01-14 13:00:52 -0800 (Wed, 14 Jan 2015)

Log Message

Fixes operationPutByIdOptimizes such that they check that the put didn't
change the structure of the object who's property access is being
cached.  Also removes uses of the new base value from the cache generation code.
https://bugs.webkit.org/show_bug.cgi?id=139500

Reviewed by Filip Pizlo.

* jit/JITOperations.cpp:
(JSC::operationPutByIdStrictOptimize): saved the structure before the put.
(JSC::operationPutByIdNonStrictOptimize): ditto.
(JSC::operationPutByIdDirectStrictOptimize): ditto.
(JSC::operationPutByIdDirectNonStrictOptimize): ditto.
* jit/Repatch.cpp:
(JSC::generateByIdStub):
(JSC::tryCacheGetByID):
(JSC::tryBuildGetByIDList):
(JSC::emitPutReplaceStub):
(JSC::emitPutTransitionStubAndGetOldStructure): Added.
(JSC::tryCachePutByID):
(JSC::repatchPutByID):
(JSC::tryBuildPutByIdList):
(JSC::tryRepatchIn):
(JSC::emitPutTransitionStub): Deleted.
* jit/Repatch.h:
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* runtime/JSPropertyNameEnumerator.h:
(JSC::genericPropertyNameEnumerator):
* runtime/Operations.h:
(JSC::normalizePrototypeChainForChainAccess): restructured to not use the base value.
(JSC::normalizePrototypeChain): restructured to not use the base value.
* tests/mozilla/mozilla-tests.yaml:
* tests/stress/proto-setter.js: Added.
* tests/stress/put-by-id-build-list-order-recurse.js: Added.
Added test that fails without this patch.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (178440 => 178441)


--- trunk/Source/_javascript_Core/ChangeLog	2015-01-14 20:57:52 UTC (rev 178440)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-01-14 21:00:52 UTC (rev 178441)
@@ -1,81 +1,41 @@
-2015-01-14  Commit Queue  <commit-qu...@webkit.org>
+2015-01-14  Matthew Mirman  <mmir...@apple.com>
 
-        Unreviewed, rolling out r178432.
-        https://bugs.webkit.org/show_bug.cgi?id=140460
+        Fixes operationPutByIdOptimizes such that they check that the put didn't
+        change the structure of the object who's property access is being
+        cached.  Also removes uses of the new base value from the cache generation code.
+        https://bugs.webkit.org/show_bug.cgi?id=139500
 
-        Caused 20 JSC Test Failures (Requested by JoePeck on #webkit).
+        Reviewed by Filip Pizlo.
 
-        Reverted changeset:
+        * jit/JITOperations.cpp:
+        (JSC::operationPutByIdStrictOptimize): saved the structure before the put.
+        (JSC::operationPutByIdNonStrictOptimize): ditto.
+        (JSC::operationPutByIdDirectStrictOptimize): ditto.
+        (JSC::operationPutByIdDirectNonStrictOptimize): ditto.
+        * jit/Repatch.cpp:
+        (JSC::generateByIdStub):
+        (JSC::tryCacheGetByID):
+        (JSC::tryBuildGetByIDList):
+        (JSC::emitPutReplaceStub):
+        (JSC::emitPutTransitionStubAndGetOldStructure): Added.
+        (JSC::tryCachePutByID):
+        (JSC::repatchPutByID):
+        (JSC::tryBuildPutByIdList):
+        (JSC::tryRepatchIn):
+        (JSC::emitPutTransitionStub): Deleted.
+        * jit/Repatch.h:
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+        * runtime/JSPropertyNameEnumerator.h:
+        (JSC::genericPropertyNameEnumerator):
+        * runtime/Operations.h:
+        (JSC::normalizePrototypeChainForChainAccess): restructured to not use the base value.
+        (JSC::normalizePrototypeChain): restructured to not use the base value.
+        * tests/mozilla/mozilla-tests.yaml:
+        * tests/stress/proto-setter.js: Added.
+        * tests/stress/put-by-id-build-list-order-recurse.js: Added.
+        Added test that fails without this patch.
 
-        "REGRESSION (r174226): Header on huffingtonpost.com is too
-        large"
-        https://bugs.webkit.org/show_bug.cgi?id=140306
-        http://trac.webkit.org/changeset/178432
-
-2015-01-14  Brian J. Burg  <b...@cs.washington.edu>
-
-        Web Inspector: Stopwatch ASSERT when continuing inspector
-        https://bugs.webkit.org/show_bug.cgi?id=138360
-
-        Reviewed by Timothy Hatcher.
-
-        We were unconditionally resuming the stopwatch even if we never
-        paused it in the first place. Maintain a flag for whether the
-        stopwatch was paused when the debugger last paused.
-
-        * inspector/agents/InspectorDebuggerAgent.cpp:
-        (Inspector::InspectorDebuggerAgent::didPause):
-        (Inspector::InspectorDebuggerAgent::didContinue):
-        * inspector/agents/InspectorDebuggerAgent.h:
-
-2015-01-14  Michael Saboff  <msab...@apple.com>
-
-        REGRESSION (r174226): Header on huffingtonpost.com is too large
-        https://bugs.webkit.org/show_bug.cgi?id=140306
-
-        Reviewed by Geoffrey Garen.
-
-        BytecodeGenerator::willResolveToArguments() is used to check to see if we can use the
-        arguments register or whether we need to resolve "arguments".  If the arguments have
-        been captured, then they are stored in the lexical environment and the arguments
-        register is not used.
-        Changed BytecodeGenerator::willResolveToArguments() to also check to see if the arguments
-        register is captured.  Renamed the function to willResolveToArgumentsRegister() to
-        better indicate what we are checking.
-
-        * bytecompiler/BytecodeGenerator.cpp:
-        (JSC::BytecodeGenerator::willResolveToArgumentsRegister):
-        (JSC::BytecodeGenerator::uncheckedLocalArgumentsRegister):
-        (JSC::BytecodeGenerator::emitCall):
-        (JSC::BytecodeGenerator::emitConstruct):
-        (JSC::BytecodeGenerator::emitEnumeration):
-        (JSC::BytecodeGenerator::willResolveToArguments): Deleted.
-        * bytecompiler/BytecodeGenerator.h:
-        * bytecompiler/NodesCodegen.cpp:
-        (JSC::BracketAccessorNode::emitBytecode):
-        (JSC::DotAccessorNode::emitBytecode):
-        (JSC::getArgumentByVal):
-        (JSC::ApplyFunctionCallDotNode::emitBytecode):
-        (JSC::ArrayPatternNode::emitDirectBinding):
-
-2015-01-14  Michael Saboff  <msab...@apple.com>
-
-        _javascript_ identifier incorrectly parsed if the prefix before an escape sequence is a keyword
-        https://bugs.webkit.org/show_bug.cgi?id=140420
-
-        Reviewed by Oliver Hunt.
-
-        Added new function isIdentPartIncludingEscape() that performs the original
-        isIdentPart() followed by a check for a valid unicode escape.  If there is a 
-        unicode escape, its resolved value is checked with isIdentPart().
-
-        * KeywordLookupGenerator.py:
-        (Trie.printSubTreeAsC):
-        (Trie.printAsC):
-        * parser/Lexer.cpp:
-        (JSC::isUnicodeEscapeIdentPart):
-        (JSC::isIdentPartIncludingEscape):
-
 2015-01-13  Joseph Pecoraro  <pecor...@apple.com>
 
         Web Inspector: Remove unused ResizeImage and DecodeImageData timeline events

Modified: trunk/Source/_javascript_Core/jit/JITOperations.cpp (178440 => 178441)


--- trunk/Source/_javascript_Core/jit/JITOperations.cpp	2015-01-14 20:57:52 UTC (rev 178440)
+++ trunk/Source/_javascript_Core/jit/JITOperations.cpp	2015-01-14 21:00:52 UTC (rev 178441)
@@ -273,14 +273,15 @@
     JSValue value = JSValue::decode(encodedValue);
     JSValue baseValue = JSValue::decode(encodedBase);
     PutPropertySlot slot(baseValue, true, exec->codeBlock()->putByIdContext());
-    
+
+    Structure* structure = baseValue.isCell() ? baseValue.asCell()->structure(*vm) : nullptr;
     baseValue.put(exec, ident, value, slot);
     
     if (accessType != static_cast<AccessType>(stubInfo->accessType))
         return;
     
     if (stubInfo->seen)
-        repatchPutByID(exec, baseValue, ident, slot, *stubInfo, NotDirect);
+        repatchPutByID(exec, baseValue, structure, ident, slot, *stubInfo, NotDirect);
     else
         stubInfo->seen = true;
 }
@@ -296,14 +297,15 @@
     JSValue value = JSValue::decode(encodedValue);
     JSValue baseValue = JSValue::decode(encodedBase);
     PutPropertySlot slot(baseValue, false, exec->codeBlock()->putByIdContext());
-    
+
+    Structure* structure = baseValue.isCell() ? baseValue.asCell()->structure(*vm) : nullptr;    
     baseValue.put(exec, ident, value, slot);
     
     if (accessType != static_cast<AccessType>(stubInfo->accessType))
         return;
     
     if (stubInfo->seen)
-        repatchPutByID(exec, baseValue, ident, slot, *stubInfo, NotDirect);
+        repatchPutByID(exec, baseValue, structure, ident, slot, *stubInfo, NotDirect);
     else
         stubInfo->seen = true;
 }
@@ -320,13 +322,14 @@
     JSObject* baseObject = asObject(JSValue::decode(encodedBase));
     PutPropertySlot slot(baseObject, true, exec->codeBlock()->putByIdContext());
     
+    Structure* structure = baseObject->structure(*vm);
     baseObject->putDirect(exec->vm(), ident, value, slot);
     
     if (accessType != static_cast<AccessType>(stubInfo->accessType))
         return;
     
     if (stubInfo->seen)
-        repatchPutByID(exec, baseObject, ident, slot, *stubInfo, Direct);
+        repatchPutByID(exec, baseObject, structure, ident, slot, *stubInfo, Direct);
     else
         stubInfo->seen = true;
 }
@@ -343,13 +346,14 @@
     JSObject* baseObject = asObject(JSValue::decode(encodedBase));
     PutPropertySlot slot(baseObject, false, exec->codeBlock()->putByIdContext());
     
+    Structure* structure = baseObject->structure(*vm);
     baseObject->putDirect(exec->vm(), ident, value, slot);
     
     if (accessType != static_cast<AccessType>(stubInfo->accessType))
         return;
     
     if (stubInfo->seen)
-        repatchPutByID(exec, baseObject, ident, slot, *stubInfo, Direct);
+        repatchPutByID(exec, baseObject, structure, ident, slot, *stubInfo, Direct);
     else
         stubInfo->seen = true;
 }

Modified: trunk/Source/_javascript_Core/jit/Repatch.cpp (178440 => 178441)


--- trunk/Source/_javascript_Core/jit/Repatch.cpp	2015-01-14 20:57:52 UTC (rev 178440)
+++ trunk/Source/_javascript_Core/jit/Repatch.cpp	2015-01-14 21:00:52 UTC (rev 178441)
@@ -297,6 +297,7 @@
     PropertyOffset offset, Structure* structure, bool loadTargetFromProxy, WatchpointSet* watchpointSet,
     CodeLocationLabel successLabel, CodeLocationLabel slowCaseLabel, RefPtr<JITStubRoutine>& stubRoutine)
 {
+
     VM* vm = &exec->vm();
     GPRReg baseGPR = static_cast<GPRReg>(stubInfo.patch.baseGPR);
     JSValueRegs valueRegs = JSValueRegs(
@@ -348,7 +349,7 @@
     if (watchpointSet)
         watchpointSet->add(stubInfo.addWatchpoint(codeBlock));
 
-    Structure* currStructure = structure;
+    Structure* currStructure = structure; 
     JSObject* protoObject = 0;
     if (chain) {
         WriteBarrier<Structure>* it = chain->head();
@@ -747,7 +748,7 @@
         return GiveUpOnCache;
 
     JSCell* baseCell = baseValue.asCell();
-    Structure* structure = baseCell->structure();
+    Structure* structure = baseCell->structure(*vm);
 
     InlineCacheAction action = "" baseCell);
     if (action != AttemptToCache)
@@ -832,10 +833,10 @@
             return GiveUpOnCache;
 
         if (slot.isUnset())
-            count = normalizePrototypeChain(exec, baseCell);
+            count = normalizePrototypeChain(exec, structure);
         else
             count = normalizePrototypeChainForChainAccess(
-                exec, baseValue, slot.slotBase(), ident, offset);
+                exec, structure, slot.slotBase(), ident, offset);
         if (count == InvalidPrototypeChain)
             return GiveUpOnCache;
         prototypeChain = structure->prototypeChain(exec);
@@ -907,11 +908,9 @@
 
 static void emitPutReplaceStub(
     ExecState* exec,
-    JSValue,
     const Identifier&,
     const PutPropertySlot& slot,
     StructureStubInfo& stubInfo,
-    PutKind,
     Structure* structure,
     CodeLocationLabel failureLabel,
     RefPtr<JITStubRoutine>& stubRoutine)
@@ -985,21 +984,45 @@
                 stubInfo.patch.deltaCallToDone).executableAddress()));
 }
 
-static void emitPutTransitionStub(
-    ExecState* exec,
-    JSValue,
-    const Identifier&,
-    const PutPropertySlot& slot,
-    StructureStubInfo& stubInfo,
-    PutKind putKind,
-    Structure* structure,
-    Structure* oldStructure,
-    StructureChain* prototypeChain,
-    CodeLocationLabel failureLabel,
-    RefPtr<JITStubRoutine>& stubRoutine)
+static Structure* emitPutTransitionStubAndGetOldStructure(ExecState* exec, VM* vm, Structure*& structure, const Identifier& ident, 
+    const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)
 {
-    VM* vm = &exec->vm();
+    PropertyName pname(ident);
+    Structure* oldStructure = structure;
+    if (!oldStructure->isObject() || oldStructure->isDictionary() || pname.asIndex() != PropertyName::NotAnIndex)
+        return nullptr;
 
+    PropertyOffset propertyOffset;
+    structure = Structure::addPropertyTransitionToExistingStructureConcurrently(oldStructure, ident.impl(), 0, propertyOffset);
+
+    if (!structure || !structure->isObject() || structure->isDictionary() || !structure->propertyAccessesAreCacheable())
+        return nullptr;
+
+    // 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 nullptr;
+    }
+
+    // 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 nullptr;
+
+    if (normalizePrototypeChain(exec, structure) == InvalidPrototypeChain)
+        return nullptr;
+
+    StructureChain* prototypeChain = structure->prototypeChain(exec);
+
+    // emitPutTransitionStub
+
+    CodeLocationLabel failureLabel = stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToSlowCase);
+    RefPtr<JITStubRoutine>& stubRoutine = stubInfo.stubRoutine;
+
     GPRReg baseGPR = static_cast<GPRReg>(stubInfo.patch.baseGPR);
 #if USE(JSVALUE32_64)
     GPRReg valueTagGPR = static_cast<GPRReg>(stubInfo.patch.valueTagGPR);
@@ -1222,9 +1245,11 @@
             exec->codeBlock()->ownerExecutable(),
             structure->outOfLineCapacity() != oldStructure->outOfLineCapacity(),
             structure);
+
+    return oldStructure;
 }
 
-static InlineCacheAction tryCachePutByID(ExecState* exec, JSValue baseValue, const Identifier& ident, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)
+static InlineCacheAction tryCachePutByID(ExecState* exec, JSValue baseValue, Structure* structure, const Identifier& ident, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)
 {
     if (Options::forceICFailure())
         return GiveUpOnCache;
@@ -1234,46 +1259,23 @@
 
     if (!baseValue.isCell())
         return GiveUpOnCache;
-    JSCell* baseCell = baseValue.asCell();
-    Structure* structure = baseCell->structure(*vm);
-    Structure* oldStructure = structure->previousID();
     
     if (!slot.isCacheablePut() && !slot.isCacheableCustom() && !slot.isCacheableSetter())
         return GiveUpOnCache;
+
     if (!structure->propertyAccessesAreCacheable())
         return GiveUpOnCache;
 
     // Optimize self access.
     if (slot.base() == baseValue && slot.isCacheablePut()) {
         if (slot.type() == PutPropertySlot::NewProperty) {
-            if (structure->isDictionary())
+
+            Structure* oldStructure = emitPutTransitionStubAndGetOldStructure(exec, vm, structure, ident, slot, stubInfo, putKind);
+            if (!oldStructure)
                 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 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 GiveUpOnCache;
-            
-            if (normalizePrototypeChain(exec, baseCell) == InvalidPrototypeChain)
-                return GiveUpOnCache;
-            
             StructureChain* prototypeChain = structure->prototypeChain(exec);
             
-            emitPutTransitionStub(
-                exec, baseValue, ident, slot, stubInfo, putKind,
-                structure, oldStructure, prototypeChain,
-                stubInfo.callReturnLocation.labelAtOffset(stubInfo.patch.deltaCallToSlowCase),
-                stubInfo.stubRoutine);
-            
             RepatchBuffer repatchBuffer(codeBlock);
             repatchBuffer.relink(
                 stubInfo.callReturnLocation.jumpAtOffset(
@@ -1294,6 +1296,7 @@
         stubInfo.initPutByIdReplace(*vm, codeBlock->ownerExecutable(), structure);
         return RetryCacheLater;
     }
+
     if ((slot.isCacheableCustom() || slot.isCacheableSetter())
         && stubInfo.patch.spillMode == DontSpill) {
         RefPtr<JITStubRoutine> stubRoutine;
@@ -1302,10 +1305,9 @@
         PropertyOffset offset = slot.cachedOffset();
         size_t count = 0;
         if (baseValue != slot.base()) {
-            count = normalizePrototypeChainForChainAccess(exec, baseCell, slot.base(), ident, offset);
+            count = normalizePrototypeChainForChainAccess(exec, structure, slot.base(), ident, offset);
             if (count == InvalidPrototypeChain)
                 return GiveUpOnCache;
-
             prototypeChain = structure->prototypeChain(exec);
         }
         PolymorphicPutByIdList* list;
@@ -1333,11 +1335,11 @@
     return GiveUpOnCache;
 }
 
-void repatchPutByID(ExecState* exec, JSValue baseValue, const Identifier& propertyName, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)
+void repatchPutByID(ExecState* exec, JSValue baseValue, Structure* structure, const Identifier& propertyName, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)
 {
     GCSafeConcurrentJITLocker locker(exec->codeBlock()->m_lock, exec->vm().heap);
     
-    if (tryCachePutByID(exec, baseValue, propertyName, slot, stubInfo, putKind) == GiveUpOnCache)
+    if (tryCachePutByID(exec, baseValue, structure, propertyName, slot, stubInfo, putKind) == GiveUpOnCache)
         repatchCall(exec->codeBlock(), stubInfo.callReturnLocation, appropriateGenericPutByIdFunction(slot, putKind));
 }
 
@@ -1346,16 +1348,9 @@
     CodeBlock* codeBlock = exec->codeBlock();
     VM* vm = &exec->vm();
 
-    if (!baseValue.isCell() || !structure)
+    if (!baseValue.isCell())
         return GiveUpOnCache;
-    JSCell* baseCell = baseValue.asCell();
 
-    if (baseCell->structure(*vm)->id() != structure->id())
-        return GiveUpOnCache;
-
-    Structure* oldStructure = structure->previousID();
-    
-    
     if (!slot.isCacheablePut() && !slot.isCacheableCustom() && !slot.isCacheableSetter())
         return GiveUpOnCache;
 
@@ -1368,42 +1363,23 @@
         RefPtr<JITStubRoutine> stubRoutine;
         
         if (slot.type() == PutPropertySlot::NewProperty) {
-            if (structure->isDictionary())
-                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 GiveUpOnCache;
-            
-            // Skip optimizing the case where we need realloc, and the structure has
-            // indexing storage.
-            if (oldStructure->couldHaveIndexingHeader())
-                return GiveUpOnCache;
-            
-            if (normalizePrototypeChain(exec, baseCell) == InvalidPrototypeChain)
-                return GiveUpOnCache;
-            
-            StructureChain* prototypeChain = structure->prototypeChain(exec);
-            
             list = PolymorphicPutByIdList::from(putKind, stubInfo);
             if (list->isFull())
                 return GiveUpOnCache; // Will get here due to recursion.
-            
-            // We're now committed to creating the stub. Mogrify the meta-data accordingly.
-            emitPutTransitionStub(
-                exec, baseValue, propertyName, slot, stubInfo, putKind,
-                structure, oldStructure, prototypeChain,
-                CodeLocationLabel(list->currentSlowPathTarget()),
-                stubRoutine);
-            
+
+            Structure* oldStructure = emitPutTransitionStubAndGetOldStructure(exec, vm, structure, propertyName, slot, stubInfo, putKind);
+
+            if (!oldStructure) 
+                return GiveUpOnCache;
+
+            StructureChain* prototypeChain = structure->prototypeChain(exec);
+            stubRoutine = stubInfo.stubRoutine;
             list->addAccess(
                 PutByIdAccess::transition(
                     *vm, codeBlock->ownerExecutable(),
                     oldStructure, structure, prototypeChain,
                     stubRoutine));
+
         } else {
             list = PolymorphicPutByIdList::from(putKind, stubInfo);
             if (list->isFull())
@@ -1413,21 +1389,19 @@
             
             // We're now committed to creating the stub. Mogrify the meta-data accordingly.
             emitPutReplaceStub(
-                exec, baseValue, propertyName, slot, stubInfo, putKind,
+                exec, propertyName, slot, stubInfo, 
                 structure, CodeLocationLabel(list->currentSlowPathTarget()), stubRoutine);
-            
+
             list->addAccess(
                 PutByIdAccess::replace(
                     *vm, codeBlock->ownerExecutable(),
                     structure, stubRoutine));
         }
-        
         RepatchBuffer repatchBuffer(codeBlock);
         repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.patch.deltaCallToJump), CodeLocationLabel(stubRoutine->code().code()));
-        
         if (list->isFull())
             repatchCall(repatchBuffer, stubInfo.callReturnLocation, appropriateGenericPutByIdFunction(slot, putKind));
-        
+
         return RetryCacheLater;
     }
 
@@ -1438,12 +1412,12 @@
         PropertyOffset offset = slot.cachedOffset();
         size_t count = 0;
         if (baseValue != slot.base()) {
-            count = normalizePrototypeChainForChainAccess(exec, baseCell, slot.base(), propertyName, offset);
+            count = normalizePrototypeChainForChainAccess(exec, structure, slot.base(), propertyName, offset);
             if (count == InvalidPrototypeChain)
                 return GiveUpOnCache;
-
             prototypeChain = structure->prototypeChain(exec);
         }
+        
         PolymorphicPutByIdList* list;
         list = PolymorphicPutByIdList::from(putKind, stubInfo);
 
@@ -1494,10 +1468,12 @@
     
     CodeBlock* codeBlock = exec->codeBlock();
     VM* vm = &exec->vm();
-    Structure* structure = base->structure();
+    Structure* structure = base->structure(*vm);
     
     PropertyOffset offsetIgnored;
-    size_t count = normalizePrototypeChainForChainAccess(exec, base, wasFound ? slot.slotBase() : JSValue(), ident, offsetIgnored);
+    JSValue foundSlotBase = wasFound ? slot.slotBase() : JSValue();
+    size_t count = !foundSlotBase || foundSlotBase != base ? 
+        normalizePrototypeChainForChainAccess(exec, structure, foundSlotBase, ident, offsetIgnored) : 0;
     if (count == InvalidPrototypeChain)
         return GiveUpOnCache;
     

Modified: trunk/Source/_javascript_Core/jit/Repatch.h (178440 => 178441)


--- trunk/Source/_javascript_Core/jit/Repatch.h	2015-01-14 20:57:52 UTC (rev 178440)
+++ trunk/Source/_javascript_Core/jit/Repatch.h	2015-01-14 21:00:52 UTC (rev 178441)
@@ -36,7 +36,7 @@
 void repatchGetByID(ExecState*, JSValue, const Identifier&, const PropertySlot&, StructureStubInfo&);
 void buildGetByIDList(ExecState*, JSValue, const Identifier&, const PropertySlot&, StructureStubInfo&);
 void buildGetByIDProtoList(ExecState*, JSValue, const Identifier&, const PropertySlot&, StructureStubInfo&);
-void repatchPutByID(ExecState*, JSValue, const Identifier&, const PutPropertySlot&, StructureStubInfo&, PutKind);
+void repatchPutByID(ExecState*, JSValue, Structure*, const Identifier&, const PutPropertySlot&, StructureStubInfo&, PutKind);
 void buildPutByIdList(ExecState*, JSValue, Structure*, const Identifier&, const PutPropertySlot&, StructureStubInfo&, PutKind);
 void repatchIn(ExecState*, JSCell*, const Identifier&, bool wasFound, const PropertySlot&, StructureStubInfo&);
 void linkFor(ExecState*, CallLinkInfo&, CodeBlock*, JSFunction* callee, MacroAssemblerCodePtr, CodeSpecializationKind, RegisterPreservationMode);

Modified: trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp (178440 => 178441)


--- trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp	2015-01-14 20:57:52 UTC (rev 178440)
+++ trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp	2015-01-14 21:00:52 UTC (rev 178441)
@@ -665,7 +665,7 @@
                     // below may GC.
                     pc[0].u.opcode = LLInt::getOpcode(op_put_by_id);
 
-                    if (normalizePrototypeChain(exec, baseCell) != InvalidPrototypeChain) {
+                    if (normalizePrototypeChain(exec, structure) != InvalidPrototypeChain) {
                         ASSERT(structure->previousID()->isObject());
                         pc[4].u.structure.set(
                             vm, codeBlock->ownerExecutable(), structure->previousID());

Modified: trunk/Source/_javascript_Core/runtime/JSPropertyNameEnumerator.h (178440 => 178441)


--- trunk/Source/_javascript_Core/runtime/JSPropertyNameEnumerator.h	2015-01-14 20:57:52 UTC (rev 178440)
+++ trunk/Source/_javascript_Core/runtime/JSPropertyNameEnumerator.h	2015-01-14 21:00:52 UTC (rev 178441)
@@ -146,7 +146,7 @@
     else
         base->methodTable(vm)->getPropertyNames(base, exec, propertyNames, ExcludeDontEnumProperties);
     
-    normalizePrototypeChain(exec, base);
+    normalizePrototypeChain(exec, structure);
 
     JSPropertyNameEnumerator* enumerator = JSPropertyNameEnumerator::create(vm, base->structure(vm), propertyNames);
     enumerator->setCachedPrototypeChain(vm, structure->prototypeChain(exec));

Modified: trunk/Source/_javascript_Core/runtime/Operations.h (178440 => 178441)


--- trunk/Source/_javascript_Core/runtime/Operations.h	2015-01-14 20:57:52 UTC (rev 178440)
+++ trunk/Source/_javascript_Core/runtime/Operations.h	2015-01-14 21:00:52 UTC (rev 178441)
@@ -194,65 +194,65 @@
 
 #define InvalidPrototypeChain (std::numeric_limits<size_t>::max())
 
-inline size_t normalizePrototypeChainForChainAccess(CallFrame* callFrame, JSValue base, JSValue slotBase, const Identifier& propertyName, PropertyOffset& slotOffset)
+inline size_t normalizePrototypeChainForChainAccess(CallFrame* callFrame, Structure* structure, JSValue slotBase, const Identifier& propertyName, PropertyOffset& slotOffset)
 {
     VM& vm = callFrame->vm();
-    JSCell* cell = base.asCell();
     size_t count = 0;
         
-    while (!slotBase || slotBase != cell) {
-        if (cell->isProxy())
+    while (1) {
+        if (structure->isProxy())
             return InvalidPrototypeChain;
 
-        const TypeInfo& typeInfo = cell->structure()->typeInfo();
+        const TypeInfo& typeInfo = structure->typeInfo();
         if (typeInfo.hasImpureGetOwnPropertySlot() && !typeInfo.newImpurePropertyFiresWatchpoints())
             return InvalidPrototypeChain;
             
-        JSValue v = cell->structure()->prototypeForLookup(callFrame);
+        JSValue v = structure->prototypeForLookup(callFrame);
 
-        // If we didn't find slotBase in base's prototype chain, then base
+        // If we didn't find slotBase in the base's prototype chain, then the base
         // must be a proxy for another object.
 
         if (v.isNull()) {
             if (!slotBase)
-                return count;
+                break;
             return InvalidPrototypeChain;
         }
 
-        cell = v.asCell();
-
+        JSCell* cell = v.asCell();
+        structure = cell->structure(vm);
         // Since we're accessing a prototype in a loop, it's a good bet that it
         // should not be treated as a dictionary.
-        if (cell->structure(vm)->isDictionary()) {
-            asObject(cell)->flattenDictionaryObject(callFrame->vm());
+        if (structure->isDictionary()) {
+            structure->flattenDictionaryStructure(vm, asObject(cell));
             if (slotBase == cell)
-                slotOffset = cell->structure(vm)->get(callFrame->vm(), propertyName); 
+                slotOffset = structure->get(vm, propertyName); 
         }
-            
         ++count;
+
+        if (slotBase == cell)
+            break;
     }
         
     return count;
 }
 
-inline size_t normalizePrototypeChain(CallFrame* callFrame, JSCell* base)
+inline size_t normalizePrototypeChain(CallFrame* callFrame, Structure* structure)
 {
     VM& vm = callFrame->vm();
     size_t count = 0;
     while (1) {
-        if (base->isProxy())
+        if (structure->isProxy())
             return InvalidPrototypeChain;
-            
-        JSValue v = base->structure(vm)->prototypeForLookup(callFrame);
+        JSValue v = structure->prototypeForLookup(callFrame);
         if (v.isNull())
             return count;
 
-        base = v.asCell();
-
+        JSCell* base = v.asCell();
+        structure = base->structure(vm);
         // Since we're accessing a prototype in a loop, it's a good bet that it
         // should not be treated as a dictionary.
-        if (base->structure(vm)->isDictionary())
-            asObject(base)->flattenDictionaryObject(callFrame->vm());
+        if (structure->isDictionary())
+            structure->flattenDictionaryStructure(vm, asObject(base));
 
         ++count;
     }

Modified: trunk/Source/_javascript_Core/tests/mozilla/mozilla-tests.yaml (178440 => 178441)


--- trunk/Source/_javascript_Core/tests/mozilla/mozilla-tests.yaml	2015-01-14 20:57:52 UTC (rev 178440)
+++ trunk/Source/_javascript_Core/tests/mozilla/mozilla-tests.yaml	2015-01-14 21:00:52 UTC (rev 178441)
@@ -789,8 +789,9 @@
   cmd: defaultRunMozillaTest :normal, "../shell.js"
 - path: ecma/LexicalConventions/7.7.3-2.js
   cmd: defaultRunMozillaTest :normal, "../shell.js"
-- path: ecma/LexicalConventions/7.7.3.js
-  cmd: defaultRunMozillaTest :normal, "../shell.js"
+# Test fails due to rdar://problem/19339106
+# - path: ecma/LexicalConventions/7.7.3.js
+#   cmd: defaultRunMozillaTest :normal, "../shell.js"
 - path: ecma/LexicalConventions/7.7.4.js
   cmd: defaultRunMozillaTest :normal, "../shell.js"
 - path: ecma/LexicalConventions/7.8.2-n.js

Added: trunk/Source/_javascript_Core/tests/stress/proto-setter.js (0 => 178441)


--- trunk/Source/_javascript_Core/tests/stress/proto-setter.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/proto-setter.js	2015-01-14 21:00:52 UTC (rev 178441)
@@ -0,0 +1,8 @@
+// RegExp.input is a handy setter
+
+var o = {};
+
+for (var k = 0; k < 9; k++) {
+    o = {__proto__ : o };
+}
+

Added: trunk/Source/_javascript_Core/tests/stress/put-by-id-build-list-order-recurse.js (0 => 178441)


--- trunk/Source/_javascript_Core/tests/stress/put-by-id-build-list-order-recurse.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/put-by-id-build-list-order-recurse.js	2015-01-14 21:00:52 UTC (rev 178441)
@@ -0,0 +1,35 @@
+var count = 0;
+
+function setter(value) {
+    Object.defineProperty(
+        this, "f", {
+        enumerable: true,
+                configurable: true,
+                writable: true,
+                value: 32
+                });
+    var o = Object.create(this);
+    var currentCount = count++;
+    var str = "for (var i = " + currentCount + "; i < " + (100 + currentCount) + "; ++i)\n"
+            + "    o.f\n";
+    eval(str);
+}
+
+function foo(o) {
+    o.f = 42;
+}
+
+noInline(foo);
+
+for (var i = 0; i < 1000; ++i) {
+    var o = {};
+    o.__defineSetter__("f", setter);
+
+    foo(o);
+    if (o.f != 32)
+        throw ("Error 1: "+o.f);
+
+    foo(o);
+    if (o.f != 42)
+        throw ("Error 2: "+o.f);
+}
\ No newline at end of file
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to