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