WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
closer to done
blah.patch (text/plain), 93.16 KB, created by
Filip Pizlo
on 2014-07-02 21:44:43 PDT
(
hide
)
Description:
closer to done
Filename:
MIME Type:
Creator:
Filip Pizlo
Created:
2014-07-02 21:44:43 PDT
Size:
93.16 KB
patch
obsolete
>Index: Source/JavaScriptCore/bytecode/ComplexGetStatus.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/ComplexGetStatus.cpp (revision 170724) >+++ Source/JavaScriptCore/bytecode/ComplexGetStatus.cpp (working copy) >@@ -46,8 +46,6 @@ ComplexGetStatus ComplexGetStatus::compu > ComplexGetStatus result; > result.m_kind = Inlineable; > >- JSCell* specificValue; >- > if (chain) { > result.m_chain = adoptRef(new IntendedStructureChain( > profiledBlock, headStructure, chain, chainCount)); >@@ -65,18 +63,12 @@ ComplexGetStatus ComplexGetStatus::compu > ASSERT_UNUSED(currentObject, currentObject); > > result.m_offset = currentStructure->getConcurrently( >- *profiledBlock->vm(), uid, result.m_attributes, specificValue); >- if (currentStructure->isDictionary()) >- specificValue = 0; >+ *profiledBlock->vm(), uid, result.m_attributes); > } else { > result.m_offset = headStructure->getConcurrently( >- *profiledBlock->vm(), uid, result.m_attributes, specificValue); >- if (headStructure->isDictionary()) >- specificValue = 0; >+ *profiledBlock->vm(), uid, result.m_attributes); > } > >- result.m_specificValue = specificValue; >- > if (!isValidOffset(result.m_offset)) > return takesSlowPath(); > >Index: Source/JavaScriptCore/bytecode/GetByIdStatus.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/GetByIdStatus.cpp (revision 170724) >+++ Source/JavaScriptCore/bytecode/GetByIdStatus.cpp (working copy) >@@ -85,15 +85,12 @@ GetByIdStatus GetByIdStatus::computeFrom > return GetByIdStatus(NoInformation, false); > > unsigned attributesIgnored; >- JSCell* specificValue; > PropertyOffset offset = structure->getConcurrently( >- *profiledBlock->vm(), uid, attributesIgnored, specificValue); >- if (structure->isDictionary()) >- specificValue = 0; >+ *profiledBlock->vm(), uid, attributesIgnored); > if (!isValidOffset(offset)) > return GetByIdStatus(NoInformation, false); > >- return GetByIdStatus(Simple, false, GetByIdVariant(StructureSet(structure), offset, specificValue)); >+ return GetByIdStatus(Simple, false, GetByIdVariant(StructureSet(structure), offset)); > #else > return GetByIdStatus(NoInformation, false); > #endif >@@ -156,18 +153,13 @@ GetByIdStatus GetByIdStatus::computeForS > if (structure->takesSlowPathInDFGForImpureProperty()) > return GetByIdStatus(slowPathState, true); > unsigned attributesIgnored; >- JSCell* specificValue; > GetByIdVariant variant; > variant.m_offset = structure->getConcurrently( >- *profiledBlock->vm(), uid, attributesIgnored, specificValue); >+ *profiledBlock->vm(), uid, attributesIgnored); > if (!isValidOffset(variant.m_offset)) > return GetByIdStatus(slowPathState, true); > >- if (structure->isDictionary()) >- specificValue = 0; >- > variant.m_structureSet.add(structure); >- variant.m_specificValue = JSValue(specificValue); > bool didAppend = result.appendVariant(variant); > ASSERT_UNUSED(didAppend, didAppend); > return result; >@@ -212,8 +204,7 @@ GetByIdStatus GetByIdStatus::computeForS > } > > GetByIdVariant variant( >- StructureSet(structure), complexGetStatus.offset(), >- complexGetStatus.specificValue(), complexGetStatus.chain(), >+ StructureSet(structure), complexGetStatus.offset(), complexGetStatus.chain(), > std::move(callLinkStatus)); > > if (!result.appendVariant(variant)) >@@ -297,16 +288,13 @@ GetByIdStatus GetByIdStatus::computeFor( > return GetByIdStatus(TakesSlowPath); > > unsigned attributes; >- JSCell* specificValue; >- PropertyOffset offset = structure->getConcurrently(vm, uid, attributes, specificValue); >+ PropertyOffset offset = structure->getConcurrently(vm, uid, attributes); > if (!isValidOffset(offset)) > return GetByIdStatus(TakesSlowPath); // It's probably a prototype lookup. Give up on life for now, even though we could totally be way smarter about it. > if (attributes & Accessor) > return GetByIdStatus(MakesCalls); // We could be smarter here, like strenght-reducing this to a Call. >- if (structure->isDictionary()) >- specificValue = 0; > >- if (!result.appendVariant(GetByIdVariant(structure, offset, specificValue))) >+ if (!result.appendVariant(GetByIdVariant(structure, offset))) > return GetByIdStatus(TakesSlowPath); > } > >Index: Source/JavaScriptCore/bytecode/GetByIdVariant.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/GetByIdVariant.cpp (revision 170724) >+++ Source/JavaScriptCore/bytecode/GetByIdVariant.cpp (working copy) >@@ -33,17 +33,15 @@ > namespace JSC { > > GetByIdVariant::GetByIdVariant( >- const StructureSet& structureSet, PropertyOffset offset, JSValue specificValue, >+ const StructureSet& structureSet, PropertyOffset offset, > const IntendedStructureChain* chain, std::unique_ptr<CallLinkStatus> callLinkStatus) > : m_structureSet(structureSet) > , m_alternateBase(nullptr) >- , m_specificValue(specificValue) > , m_offset(offset) > , m_callLinkStatus(std::move(callLinkStatus)) > { > if (!structureSet.size()) { > ASSERT(offset == invalidOffset); >- ASSERT(!specificValue); > ASSERT(!chain); > } > >@@ -66,7 +64,6 @@ GetByIdVariant& GetByIdVariant::operator > m_structureSet = other.m_structureSet; > m_constantChecks = other.m_constantChecks; > m_alternateBase = other.m_alternateBase; >- m_specificValue = other.m_specificValue; > m_offset = other.m_offset; > if (other.m_callLinkStatus) > m_callLinkStatus = std::make_unique<CallLinkStatus>(*other.m_callLinkStatus); >@@ -86,9 +83,6 @@ bool GetByIdVariant::attemptToMerge(cons > if (!areCompatible(m_constantChecks, other.m_constantChecks)) > return false; > >- if (m_specificValue != other.m_specificValue) >- m_specificValue = JSValue(); >- > mergeInto(other.m_constantChecks, m_constantChecks); > m_structureSet.merge(other.m_structureSet); > >@@ -112,8 +106,6 @@ void GetByIdVariant::dumpInContext(Print > "[", listDumpInContext(m_constantChecks, context), "]"); > if (m_alternateBase) > out.print(", alternateBase = ", inContext(JSValue(m_alternateBase), context)); >- if (specificValue()) >- out.print(", specificValue = ", inContext(specificValue(), context)); > out.print(", offset = ", offset()); > if (m_callLinkStatus) > out.print(", call = ", *m_callLinkStatus); >Index: Source/JavaScriptCore/bytecode/GetByIdVariant.h >=================================================================== >--- Source/JavaScriptCore/bytecode/GetByIdVariant.h (revision 170724) >+++ Source/JavaScriptCore/bytecode/GetByIdVariant.h (working copy) >@@ -42,8 +42,7 @@ struct DumpContext; > class GetByIdVariant { > public: > GetByIdVariant( >- const StructureSet& structureSet = StructureSet(), >- PropertyOffset offset = invalidOffset, JSValue specificValue = JSValue(), >+ const StructureSet& structureSet = StructureSet(), PropertyOffset offset = invalidOffset, > const IntendedStructureChain* chain = nullptr, > std::unique_ptr<CallLinkStatus> callLinkStatus = nullptr); > >@@ -58,7 +57,6 @@ public: > StructureSet& structureSet() { return m_structureSet; } > const ConstantStructureCheckVector& constantChecks() const { return m_constantChecks; } > JSObject* alternateBase() const { return m_alternateBase; } >- JSValue specificValue() const { return m_specificValue; } > PropertyOffset offset() const { return m_offset; } > CallLinkStatus* callLinkStatus() const { return m_callLinkStatus.get(); } > >@@ -73,7 +71,6 @@ private: > StructureSet m_structureSet; > ConstantStructureCheckVector m_constantChecks; > JSObject* m_alternateBase; >- JSValue m_specificValue; > PropertyOffset m_offset; > std::unique_ptr<CallLinkStatus> m_callLinkStatus; > }; >Index: Source/JavaScriptCore/bytecode/PutByIdStatus.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/PutByIdStatus.cpp (revision 170724) >+++ Source/JavaScriptCore/bytecode/PutByIdStatus.cpp (working copy) >@@ -254,8 +254,8 @@ PutByIdStatus PutByIdStatus::computeForS > locker, *stub->m_callLinkInfo, callExitSiteData)); > > variant = PutByIdVariant::setter( >- structure, complexGetStatus.offset(), complexGetStatus.specificValue(), >- complexGetStatus.chain(), std::move(callLinkStatus)); >+ structure, complexGetStatus.offset(), complexGetStatus.chain(), >+ std::move(callLinkStatus)); > } } > break; > } >@@ -334,19 +334,13 @@ PutByIdStatus PutByIdStatus::computeFor( > return PutByIdStatus(TakesSlowPath); > > unsigned attributes; >- JSCell* specificValue; >- PropertyOffset offset = structure->getConcurrently(vm, uid, attributes, specificValue); >+ PropertyOffset offset = structure->getConcurrently(vm, uid, attributes); > if (isValidOffset(offset)) { > if (attributes & CustomAccessor) > return PutByIdStatus(MakesCalls); > > if (attributes & (Accessor | ReadOnly)) > return PutByIdStatus(TakesSlowPath); >- if (specificValue) { >- // We need the PutById slow path to verify that we're storing the right value into >- // the specialized slot. >- return PutByIdStatus(TakesSlowPath); >- } > if (!result.appendVariant(PutByIdVariant::replace(structure, offset))) > return PutByIdStatus(TakesSlowPath); > continue; >@@ -384,22 +378,9 @@ PutByIdStatus PutByIdStatus::computeFor( > } > > // We only optimize if there is already a structure that the transition is cached to. >- // Among other things, this allows us to guard against a transition with a specific >- // value. >- // >- // - If we're storing a value that could be specific: this would only be a problem if >- // the existing transition did have a specific value already, since if it didn't, >- // then we would behave "as if" we were not storing a specific value. If it did >- // have a specific value, then we'll know - the fact that we pass 0 for >- // specificValue will tell us. >- // >- // - If we're not storing a value that could be specific: again, this would only be a >- // problem if the existing transition did have a specific value, which we check for >- // by passing 0 for the specificValue. >- Structure* transition = Structure::addPropertyTransitionToExistingStructureConcurrently(structure, uid, 0, 0, offset); >+ Structure* transition = Structure::addPropertyTransitionToExistingStructureConcurrently(structure, uid, 0, offset); > if (!transition) >- return PutByIdStatus(TakesSlowPath); // This occurs in bizarre cases only. See above. >- ASSERT(!transition->transitionDidInvolveSpecificValue()); >+ return PutByIdStatus(TakesSlowPath); > ASSERT(isValidOffset(offset)); > > bool didAppend = result.appendVariant( >Index: Source/JavaScriptCore/bytecode/PutByIdVariant.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/PutByIdVariant.cpp (revision 170724) >+++ Source/JavaScriptCore/bytecode/PutByIdVariant.cpp (working copy) >@@ -45,7 +45,6 @@ PutByIdVariant& PutByIdVariant::operator > m_newStructure = other.m_newStructure; > m_constantChecks = other.m_constantChecks; > m_alternateBase = other.m_alternateBase; >- m_specificValue = other.m_specificValue; > m_offset = other.m_offset; > if (other.m_callLinkStatus) > m_callLinkStatus = std::make_unique<CallLinkStatus>(*other.m_callLinkStatus); >@@ -78,7 +77,7 @@ PutByIdVariant PutByIdVariant::transitio > } > > PutByIdVariant PutByIdVariant::setter( >- const StructureSet& structure, PropertyOffset offset, JSValue specificValue, >+ const StructureSet& structure, PropertyOffset offset, > IntendedStructureChain* chain, std::unique_ptr<CallLinkStatus> callLinkStatus) > { > PutByIdVariant result; >@@ -89,7 +88,6 @@ PutByIdVariant PutByIdVariant::setter( > result.m_alternateBase = chain->terminalPrototype(); > } > result.m_offset = offset; >- result.m_specificValue = specificValue; > result.m_callLinkStatus = std::move(callLinkStatus); > return result; > } >@@ -229,8 +227,6 @@ void PutByIdVariant::dumpInContext(Print > listDumpInContext(constantChecks(), context), "]"); > if (m_alternateBase) > out.print(", alternateBase = ", inContext(JSValue(m_alternateBase), context)); >- if (m_specificValue) >- out.print(", specificValue = ", inContext(m_specificValue, context)); > out.print(", offset = ", m_offset); > out.print(", call = ", *m_callLinkStatus); > out.print(">"); >Index: Source/JavaScriptCore/bytecode/PutByIdVariant.h >=================================================================== >--- Source/JavaScriptCore/bytecode/PutByIdVariant.h (revision 170724) >+++ Source/JavaScriptCore/bytecode/PutByIdVariant.h (working copy) >@@ -62,7 +62,7 @@ public: > const IntendedStructureChain* structureChain, PropertyOffset offset); > > static PutByIdVariant setter( >- const StructureSet& structure, PropertyOffset offset, JSValue specificValue, >+ const StructureSet& structure, PropertyOffset offset, > IntendedStructureChain* chain, std::unique_ptr<CallLinkStatus> callLinkStatus); > > Kind kind() const { return m_kind; } >@@ -117,12 +117,6 @@ public: > return m_alternateBase; > } > >- JSValue specificValue() const >- { >- ASSERT(kind() == Setter); >- return m_specificValue; >- } >- > CallLinkStatus* callLinkStatus() const > { > ASSERT(kind() == Setter); >@@ -142,7 +136,6 @@ private: > Structure* m_newStructure; > ConstantStructureCheckVector m_constantChecks; > JSObject* m_alternateBase; >- JSValue m_specificValue; > PropertyOffset m_offset; > std::unique_ptr<CallLinkStatus> m_callLinkStatus; > }; >Index: Source/JavaScriptCore/bytecode/Watchpoint.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/Watchpoint.cpp (revision 170724) >+++ Source/JavaScriptCore/bytecode/Watchpoint.cpp (working copy) >@@ -70,11 +70,6 @@ void WatchpointSet::add(Watchpoint* watc > m_state = IsWatched; > } > >-void WatchpointSet::fireAll(const char* reason) >-{ >- fireAll(StringFireDetail(reason)); >-} >- > void WatchpointSet::fireAllSlow(const FireDetail& detail) > { > ASSERT(state() == IsWatched); >@@ -85,6 +80,11 @@ void WatchpointSet::fireAllSlow(const Fi > WTF::storeStoreFence(); > } > >+void WatchpointSet::fireAllSlow(const char* reason) >+{ >+ fireAllSlow(StringFireDetail(reason)); >+} >+ > void WatchpointSet::fireAllWatchpoints(const FireDetail& detail) > { > while (!m_set.isEmpty()) >Index: Source/JavaScriptCore/bytecode/Watchpoint.h >=================================================================== >--- Source/JavaScriptCore/bytecode/Watchpoint.h (revision 170724) >+++ Source/JavaScriptCore/bytecode/Watchpoint.h (working copy) >@@ -131,12 +131,17 @@ public: > > void fireAll(const FireDetail& detail) > { >- if (state() != IsWatched) >+ if (LIKELY(state() != IsWatched)) > return; > fireAllSlow(detail); > } > >- JS_EXPORT_PRIVATE void fireAll(const char* reason); >+ void fireAll(const char* reason) >+ { >+ if (LIKELY(state() != IsWatched)) >+ return; >+ fireAllSlow(reason); >+ } > > void touch(const FireDetail& detail) > { >@@ -157,6 +162,7 @@ public: > int8_t* addressOfSetIsNotEmpty() { return &m_setIsNotEmpty; } > > JS_EXPORT_PRIVATE void fireAllSlow(const FireDetail&); // Call only if you've checked isWatched. >+ JS_EXPORT_PRIVATE void fireAllSlow(const char* reason); // Ditto. > > private: > void fireAllWatchpoints(const FireDetail&); >Index: Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (revision 170724) >+++ Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (working copy) >@@ -30,6 +30,7 @@ > > #include "DFGAbstractInterpreter.h" > #include "GetByIdStatus.h" >+#include "GetterSetter.h" > #include "Operations.h" > #include "PutByIdStatus.h" > #include "StringObject.h" >@@ -1387,14 +1388,17 @@ bool AbstractInterpreter<AbstractStateTy > // something more subtle? > AbstractValue result; > for (unsigned i = status.numVariants(); i--;) { >- if (!status[i].specificValue()) { >+ DFG_ASSERT(m_graph, node, !status[i].alternateBase()); >+ JSValue constantResult = >+ m_graph.tryGetConstantProperty(value.m_value, status[i].offset()); >+ if (!constantResult) { > result.makeHeapTop(); > break; > } > > AbstractValue thisResult; > thisResult.set( >- m_graph, *m_graph.freeze(status[i].specificValue()), >+ m_graph, *m_graph.freeze(constantResult), > m_state.structureClobberState()); > result.merge(thisResult); > } >@@ -1569,11 +1573,27 @@ bool AbstractInterpreter<AbstractStateTy > } > > case GetByOffset: { >+ StorageAccessData data = m_graph.m_storageAccessData[node->storageAccessDataIndex()]; >+ JSValue result = m_graph.tryGetConstantProperty( >+ forNode(node->child2()).m_value, data.offset); >+ if (result) { >+ setConstant(node, *m_graph.freeze(result)); >+ break; >+ } >+ > forNode(node).makeHeapTop(); > break; > } > > case GetGetterSetterByOffset: { >+ StorageAccessData data = m_graph.m_storageAccessData[node->storageAccessDataIndex()]; >+ JSValue result = m_graph.tryGetConstantProperty( >+ forNode(node->child2()).m_value, data.offset); >+ if (result && jsDynamicCast<GetterSetter*>(result)) { >+ setConstant(node, *m_graph.freeze(result)); >+ break; >+ } >+ > forNode(node).set(m_graph, m_graph.m_vm.getterSetterStructure.get()); > break; > } >@@ -1602,14 +1622,22 @@ bool AbstractInterpreter<AbstractStateTy > if (set.isEmpty()) > continue; > baseSet.merge(set); >- if (!variant.specificValue()) { >+ >+ JSValue baseForLoad; >+ if (variant.alternateBase()) >+ baseForLoad = variant.alternateBase(); >+ else >+ baseForLoad = base.m_value; >+ JSValue constantResult = >+ m_graph.tryGetConstantProperty(baseForLoad, variant.offset()); >+ if (!constantResult) { > result.makeHeapTop(); > continue; > } > AbstractValue thisResult; > thisResult.set( > m_graph, >- *m_graph.freeze(variant.specificValue()), >+ *m_graph.freeze(constantResult), > m_state.structureClobberState()); > result.merge(thisResult); > } >Index: Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (revision 170724) >+++ Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (working copy) >@@ -1678,6 +1678,13 @@ bool ByteCodeParser::handleConstantInter > > Node* ByteCodeParser::handleGetByOffset(SpeculatedType prediction, Node* base, unsigned identifierNumber, PropertyOffset offset, NodeType op) > { >+ if (base->hasConstant()) { >+ if (JSValue constant = m_graph.tryGetConstantProperty(base->asJSValue(), offset)) { >+ addToGraph(Phantom, base); >+ return weakJSConstant(constant); >+ } >+ } >+ > Node* propertyStorage; > if (isInlineOffset(offset)) > propertyStorage = base; >@@ -1772,21 +1779,14 @@ void ByteCodeParser::handleGetById( > // Unless we want bugs like https://bugs.webkit.org/show_bug.cgi?id=88783, we need to > // ensure that the base of the original get_by_id is kept alive until we're done with > // all of the speculations. We only insert the Phantom if there had been a CheckStructure >- // on something other than the base following the CheckStructure on base, or if the >- // access was compiled to a WeakJSConstant specific value, in which case we might not >- // have any explicit use of the base at all. >- if (variant.specificValue() || originalBase != base) >+ // on something other than the base following the CheckStructure on base. >+ if (originalBase != base) > addToGraph(Phantom, originalBase); > >- Node* loadedValue; >- if (variant.specificValue()) >- loadedValue = weakJSConstant(variant.specificValue()); >- else { >- loadedValue = handleGetByOffset( >- variant.callLinkStatus() ? SpecCellOther : prediction, >- base, identifierNumber, variant.offset(), >- variant.callLinkStatus() ? GetGetterSetterByOffset : GetByOffset); >- } >+ Node* loadedValue = handleGetByOffset( >+ variant.callLinkStatus() ? SpecCellOther : prediction, >+ base, identifierNumber, variant.offset(), >+ variant.callLinkStatus() ? GetGetterSetterByOffset : GetByOffset); > > if (!variant.callLinkStatus()) { > set(VirtualRegister(destinationOperand), loadedValue); >@@ -1949,14 +1949,8 @@ void ByteCodeParser::handlePutById( > if (variant.alternateBase()) > base = weakJSConstant(variant.alternateBase()); > >- Node* loadedValue; >- if (variant.specificValue()) >- loadedValue = weakJSConstant(variant.specificValue()); >- else { >- loadedValue = handleGetByOffset( >- SpecCellOther, base, identifierNumber, variant.offset(), >- GetGetterSetterByOffset); >- } >+ Node* loadedValue = handleGetByOffset( >+ SpecCellOther, base, identifierNumber, variant.offset(), GetGetterSetterByOffset); > > Node* setter = addToGraph(GetSetter, loadedValue); > >@@ -2958,10 +2952,7 @@ bool ByteCodeParser::parseBlock(unsigned > } > Node* base = cellConstantWithStructureCheck(globalObject, status[0].structureSet().onlyStructure()); > addToGraph(Phantom, get(VirtualRegister(scope))); >- if (JSValue specificValue = status[0].specificValue()) >- set(VirtualRegister(dst), weakJSConstant(specificValue.asCell())); >- else >- set(VirtualRegister(dst), handleGetByOffset(prediction, base, identifierNumber, operand)); >+ set(VirtualRegister(dst), handleGetByOffset(prediction, base, identifierNumber, operand)); > break; > } > case GlobalVar: >@@ -2969,16 +2960,16 @@ bool ByteCodeParser::parseBlock(unsigned > addToGraph(Phantom, get(VirtualRegister(scope))); > SymbolTableEntry entry = globalObject->symbolTable()->get(uid); > VariableWatchpointSet* watchpointSet = entry.watchpointSet(); >- JSValue specificValue = >+ JSValue inferredValue = > watchpointSet ? watchpointSet->inferredValue() : JSValue(); >- if (!specificValue) { >+ if (!inferredValue) { > SpeculatedType prediction = getPrediction(); > set(VirtualRegister(dst), addToGraph(GetGlobalVar, OpInfo(operand), OpInfo(prediction))); > break; > } > > addToGraph(VariableWatchpoint, OpInfo(watchpointSet)); >- set(VirtualRegister(dst), weakJSConstant(specificValue)); >+ set(VirtualRegister(dst), weakJSConstant(inferredValue)); > break; > } > case ClosureVar: >Index: Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp (revision 170724) >+++ Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp (working copy) >@@ -407,8 +407,13 @@ private: > > addBaseCheck(indexInBlock, node, baseValue, variant.structureSet()); > >- if (variant.specificValue()) { >- m_graph.convertToConstant(node, m_graph.freeze(variant.specificValue())); >+ JSValue baseForLoad; >+ if (variant.alternateBase()) >+ baseForLoad = variant.alternateBase(); >+ else >+ baseForLoad = baseValue.m_value; >+ if (JSValue value = m_graph.tryGetConstantProperty(baseForLoad, variant.offset())) { >+ m_graph.convertToConstant(node, m_graph.freeze(value)); > return; > } > >Index: Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (revision 170724) >+++ Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (working copy) >@@ -1286,22 +1286,23 @@ private: > return true; > } > >- bool isStringPrototypeMethodSane(Structure* stringPrototypeStructure, StringImpl* uid) >+ bool isStringPrototypeMethodSane(JSObject* stringPrototype, StringImpl* uid) > { >+ Structure* structure = stringPrototype->structure(); >+ > unsigned attributesUnused; >- JSCell* specificValue; >- PropertyOffset offset = stringPrototypeStructure->getConcurrently( >- vm(), uid, attributesUnused, specificValue); >+ PropertyOffset offset = structure->getConcurrently(vm(), uid, attributesUnused); > if (!isValidOffset(offset)) > return false; > >- if (!specificValue) >+ JSValue value = m_graph.tryGetConstantProperty(stringPrototype, offset); >+ if (!value) > return false; > >- if (!specificValue->inherits(JSFunction::info())) >+ JSFunction* function = jsDynamicCast<JSFunction*>(value); >+ if (!function) > return false; > >- JSFunction* function = jsCast<JSFunction*>(specificValue); > if (function->executable()->intrinsicFor(CodeForCall) != StringPrototypeValueOfIntrinsic) > return false; > >@@ -1330,9 +1331,9 @@ private: > // (that would call toString()). We don't want the DFG to have to distinguish > // between the two, just because that seems like it would get confusing. So we > // just require both methods to be sane. >- if (!isStringPrototypeMethodSane(stringPrototypeStructure, vm().propertyNames->valueOf.impl())) >+ if (!isStringPrototypeMethodSane(stringPrototypeObject, vm().propertyNames->valueOf.impl())) > return false; >- if (!isStringPrototypeMethodSane(stringPrototypeStructure, vm().propertyNames->toString.impl())) >+ if (!isStringPrototypeMethodSane(stringPrototypeObject, vm().propertyNames->toString.impl())) > return false; > > return true; >Index: Source/JavaScriptCore/dfg/DFGGraph.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGGraph.cpp (revision 170724) >+++ Source/JavaScriptCore/dfg/DFGGraph.cpp (working copy) >@@ -789,6 +789,26 @@ unsigned Graph::requiredRegisterCountFor > return std::max(frameRegisterCount(), requiredRegisterCountForExit()); > } > >+JSValue Graph::tryGetConstantProperty(JSValue base, PropertyOffset offset) >+{ >+ if (!base || !base.isObject()) >+ return JSValue(); >+ >+ JSObject* object = asObject(base); >+ Structure* structure = object->structure(); >+ >+ WatchpointSet* set = structure->propertyReplacementWatchpointSet(offset); >+ if (!set || !set->isStillValid()) >+ return JSValue(); >+ >+ ASSERT(structure->isValidOffset(offset)); >+ ASSERT(!structure->isUncacheableDictionary()); >+ >+ watchpoints().addLazily(set); >+ >+ return object->getDirect(offset); >+} >+ > JSActivation* Graph::tryGetActivation(Node* node) > { > return node->dynamicCastConstant<JSActivation*>(); >@@ -900,7 +920,6 @@ void Graph::visitChildren(SlotVisitor& v > case MultiGetByOffset: > for (unsigned i = node->multiGetByOffsetData().variants.size(); i--;) { > GetByIdVariant& variant = node->multiGetByOffsetData().variants[i]; >- visitor.appendUnbarrieredReadOnlyValue(variant.specificValue()); > const StructureSet& set = variant.structureSet(); > for (unsigned j = set.size(); j--;) > visitor.appendUnbarrieredReadOnlyPointer(set[j]); >Index: Source/JavaScriptCore/dfg/DFGGraph.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGGraph.h (revision 170724) >+++ Source/JavaScriptCore/dfg/DFGGraph.h (working copy) >@@ -679,6 +679,8 @@ public: > unsigned requiredRegisterCountForExit(); > unsigned requiredRegisterCountForExecutionAndExit(); > >+ JSValue tryGetConstantProperty(JSValue base, PropertyOffset offset); >+ > JSActivation* tryGetActivation(Node*); > WriteBarrierBase<Unknown>* tryGetRegisters(Node*); > >Index: Source/JavaScriptCore/dfg/DFGWatchableStructureWatchingPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGWatchableStructureWatchingPhase.cpp (revision 170724) >+++ Source/JavaScriptCore/dfg/DFGWatchableStructureWatchingPhase.cpp (working copy) >@@ -86,7 +86,6 @@ public: > case MultiGetByOffset: > for (unsigned i = node->multiGetByOffsetData().variants.size(); i--;) { > GetByIdVariant& variant = node->multiGetByOffsetData().variants[i]; >- tryWatch(m_graph.freeze(variant.specificValue())->structure()); > tryWatch(variant.structureSet()); > // Don't need to watch anything in the structure chain because that would > // have been decomposed into CheckStructure's. Don't need to watch the >Index: Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (revision 170724) >+++ Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (working copy) >@@ -3234,8 +3234,13 @@ private: > > GetByIdVariant variant = data.variants[i]; > LValue result; >- if (variant.specificValue()) >- result = m_out.constInt64(JSValue::encode(variant.specificValue())); >+ JSValue constantResult; >+ if (variant.alternateBase()) { >+ constantResult = m_graph.tryGetConstantProperty( >+ variant.alternateBase(), variant.offset()); >+ } >+ if (constantResult) >+ result = m_out.constInt64(JSValue::encode(constantResult)); > else { > LValue propertyBase; > if (variant.alternateBase()) >Index: Source/JavaScriptCore/jit/Repatch.cpp >=================================================================== >--- Source/JavaScriptCore/jit/Repatch.cpp (revision 170724) >+++ Source/JavaScriptCore/jit/Repatch.cpp (working copy) >@@ -101,6 +101,8 @@ static void repatchByIdSelfAccess(VM& vm > { > if (structure->typeInfo().newImpurePropertyFiresWatchpoints()) > vm.registerWatchpointForImpureProperty(propertyName, stubInfo.addWatchpoint(codeBlock)); >+ >+ structure->startWatchingPropertyForReplacements(vm, offset); > > RepatchBuffer repatchBuffer(codeBlock); > >@@ -343,8 +345,11 @@ static void generateByIdStub( > failureCases, scratchGPR); > currStructure = it->get(); > } >+ ASSERT(protoObject->structure() == currStructure); > } > >+ currStructure->startWatchingPropertyForReplacements(*vm, offset); >+ > GPRReg baseForAccessGPR; > if (chain) { > stubJit.move(MacroAssembler::TrustedImmPtr(protoObject), scratchGPR); >Index: Source/JavaScriptCore/runtime/IntendedStructureChain.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/IntendedStructureChain.cpp (revision 170724) >+++ Source/JavaScriptCore/runtime/IntendedStructureChain.cpp (working copy) >@@ -107,8 +107,7 @@ bool IntendedStructureChain::mayIntercep > { > for (unsigned i = 0; i < m_vector.size(); ++i) { > unsigned attributes; >- JSCell* specificValue; >- PropertyOffset offset = m_vector[i]->getConcurrently(vm, uid, attributes, specificValue); >+ PropertyOffset offset = m_vector[i]->getConcurrently(vm, uid, attributes); > if (!isValidOffset(offset)) > continue; > if (attributes & (ReadOnly | Accessor)) >Index: Source/JavaScriptCore/runtime/JSCJSValue.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/JSCJSValue.cpp (revision 170724) >+++ Source/JavaScriptCore/runtime/JSCJSValue.cpp (working copy) >@@ -139,8 +139,7 @@ void JSValue::putToPrimitive(ExecState* > > for (; ; obj = asObject(prototype)) { > unsigned attributes; >- JSCell* specificValue; >- PropertyOffset offset = obj->structure()->get(vm, propertyName, attributes, specificValue); >+ PropertyOffset offset = obj->structure()->get(vm, propertyName, attributes); > if (offset != invalidOffset) { > if (attributes & ReadOnly) { > if (slot.isStrictMode()) >Index: Source/JavaScriptCore/runtime/JSGlobalObject.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/JSGlobalObject.cpp (revision 170724) >+++ Source/JavaScriptCore/runtime/JSGlobalObject.cpp (working copy) >@@ -282,7 +282,7 @@ void JSGlobalObject::reset(JSValue proto > m_functionPrototype.set(vm, this, FunctionPrototype::create(vm, FunctionPrototype::createStructure(vm, this, jsNull()))); // The real prototype will be set once ObjectPrototype is created. > m_functionStructure.set(vm, this, JSFunction::createStructure(vm, this, m_functionPrototype.get())); > m_boundFunctionStructure.set(vm, this, JSBoundFunction::createStructure(vm, this, m_functionPrototype.get())); >- m_namedFunctionStructure.set(vm, this, Structure::addPropertyTransition(vm, m_functionStructure.get(), vm.propertyNames->name, DontDelete | ReadOnly | DontEnum, 0, m_functionNameOffset)); >+ m_namedFunctionStructure.set(vm, this, Structure::addPropertyTransition(vm, m_functionStructure.get(), vm.propertyNames->name, DontDelete | ReadOnly | DontEnum, m_functionNameOffset)); > m_internalFunctionStructure.set(vm, this, InternalFunction::createStructure(vm, this, m_functionPrototype.get())); > JSFunction* callFunction = 0; > JSFunction* applyFunction = 0; >@@ -429,8 +429,8 @@ void JSGlobalObject::reset(JSValue proto > PrototypeMap& prototypeMap = vm.prototypeMap; > Structure* iteratorResultStructure = prototypeMap.emptyObjectStructureForPrototype(m_objectPrototype.get(), JSFinalObject::defaultInlineCapacity()); > PropertyOffset offset; >- iteratorResultStructure = Structure::addPropertyTransition(vm, iteratorResultStructure, vm.propertyNames->done, 0, 0, offset); >- iteratorResultStructure = Structure::addPropertyTransition(vm, iteratorResultStructure, vm.propertyNames->value, 0, 0, offset); >+ iteratorResultStructure = Structure::addPropertyTransition(vm, iteratorResultStructure, vm.propertyNames->done, 0, offset); >+ iteratorResultStructure = Structure::addPropertyTransition(vm, iteratorResultStructure, vm.propertyNames->value, 0, offset); > m_iteratorResultStructure.set(vm, this, iteratorResultStructure); > > m_evalFunction.set(vm, this, JSFunction::create(vm, this, 1, vm.propertyNames->eval.string(), globalFuncEval)); >Index: Source/JavaScriptCore/runtime/JSObject.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/JSObject.cpp (revision 170724) >+++ Source/JavaScriptCore/runtime/JSObject.cpp (working copy) >@@ -1,7 +1,7 @@ > /* > * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) > * Copyright (C) 2001 Peter Kelly (pmk@post.com) >- * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2012, 2013 Apple Inc. All rights reserved. >+ * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2012, 2013, 2014 Apple Inc. All rights reserved. > * Copyright (C) 2007 Eric Seidel (eric@webkit.org) > * > * This library is free software; you can redistribute it and/or >@@ -55,15 +55,6 @@ namespace JSC { > // ArrayConventions.h. > static unsigned lastArraySize = 0; > >-JSCell* getCallableObjectSlow(JSCell* cell) >-{ >- if (cell->type() == JSFunctionType) >- return cell; >- if (cell->structure()->classInfo()->isSubClassOf(InternalFunction::info())) >- return cell; >- return 0; >-} >- > STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSObject); > STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSFinalObject); > >@@ -360,7 +351,7 @@ void JSObject::put(JSCell* cell, ExecSta > prototype = obj->prototype(); > if (prototype.isNull()) { > ASSERT(!thisObject->structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName)); >- if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot, getCallableObject(value)) >+ if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot) > && slot.isStrictMode()) > throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError)); > return; >@@ -371,8 +362,7 @@ void JSObject::put(JSCell* cell, ExecSta > JSObject* obj; > for (obj = thisObject; ; obj = asObject(prototype)) { > unsigned attributes; >- JSCell* specificValue; >- PropertyOffset offset = obj->structure(vm)->get(vm, propertyName, attributes, specificValue); >+ PropertyOffset offset = obj->structure(vm)->get(vm, propertyName, attributes); > if (isValidOffset(offset)) { > if (attributes & ReadOnly) { > ASSERT(thisObject->structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject); >@@ -407,7 +397,7 @@ void JSObject::put(JSCell* cell, ExecSta > } > > ASSERT(!thisObject->structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName) || obj == thisObject); >- if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot, getCallableObject(value)) && slot.isStrictMode()) >+ if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot) && slot.isStrictMode()) > throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError)); > return; > } >@@ -1227,7 +1217,7 @@ void JSObject::putDirectAccessor(ExecSta > void JSObject::putDirectNonIndexAccessor(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes) > { > PutPropertySlot slot(this); >- putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot, getCallableObject(value)); >+ putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot); > > // putDirect will change our Structure if we add a new property. For > // getters and setters, though, we also need to change our Structure >@@ -1267,9 +1257,8 @@ bool JSObject::deleteProperty(JSCell* ce > thisObject->reifyStaticFunctionsForDelete(exec); > > unsigned attributes; >- JSCell* specificValue; > VM& vm = exec->vm(); >- if (isValidOffset(thisObject->structure(vm)->get(vm, propertyName, attributes, specificValue))) { >+ if (isValidOffset(thisObject->structure(vm)->get(vm, propertyName, attributes))) { > if (attributes & DontDelete && !vm.isInDefineOwnProperty()) > return false; > thisObject->removeDirect(vm, propertyName); >@@ -1353,7 +1342,7 @@ bool JSObject::deletePropertyByIndex(JSC > > static ALWAYS_INLINE JSValue callDefaultValueFunction(ExecState* exec, const JSObject* object, PropertyName propertyName) > { >- JSValue function = object->get(exec, propertyName); >+ JSValue function = object->getAndWatch(exec, propertyName); > CallData callData; > CallType callType = getCallData(function, callData); > if (callType == CallTypeNone) >@@ -1446,20 +1435,6 @@ bool JSObject::defaultHasInstance(ExecSt > return false; > } > >-bool JSObject::getPropertySpecificValue(ExecState* exec, PropertyName propertyName, JSCell*& specificValue) const >-{ >- VM& vm = exec->vm(); >- unsigned attributes; >- if (isValidOffset(structure(vm)->get(vm, propertyName, attributes, specificValue))) >- return true; >- >- // This could be a function within the static table? - should probably >- // also look in the hash? This currently should not be a problem, since >- // we've currently always call 'get' first, which should have populated >- // the normal storage. >- return false; >-} >- > void JSObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) > { > propertyNames.setBaseObject(object); >Index: Source/JavaScriptCore/runtime/JSObject.h >=================================================================== >--- Source/JavaScriptCore/runtime/JSObject.h (revision 170724) >+++ Source/JavaScriptCore/runtime/JSObject.h (working copy) >@@ -1,7 +1,7 @@ > /* > * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) > * Copyright (C) 2001 Peter Kelly (pmk@post.com) >- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012, 2013 Apple Inc. All rights reserved. >+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012, 2013, 2014 Apple Inc. All rights reserved. > * > * This library is free software; you can redistribute it and/or > * modify it under the terms of the GNU Library General Public >@@ -56,15 +56,6 @@ inline JSCell* getJSFunction(JSValue val > return 0; > } > >-JS_EXPORT_PRIVATE JSCell* getCallableObjectSlow(JSCell*); >- >-inline JSCell* getCallableObject(JSValue value) >-{ >- if (!value.isCell()) >- return 0; >- return getCallableObjectSlow(value.asCell()); >-} >- > class GetterSetter; > class InternalFunction; > class JSFunction; >@@ -119,6 +110,7 @@ public: > } > > JSValue get(ExecState*, PropertyName) const; >+ JSValue getAndWatch(ExecState*, PropertyName) const; > JSValue get(ExecState*, unsigned propertyName) const; > > bool fastGetOwnPropertySlot(ExecState*, VM&, Structure&, PropertyName, PropertySlot&); >@@ -491,8 +483,6 @@ public: > > JS_EXPORT_PRIVATE static JSValue toThis(JSCell*, ExecState*, ECMAMode); > >- bool getPropertySpecificValue(ExecState*, PropertyName, JSCell*& specificFunction) const; >- > // This get function only looks at the property map. > JSValue getDirect(VM& vm, PropertyName propertyName) const > { >@@ -504,9 +494,8 @@ public: > > JSValue getDirect(VM& vm, PropertyName propertyName, unsigned& attributes) const > { >- JSCell* specific; > Structure* structure = this->structure(vm); >- PropertyOffset offset = structure->get(vm, propertyName, attributes, specific); >+ PropertyOffset offset = structure->get(vm, propertyName, attributes); > checkOffset(offset, structure->inlineCapacity()); > return offset != invalidOffset ? getDirect(offset) : JSValue(); > } >@@ -521,9 +510,8 @@ public: > > PropertyOffset getDirectOffset(VM& vm, PropertyName propertyName, unsigned& attributes) > { >- JSCell* specific; > Structure* structure = this->structure(vm); >- PropertyOffset offset = structure->get(vm, propertyName, attributes, specific); >+ PropertyOffset offset = structure->get(vm, propertyName, attributes); > checkOffset(offset, structure->inlineCapacity()); > return offset; > } >@@ -949,7 +937,7 @@ private: > ArrayStorage* enterDictionaryIndexingModeWhenArrayStorageAlreadyExists(VM&, ArrayStorage*); > > template<PutMode> >- bool putDirectInternal(VM&, PropertyName, JSValue, unsigned attr, PutPropertySlot&, JSCell*); >+ bool putDirectInternal(VM&, PropertyName, JSValue, unsigned attr, PutPropertySlot&); > > bool inlineGetOwnPropertySlot(ExecState*, VM&, Structure&, PropertyName, PropertySlot&); > JS_EXPORT_PRIVATE void fillGetterPropertySlot(PropertySlot&, JSValue, unsigned, PropertyOffset); >@@ -1213,8 +1201,7 @@ inline JSValue JSObject::prototype() con > ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, VM& vm, Structure& structure, PropertyName propertyName, PropertySlot& slot) > { > unsigned attributes; >- JSCell* specific; >- PropertyOffset offset = structure.get(vm, propertyName, attributes, specific); >+ PropertyOffset offset = structure.get(vm, propertyName, attributes); > if (LIKELY(isValidOffset(offset))) { > JSValue value = getDirect(offset); > if (structure.hasGetterSetterProperties() && value.isGetterSetter()) >@@ -1285,6 +1272,20 @@ inline JSValue JSObject::get(ExecState* > return jsUndefined(); > } > >+inline JSValue JSObject::getAndWatch(ExecState* exec, PropertyName propertyName) const >+{ >+ PropertySlot slot(this); >+ if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot)) { >+ if (slot.isCacheable()) { >+ slot.slotBase()->structure()->startWatchingPropertyForReplacements( >+ exec->vm(), slot.cachedOffset()); >+ } >+ return slot.getValue(exec, propertyName); >+ } >+ >+ return jsUndefined(); >+} >+ > inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const > { > PropertySlot slot(this); >@@ -1295,7 +1296,7 @@ inline JSValue JSObject::get(ExecState* > } > > template<JSObject::PutMode mode> >-inline bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot, JSCell* specificFunction) >+inline bool JSObject::putDirectInternal(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot) > { > ASSERT(value); > ASSERT(value.isGetterSetter() == !!(attributes & Accessor)); >@@ -1305,25 +1306,15 @@ inline bool JSObject::putDirectInternal( > Structure* structure = this->structure(vm); > if (structure->isDictionary()) { > unsigned currentAttributes; >- JSCell* currentSpecificFunction; >- PropertyOffset offset = structure->get(vm, propertyName, currentAttributes, currentSpecificFunction); >+ PropertyOffset offset = structure->get(vm, propertyName, currentAttributes); > if (offset != invalidOffset) { >- // If there is currently a specific function, and there now either isn't, >- // or the new value is different, then despecify. >- if (currentSpecificFunction && (specificFunction != currentSpecificFunction)) >- structure->despecifyDictionaryFunction(vm, propertyName); > if ((mode == PutModePut) && currentAttributes & ReadOnly) > return false; > > putDirect(vm, offset, value); >- // At this point, the objects structure only has a specific value set if previously there >- // had been one set, and if the new value being specified is the same (otherwise we would >- // have despecified, above). So, if currentSpecificFunction is not set, or if the new >- // value is different (or there is no new value), then the slot now has no value - and >- // as such it is cachable. >- // If there was previously a value, and the new value is the same, then we cannot cache. >- if (!currentSpecificFunction || (specificFunction != currentSpecificFunction)) >- slot.setExistingProperty(this, offset); >+ structure->didReplaceProperty(offset); >+ >+ slot.setExistingProperty(this, offset); > return true; > } > >@@ -1334,15 +1325,13 @@ inline bool JSObject::putDirectInternal( > Butterfly* newButterfly = butterfly(); > if (this->structure()->putWillGrowOutOfLineStorage()) > newButterfly = growOutOfLineStorage(vm, this->structure()->outOfLineCapacity(), this->structure()->suggestedNewOutOfLineStorageCapacity()); >- offset = this->structure()->addPropertyWithoutTransition(vm, propertyName, attributes, specificFunction); >+ offset = this->structure()->addPropertyWithoutTransition(vm, propertyName, attributes); > setStructureAndButterfly(vm, this->structure(), newButterfly); > > validateOffset(offset); > ASSERT(this->structure()->isValidOffset(offset)); > putDirect(vm, offset, value); >- // See comment on setNewProperty call below. >- if (!specificFunction) >- slot.setNewProperty(this, offset); >+ slot.setNewProperty(this, offset); > if (attributes & ReadOnly) > this->structure()->setContainsReadOnlyProperties(); > return true; >@@ -1350,7 +1339,7 @@ inline bool JSObject::putDirectInternal( > > PropertyOffset offset; > size_t currentCapacity = this->structure()->outOfLineCapacity(); >- if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName, attributes, specificFunction, offset)) { >+ if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName, attributes, offset)) { > DeferGC deferGC(vm.heap); > Butterfly* newButterfly = butterfly(); > if (currentCapacity != structure->outOfLineCapacity()) { >@@ -1362,40 +1351,17 @@ inline bool JSObject::putDirectInternal( > ASSERT(structure->isValidOffset(offset)); > setStructureAndButterfly(vm, structure, newButterfly); > putDirect(vm, offset, value); >- // This is a new property; transitions with specific values are not currently cachable, >- // so leave the slot in an uncachable state. >- if (!specificFunction) >- slot.setNewProperty(this, offset); >+ slot.setNewProperty(this, offset); > return true; > } > > unsigned currentAttributes; >- JSCell* currentSpecificFunction; >- offset = structure->get(vm, propertyName, currentAttributes, currentSpecificFunction); >+ offset = structure->get(vm, propertyName, currentAttributes); > if (offset != invalidOffset) { > if ((mode == PutModePut) && currentAttributes & ReadOnly) > return false; > >- // There are three possibilities here: >- // (1) There is an existing specific value set, and we're overwriting with *the same value*. >- // * Do nothing - no need to despecify, but that means we can't cache (a cached >- // put could write a different value). Leave the slot in an uncachable state. >- // (2) There is a specific value currently set, but we're writing a different value. >- // * First, we have to despecify. Having done so, this is now a regular slot >- // with no specific value, so go ahead & cache like normal. >- // (3) Normal case, there is no specific value set. >- // * Go ahead & cache like normal. >- if (currentSpecificFunction) { >- // case (1) Do the put, then return leaving the slot uncachable. >- if (specificFunction == currentSpecificFunction) { >- putDirect(vm, offset, value); >- return true; >- } >- // case (2) Despecify, fall through to (3). >- setStructure(vm, Structure::despecifyFunctionTransition(vm, structure, propertyName)); >- } >- >- // case (3) set the slot, do the put, return. >+ structure->didReplaceProperty(offset); > slot.setExistingProperty(this, offset); > putDirect(vm, offset, value); > return true; >@@ -1404,17 +1370,14 @@ inline bool JSObject::putDirectInternal( > if ((mode == PutModePut) && !isExtensible()) > return false; > >- structure = Structure::addPropertyTransition(vm, structure, propertyName, attributes, specificFunction, offset, slot.context()); >+ structure = Structure::addPropertyTransition(vm, structure, propertyName, attributes, offset, slot.context()); > > validateOffset(offset); > ASSERT(structure->isValidOffset(offset)); > setStructureAndReallocateStorageIfNecessary(vm, structure); > > putDirect(vm, offset, value); >- // This is a new property; transitions with specific values are not currently cachable, >- // so leave the slot in an uncachable state. >- if (!specificFunction) >- slot.setNewProperty(this, offset); >+ slot.setNewProperty(this, offset); > if (attributes & ReadOnly) > structure->setContainsReadOnlyProperties(); > return true; >@@ -1447,20 +1410,20 @@ inline bool JSObject::putOwnDataProperty > ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); > ASSERT(!structure()->hasGetterSetterProperties()); > >- return putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot, getCallableObject(value)); >+ return putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot); > } > > inline void JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes) > { > ASSERT(!value.isGetterSetter() && !(attributes & Accessor)); > PutPropertySlot slot(this); >- putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot, getCallableObject(value)); >+ putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot); > } > > inline void JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, PutPropertySlot& slot) > { > ASSERT(!value.isGetterSetter()); >- putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, 0, slot, getCallableObject(value)); >+ putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, 0, slot); > } > > inline void JSObject::putDirectWithoutTransition(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes) >@@ -1470,7 +1433,7 @@ inline void JSObject::putDirectWithoutTr > Butterfly* newButterfly = m_butterfly.get(); > if (structure()->putWillGrowOutOfLineStorage()) > newButterfly = growOutOfLineStorage(vm, structure()->outOfLineCapacity(), structure()->suggestedNewOutOfLineStorageCapacity()); >- PropertyOffset offset = structure()->addPropertyWithoutTransition(vm, propertyName, attributes, getCallableObject(value)); >+ PropertyOffset offset = structure()->addPropertyWithoutTransition(vm, propertyName, attributes); > setStructureAndButterfly(vm, structure(), newButterfly); > putDirect(vm, offset, value); > } >Index: Source/JavaScriptCore/runtime/PropertyMapHashTable.h >=================================================================== >--- Source/JavaScriptCore/runtime/PropertyMapHashTable.h (revision 170724) >+++ Source/JavaScriptCore/runtime/PropertyMapHashTable.h (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. >+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2014 Apple Inc. All rights reserved. > * > * This library is free software; you can redistribute it and/or > * modify it under the terms of the GNU Library General Public >@@ -76,13 +76,11 @@ struct PropertyMapEntry { > StringImpl* key; > PropertyOffset offset; > unsigned attributes; >- WriteBarrier<JSCell> specificValue; > >- PropertyMapEntry(VM& vm, JSCell* owner, StringImpl* key, PropertyOffset offset, unsigned attributes, JSCell* specificValue) >+ PropertyMapEntry(StringImpl* key, PropertyOffset offset, unsigned attributes) > : key(key) > , offset(offset) > , attributes(attributes) >- , specificValue(vm, owner, specificValue, WriteBarrier<JSCell>::MayBeNull) > { > } > }; >@@ -141,8 +139,6 @@ public: > return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); > } > >- static void visitChildren(JSCell*, SlotVisitor&); >- > typedef StringImpl* KeyType; > typedef PropertyMapEntry ValueType; > >@@ -157,8 +153,8 @@ public: > > // Constructor is passed an initial capacity, a PropertyTable to copy, or both. > static PropertyTable* create(VM&, unsigned initialCapacity); >- static PropertyTable* clone(VM&, JSCell* owner, const PropertyTable&); >- static PropertyTable* clone(VM&, JSCell* owner, unsigned initialCapacity, const PropertyTable&); >+ static PropertyTable* clone(VM&, const PropertyTable&); >+ static PropertyTable* clone(VM&, unsigned initialCapacity, const PropertyTable&); > ~PropertyTable(); > > // Ordered iteration methods. >@@ -196,7 +192,7 @@ public: > PropertyOffset nextOffset(PropertyOffset inlineCapacity); > > // Copy this PropertyTable, ensuring the copy has at least the capacity provided. >- PropertyTable* copy(VM&, JSCell* owner, unsigned newCapacity); >+ PropertyTable* copy(VM&, unsigned newCapacity); > > #ifndef NDEBUG > size_t sizeInMemory(); >@@ -204,12 +200,12 @@ public: > #endif > > protected: >- static const unsigned StructureFlags = OverridesVisitChildren | StructureIsImmortal; >+ static const unsigned StructureFlags = StructureIsImmortal; > > private: > PropertyTable(VM&, unsigned initialCapacity); >- PropertyTable(VM&, JSCell*, const PropertyTable&); >- PropertyTable(VM&, JSCell*, unsigned initialCapacity, const PropertyTable&); >+ PropertyTable(VM&, const PropertyTable&); >+ PropertyTable(VM&, unsigned initialCapacity, const PropertyTable&); > > PropertyTable(const PropertyTable&); > // Used to insert a value known not to be in the table, and where we know capacity to be available. >@@ -494,15 +490,15 @@ inline PropertyOffset PropertyTable::nex > return offsetForPropertyNumber(size(), inlineCapacity); > } > >-inline PropertyTable* PropertyTable::copy(VM& vm, JSCell* owner, unsigned newCapacity) >+inline PropertyTable* PropertyTable::copy(VM& vm, unsigned newCapacity) > { > ASSERT(newCapacity >= m_keyCount); > > // Fast case; if the new table will be the same m_indexSize as this one, we can memcpy it, > // save rehashing all keys. > if (sizeForCapacity(newCapacity) == m_indexSize) >- return PropertyTable::clone(vm, owner, *this); >- return PropertyTable::clone(vm, owner, newCapacity, *this); >+ return PropertyTable::clone(vm, *this); >+ return PropertyTable::clone(vm, newCapacity, *this); > } > > #ifndef NDEBUG >Index: Source/JavaScriptCore/runtime/PropertyTable.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/PropertyTable.cpp (revision 170724) >+++ Source/JavaScriptCore/runtime/PropertyTable.cpp (working copy) >@@ -44,16 +44,16 @@ PropertyTable* PropertyTable::create(VM& > return table; > } > >-PropertyTable* PropertyTable::clone(VM& vm, JSCell* owner, const PropertyTable& other) >+PropertyTable* PropertyTable::clone(VM& vm, const PropertyTable& other) > { >- PropertyTable* table = new (NotNull, allocateCell<PropertyTable>(vm.heap)) PropertyTable(vm, owner, other); >+ PropertyTable* table = new (NotNull, allocateCell<PropertyTable>(vm.heap)) PropertyTable(vm, other); > table->finishCreation(vm); > return table; > } > >-PropertyTable* PropertyTable::clone(VM& vm, JSCell* owner, unsigned initialCapacity, const PropertyTable& other) >+PropertyTable* PropertyTable::clone(VM& vm, unsigned initialCapacity, const PropertyTable& other) > { >- PropertyTable* table = new (NotNull, allocateCell<PropertyTable>(vm.heap)) PropertyTable(vm, owner, initialCapacity, other); >+ PropertyTable* table = new (NotNull, allocateCell<PropertyTable>(vm.heap)) PropertyTable(vm, initialCapacity, other); > table->finishCreation(vm); > return table; > } >@@ -69,7 +69,7 @@ PropertyTable::PropertyTable(VM& vm, uns > ASSERT(isPowerOf2(m_indexSize)); > } > >-PropertyTable::PropertyTable(VM& vm, JSCell* owner, const PropertyTable& other) >+PropertyTable::PropertyTable(VM& vm, const PropertyTable& other) > : JSCell(vm, vm.propertyTableStructure.get()) > , m_indexSize(other.m_indexSize) > , m_indexMask(other.m_indexMask) >@@ -82,10 +82,8 @@ PropertyTable::PropertyTable(VM& vm, JSC > memcpy(m_index, other.m_index, dataSize()); > > iterator end = this->end(); >- for (iterator iter = begin(); iter != end; ++iter) { >+ for (iterator iter = begin(); iter != end; ++iter) > iter->key->ref(); >- vm.heap.writeBarrier(owner, iter->specificValue.get()); >- } > > // Copy the m_deletedOffsets vector. > Vector<PropertyOffset>* otherDeletedOffsets = other.m_deletedOffsets.get(); >@@ -93,7 +91,7 @@ PropertyTable::PropertyTable(VM& vm, JSC > m_deletedOffsets = adoptPtr(new Vector<PropertyOffset>(*otherDeletedOffsets)); > } > >-PropertyTable::PropertyTable(VM& vm, JSCell* owner, unsigned initialCapacity, const PropertyTable& other) >+PropertyTable::PropertyTable(VM& vm, unsigned initialCapacity, const PropertyTable& other) > : JSCell(vm, vm.propertyTableStructure.get()) > , m_indexSize(sizeForCapacity(initialCapacity)) > , m_indexMask(m_indexSize - 1) >@@ -109,7 +107,6 @@ PropertyTable::PropertyTable(VM& vm, JSC > ASSERT(canInsert()); > reinsert(*iter); > iter->key->ref(); >- vm.heap.writeBarrier(owner, iter->specificValue.get()); > } > > // Copy the m_deletedOffsets vector. >@@ -132,17 +129,4 @@ PropertyTable::~PropertyTable() > fastFree(m_index); > } > >-void PropertyTable::visitChildren(JSCell* cell, SlotVisitor& visitor) >-{ >- PropertyTable* thisObject = jsCast<PropertyTable*>(cell); >- ASSERT_GC_OBJECT_INHERITS(thisObject, info()); >- ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren()); >- >- JSCell::visitChildren(thisObject, visitor); >- >- PropertyTable::iterator end = thisObject->end(); >- for (PropertyTable::iterator ptr = thisObject->begin(); ptr != end; ++ptr) >- visitor.append(&ptr->specificValue); >-} >- > } >Index: Source/JavaScriptCore/runtime/Structure.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/Structure.cpp (revision 170724) >+++ Source/JavaScriptCore/runtime/Structure.cpp (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2008, 2009, 2013 Apple Inc. All rights reserved. >+ * Copyright (C) 2008, 2009, 2013, 2014 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -173,7 +173,6 @@ Structure::Structure(VM& vm, JSGlobalObj > setHasReadOnlyOrGetterSetterPropertiesExcludingProto(classInfo->hasStaticSetterOrReadonlyProperties(vm)); > setHasNonEnumerableProperties(false); > setAttributesInPrevious(0); >- setSpecificFunctionThrashCount(0); > setPreventExtensions(false); > setDidTransition(false); > setStaticFunctionsReified(false); >@@ -203,7 +202,6 @@ Structure::Structure(VM& vm) > setHasReadOnlyOrGetterSetterPropertiesExcludingProto(m_classInfo->hasStaticSetterOrReadonlyProperties(vm)); > setHasNonEnumerableProperties(false); > setAttributesInPrevious(0); >- setSpecificFunctionThrashCount(0); > setPreventExtensions(false); > setDidTransition(false); > setStaticFunctionsReified(false); >@@ -232,7 +230,6 @@ Structure::Structure(VM& vm, const Struc > setHasReadOnlyOrGetterSetterPropertiesExcludingProto(previous->hasReadOnlyOrGetterSetterPropertiesExcludingProto()); > setHasNonEnumerableProperties(previous->hasNonEnumerableProperties()); > setAttributesInPrevious(0); >- setSpecificFunctionThrashCount(previous->specificFunctionThrashCount()); > setPreventExtensions(previous->preventExtensions()); > setDidTransition(true); > setStaticFunctionsReified(previous->staticFunctionsReified()); >@@ -300,7 +297,7 @@ void Structure::materializePropertyMap(V > findStructuresAndMapForMaterialization(structures, structure, table); > > if (table) { >- table = table->copy(vm, structure, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity)); >+ table = table->copy(vm, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity)); > structure->m_lock.unlock(); > } > >@@ -317,7 +314,7 @@ void Structure::materializePropertyMap(V > structure = structures[i]; > if (!structure->m_nameInPrevious) > continue; >- PropertyMapEntry entry(vm, this, structure->m_nameInPrevious.get(), structure->m_offset, structure->attributesInPrevious(), structure->m_specificValueInPrevious.get()); >+ PropertyMapEntry entry(structure->m_nameInPrevious.get(), structure->m_offset, structure->attributesInPrevious()); > propertyTable()->add(entry, m_offset, PropertyTable::PropertyOffsetMustNotChange); > } > >@@ -336,30 +333,12 @@ size_t Structure::suggestedNewOutOfLineS > return nextOutOfLineStorageCapacity(outOfLineCapacity()); > } > >-void Structure::despecifyDictionaryFunction(VM& vm, PropertyName propertyName) >-{ >- StringImpl* rep = propertyName.uid(); >- >- DeferGC deferGC(vm.heap); >- materializePropertyMapIfNecessary(vm, deferGC); >- >- ASSERT(isDictionary()); >- ASSERT(propertyTable()); >- >- PropertyMapEntry* entry = propertyTable()->get(rep); >- ASSERT(entry); >- entry->specificValue.clear(); >-} >- >-Structure* Structure::addPropertyTransitionToExistingStructureImpl(Structure* structure, StringImpl* uid, unsigned attributes, JSCell* specificValue, PropertyOffset& offset) >+Structure* Structure::addPropertyTransitionToExistingStructureImpl(Structure* structure, StringImpl* uid, unsigned attributes, PropertyOffset& offset) > { > ASSERT(!structure->isDictionary()); > ASSERT(structure->isObject()); > > if (Structure* existingTransition = structure->m_transitionTable.get(uid, attributes)) { >- JSCell* specificValueInPrevious = existingTransition->m_specificValueInPrevious.get(); >- if (specificValueInPrevious && specificValueInPrevious != specificValue) >- return 0; > validateOffset(existingTransition->m_offset, existingTransition->inlineCapacity()); > offset = existingTransition->m_offset; > return existingTransition; >@@ -368,16 +347,16 @@ Structure* Structure::addPropertyTransit > return 0; > } > >-Structure* Structure::addPropertyTransitionToExistingStructure(Structure* structure, PropertyName propertyName, unsigned attributes, JSCell* specificValue, PropertyOffset& offset) >+Structure* Structure::addPropertyTransitionToExistingStructure(Structure* structure, PropertyName propertyName, unsigned attributes, PropertyOffset& offset) > { > ASSERT(!isCompilationThread()); >- return addPropertyTransitionToExistingStructureImpl(structure, propertyName.uid(), attributes, specificValue, offset); >+ return addPropertyTransitionToExistingStructureImpl(structure, propertyName.uid(), attributes, offset); > } > >-Structure* Structure::addPropertyTransitionToExistingStructureConcurrently(Structure* structure, StringImpl* uid, unsigned attributes, JSCell* specificValue, PropertyOffset& offset) >+Structure* Structure::addPropertyTransitionToExistingStructureConcurrently(Structure* structure, StringImpl* uid, unsigned attributes, PropertyOffset& offset) > { > ConcurrentJITLocker locker(structure->m_lock); >- return addPropertyTransitionToExistingStructureImpl(structure, uid, attributes, specificValue, offset); >+ return addPropertyTransitionToExistingStructureImpl(structure, uid, attributes, offset); > } > > bool Structure::anyObjectInChainMayInterceptIndexedAccesses() const >@@ -432,25 +411,12 @@ NonPropertyTransition Structure::suggest > return AllocateArrayStorage; > } > >-Structure* Structure::addPropertyTransition(VM& vm, Structure* structure, PropertyName propertyName, unsigned attributes, JSCell* specificValue, PropertyOffset& offset, PutPropertySlot::Context context) >+Structure* Structure::addPropertyTransition(VM& vm, Structure* structure, PropertyName propertyName, unsigned attributes, PropertyOffset& offset, PutPropertySlot::Context context) > { >- // If we have a specific function, we may have got to this point if there is >- // already a transition with the correct property name and attributes, but >- // specialized to a different function. In this case we just want to give up >- // and despecialize the transition. >- // In this case we clear the value of specificFunction which will result >- // in us adding a non-specific transition, and any subsequent lookup in >- // Structure::addPropertyTransitionToExistingStructure will just use that. >- if (specificValue && structure->m_transitionTable.contains(propertyName.uid(), attributes)) >- specificValue = 0; >- > ASSERT(!structure->isDictionary()); > ASSERT(structure->isObject()); >- ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, specificValue, offset)); >+ ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, offset)); > >- if (structure->specificFunctionThrashCount() == maxSpecificFunctionThrashCount) >- specificValue = 0; >- > int maxTransitionLength; > if (context == PutPropertySlot::PutById) > maxTransitionLength = s_maxTransitionLengthForNonEvalPutById; >@@ -459,7 +425,7 @@ Structure* Structure::addPropertyTransit > if (structure->transitionCount() > maxTransitionLength) { > Structure* transition = toCacheableDictionaryTransition(vm, structure); > ASSERT(structure != transition); >- offset = transition->putSpecificValue(vm, propertyName, attributes, specificValue); >+ offset = transition->add(vm, propertyName, attributes); > return transition; > } > >@@ -469,11 +435,10 @@ Structure* Structure::addPropertyTransit > transition->setPreviousID(vm, transition, structure); > transition->m_nameInPrevious = propertyName.uid(); > transition->setAttributesInPrevious(attributes); >- transition->m_specificValueInPrevious.setMayBeNull(vm, transition, specificValue); >- transition->propertyTable().set(vm, transition, structure->takePropertyTableOrCloneIfPinned(vm, transition)); >+ transition->propertyTable().set(vm, transition, structure->takePropertyTableOrCloneIfPinned(vm)); > transition->m_offset = structure->m_offset; > >- offset = transition->putSpecificValue(vm, propertyName, attributes, specificValue); >+ offset = transition->add(vm, propertyName, attributes); > > checkOffset(transition->m_offset, transition->inlineCapacity()); > { >@@ -505,34 +470,10 @@ Structure* Structure::changePrototypeTra > > DeferGC deferGC(vm.heap); > structure->materializePropertyMapIfNecessary(vm, deferGC); >- transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition)); >- transition->m_offset = structure->m_offset; >- transition->pin(); >- >- transition->checkOffsetConsistency(); >- return transition; >-} >- >-Structure* Structure::despecifyFunctionTransition(VM& vm, Structure* structure, PropertyName replaceFunction) >-{ >- ASSERT(structure->specificFunctionThrashCount() < maxSpecificFunctionThrashCount); >- Structure* transition = create(vm, structure); >- >- transition->setSpecificFunctionThrashCount(transition->specificFunctionThrashCount() + 1); >- >- DeferGC deferGC(vm.heap); >- structure->materializePropertyMapIfNecessary(vm, deferGC); >- transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition)); >+ transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm)); > transition->m_offset = structure->m_offset; > transition->pin(); > >- if (transition->specificFunctionThrashCount() == maxSpecificFunctionThrashCount) >- transition->despecifyAllFunctions(vm); >- else { >- bool removed = transition->despecifyFunction(vm, replaceFunction); >- ASSERT_UNUSED(removed, removed); >- } >- > transition->checkOffsetConsistency(); > return transition; > } >@@ -544,7 +485,7 @@ Structure* Structure::attributeChangeTra > Structure* transition = create(vm, structure); > > structure->materializePropertyMapIfNecessary(vm, deferGC); >- transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition)); >+ transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm)); > transition->m_offset = structure->m_offset; > transition->pin(); > >@@ -568,7 +509,7 @@ Structure* Structure::toDictionaryTransi > > DeferGC deferGC(vm.heap); > structure->materializePropertyMapIfNecessary(vm, deferGC); >- transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition)); >+ transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm)); > transition->m_offset = structure->m_offset; > transition->setDictionaryKind(kind); > transition->pin(); >@@ -631,7 +572,7 @@ Structure* Structure::preventExtensionsT > > DeferGC deferGC(vm.heap); > structure->materializePropertyMapIfNecessary(vm, deferGC); >- transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm, transition)); >+ transition->propertyTable().set(vm, transition, structure->copyPropertyTableForPinning(vm)); > transition->m_offset = structure->m_offset; > transition->setPreventExtensions(true); > transition->pin(); >@@ -640,13 +581,13 @@ Structure* Structure::preventExtensionsT > return transition; > } > >-PropertyTable* Structure::takePropertyTableOrCloneIfPinned(VM& vm, Structure* owner) >+PropertyTable* Structure::takePropertyTableOrCloneIfPinned(VM& vm) > { > DeferGC deferGC(vm.heap); > materializePropertyMapIfNecessaryForPinning(vm, deferGC); > > if (isPinnedPropertyTable()) >- return propertyTable()->copy(vm, owner, propertyTable()->size() + 1); >+ return propertyTable()->copy(vm, propertyTable()->size() + 1); > > // Hold the lock while stealing the table - so that getConcurrently() on another thread > // will either have to bypass this structure, or will get to use the property table >@@ -682,7 +623,7 @@ Structure* Structure::nonPropertyTransit > transition->setPreviousID(vm, transition, structure); > transition->setAttributesInPrevious(attributes); > transition->m_blob.setIndexingType(indexingType); >- transition->propertyTable().set(vm, transition, structure->takePropertyTableOrCloneIfPinned(vm, transition)); >+ transition->propertyTable().set(vm, transition, structure->takePropertyTableOrCloneIfPinned(vm)); > transition->m_offset = structure->m_offset; > checkOffset(transition->m_offset, transition->inlineCapacity()); > >@@ -773,19 +714,16 @@ Structure* Structure::flattenDictionaryS > return this; > } > >-PropertyOffset Structure::addPropertyWithoutTransition(VM& vm, PropertyName propertyName, unsigned attributes, JSCell* specificValue) >+PropertyOffset Structure::addPropertyWithoutTransition(VM& vm, PropertyName propertyName, unsigned attributes) > { > ASSERT(!enumerationCache()); > >- if (specificFunctionThrashCount() == maxSpecificFunctionThrashCount) >- specificValue = 0; >- > DeferGC deferGC(vm.heap); > materializePropertyMapIfNecessaryForPinning(vm, deferGC); > > pin(); > >- return putSpecificValue(vm, propertyName, attributes, specificValue); >+ return add(vm, propertyName, attributes); > } > > PropertyOffset Structure::removePropertyWithoutTransition(VM& vm, PropertyName propertyName) >@@ -812,11 +750,32 @@ void Structure::allocateRareData(VM& vm) > { > ASSERT(!hasRareData()); > StructureRareData* rareData = StructureRareData::create(vm, previous()); >+ WTF::storeStoreFence(); > m_previousOrRareData.set(vm, this, rareData); >+ WTF::storeStoreFence(); > setHasRareData(true); > ASSERT(hasRareData()); > } > >+void Structure::startWatchingPropertyForReplacements(VM& vm, PropertyOffset offset) >+{ >+ ASSERT(!isUncacheableDictionary()); >+ >+ if (!hasRareData()) >+ allocateRareData(vm); >+ ConcurrentJITLocker locker(m_lock); >+ StructureRareData* rareData = this->rareData(); >+ if (!rareData->m_replacementWatchpointSets) { >+ rareData->m_replacementWatchpointSets = >+ std::make_unique<StructureRareData::PropertyWatchpointMap>(); >+ WTF::storeStoreFence(); >+ } >+ auto result = rareData->m_replacementWatchpointSets->add(offset, nullptr); >+ if (!result.isNewEntry) >+ return; >+ result.iterator->value = adoptRef(new WatchpointSet(IsWatched)); >+} >+ > #if DUMP_PROPERTYMAP_STATS > > struct PropertyMapStatisticsExitLogger { >@@ -845,21 +804,21 @@ inline void Structure::checkConsistency( > > #endif > >-PropertyTable* Structure::copyPropertyTable(VM& vm, Structure* owner) >+PropertyTable* Structure::copyPropertyTable(VM& vm) > { > if (!propertyTable()) > return 0; >- return PropertyTable::clone(vm, owner, *propertyTable().get()); >+ return PropertyTable::clone(vm, *propertyTable().get()); > } > >-PropertyTable* Structure::copyPropertyTableForPinning(VM& vm, Structure* owner) >+PropertyTable* Structure::copyPropertyTableForPinning(VM& vm) > { > if (propertyTable()) >- return PropertyTable::clone(vm, owner, *propertyTable().get()); >+ return PropertyTable::clone(vm, *propertyTable().get()); > return PropertyTable::create(vm, numberOfSlotsForLastOffset(m_offset, m_inlineCapacity)); > } > >-PropertyOffset Structure::getConcurrently(VM&, StringImpl* uid, unsigned& attributes, JSCell*& specificValue) >+PropertyOffset Structure::getConcurrently(VM&, StringImpl* uid, unsigned& attributes) > { > Vector<Structure*, 8> structures; > Structure* structure; >@@ -871,7 +830,6 @@ PropertyOffset Structure::getConcurrentl > PropertyMapEntry* entry = table->get(uid); > if (entry) { > attributes = entry->attributes; >- specificValue = entry->specificValue.get(); > PropertyOffset result = entry->offset; > structure->m_lock.unlock(); > return result; >@@ -885,14 +843,13 @@ PropertyOffset Structure::getConcurrentl > continue; > > attributes = structure->attributesInPrevious(); >- specificValue = structure->m_specificValueInPrevious.get(); > return structure->m_offset; > } > > return invalidOffset; > } > >-PropertyOffset Structure::get(VM& vm, PropertyName propertyName, unsigned& attributes, JSCell*& specificValue) >+PropertyOffset Structure::get(VM& vm, PropertyName propertyName, unsigned& attributes) > { > ASSERT(!isCompilationThread()); > ASSERT(structure()->classInfo() == info()); >@@ -907,39 +864,10 @@ PropertyOffset Structure::get(VM& vm, Pr > return invalidOffset; > > attributes = entry->attributes; >- specificValue = entry->specificValue.get(); > return entry->offset; > } > >-bool Structure::despecifyFunction(VM& vm, PropertyName propertyName) >-{ >- DeferGC deferGC(vm.heap); >- materializePropertyMapIfNecessary(vm, deferGC); >- if (!propertyTable()) >- return false; >- >- PropertyMapEntry* entry = propertyTable()->get(propertyName.uid()); >- if (!entry) >- return false; >- >- ASSERT(entry->specificValue); >- entry->specificValue.clear(); >- return true; >-} >- >-void Structure::despecifyAllFunctions(VM& vm) >-{ >- DeferGC deferGC(vm.heap); >- materializePropertyMapIfNecessary(vm, deferGC); >- if (!propertyTable()) >- return; >- >- PropertyTable::iterator end = propertyTable()->end(); >- for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter) >- iter->specificValue.clear(); >-} >- >-PropertyOffset Structure::putSpecificValue(VM& vm, PropertyName propertyName, unsigned attributes, JSCell* specificValue) >+PropertyOffset Structure::add(VM& vm, PropertyName propertyName, unsigned attributes) > { > GCSafeConcurrentJITLocker locker(m_lock, vm.heap); > >@@ -956,7 +884,7 @@ PropertyOffset Structure::putSpecificVal > > PropertyOffset newOffset = propertyTable()->nextOffset(m_inlineCapacity); > >- propertyTable()->add(PropertyMapEntry(vm, this, rep, newOffset, attributes, specificValue), m_offset, PropertyTable::PropertyOffsetMayChange); >+ propertyTable()->add(PropertyMapEntry(rep, newOffset, attributes), m_offset, PropertyTable::PropertyOffsetMayChange); > > checkConsistency(); > return newOffset; >@@ -1060,7 +988,6 @@ void Structure::visitChildren(JSCell* ce > visitor.append(&thisObject->m_cachedPrototypeChain); > } > visitor.append(&thisObject->m_previousOrRareData); >- visitor.append(&thisObject->m_specificValueInPrevious); > > if (thisObject->isPinnedPropertyTable()) { > ASSERT(thisObject->m_propertyTableUnsafe); >@@ -1083,8 +1010,7 @@ bool Structure::prototypeChainMayInterce > current = prototype.asCell()->structure(vm); > > unsigned attributes; >- JSCell* specificValue; >- PropertyOffset offset = current->get(vm, propertyName, attributes, specificValue); >+ PropertyOffset offset = current->get(vm, propertyName, attributes); > if (!JSC::isValidOffset(offset)) > continue; > >@@ -1144,13 +1070,8 @@ void Structure::dump(PrintStream& out) c > if (table) { > PropertyTable::iterator iter = table->begin(); > PropertyTable::iterator end = table->end(); >- for (; iter != end; ++iter) { >+ for (; iter != end; ++iter) > out.print(comma, iter->key, ":", static_cast<int>(iter->offset)); >- if (iter->specificValue) { >- DumpContext dummyContext; >- out.print("=>", RawPointer(iter->specificValue.get())); >- } >- } > > structure->m_lock.unlock(); > } >@@ -1160,10 +1081,6 @@ void Structure::dump(PrintStream& out) c > if (!structure->m_nameInPrevious) > continue; > out.print(comma, structure->m_nameInPrevious.get(), ":", static_cast<int>(structure->m_offset)); >- if (structure->m_specificValueInPrevious) { >- DumpContext dummyContext; >- out.print("=>", RawPointer(structure->m_specificValueInPrevious.get())); >- } > } > > out.print("}, ", IndexingTypeDump(indexingType())); >Index: Source/JavaScriptCore/runtime/Structure.h >=================================================================== >--- Source/JavaScriptCore/runtime/Structure.h (revision 170724) >+++ Source/JavaScriptCore/runtime/Structure.h (working copy) >@@ -111,12 +111,11 @@ public: > > static void dumpStatistics(); > >- JS_EXPORT_PRIVATE static Structure* addPropertyTransition(VM&, Structure*, PropertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&, PutPropertySlot::Context = PutPropertySlot::UnknownContext); >- static Structure* addPropertyTransitionToExistingStructureConcurrently(Structure*, StringImpl* uid, unsigned attributes, JSCell* specificValue, PropertyOffset&); >- JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, PropertyName, unsigned attributes, JSCell* specificValue, PropertyOffset&); >+ JS_EXPORT_PRIVATE static Structure* addPropertyTransition(VM&, Structure*, PropertyName, unsigned attributes, PropertyOffset&, PutPropertySlot::Context = PutPropertySlot::UnknownContext); >+ static Structure* addPropertyTransitionToExistingStructureConcurrently(Structure*, StringImpl* uid, unsigned attributes, PropertyOffset&); >+ JS_EXPORT_PRIVATE static Structure* addPropertyTransitionToExistingStructure(Structure*, PropertyName, unsigned attributes, PropertyOffset&); > static Structure* removePropertyTransition(VM&, Structure*, PropertyName, PropertyOffset&); > JS_EXPORT_PRIVATE static Structure* changePrototypeTransition(VM&, Structure*, JSValue prototype); >- JS_EXPORT_PRIVATE static Structure* despecifyFunctionTransition(VM&, Structure*, PropertyName); > static Structure* attributeChangeTransition(VM&, Structure*, PropertyName, unsigned attributes); > static Structure* toCacheableDictionaryTransition(VM&, Structure*); > static Structure* toUncacheableDictionaryTransition(VM&, Structure*); >@@ -138,7 +137,7 @@ public: > static void destroy(JSCell*); > > // These should be used with caution. >- JS_EXPORT_PRIVATE PropertyOffset addPropertyWithoutTransition(VM&, PropertyName, unsigned attributes, JSCell* specificValue); >+ JS_EXPORT_PRIVATE PropertyOffset addPropertyWithoutTransition(VM&, PropertyName, unsigned attributes); > PropertyOffset removePropertyWithoutTransition(VM&, PropertyName); > void setPrototypeWithoutTransition(VM& vm, JSValue prototype) { m_prototype.set(vm, this, prototype); } > >@@ -188,8 +187,6 @@ public: > // Will just the prototype chain intercept this property access? > bool prototypeChainMayInterceptStoreTo(VM&, PropertyName); > >- bool transitionDidInvolveSpecificValue() const { return !!m_specificValueInPrevious; } >- > Structure* previousID() const > { > ASSERT(structure()->classInfo() == info()); >@@ -263,10 +260,10 @@ public: > > PropertyOffset get(VM&, PropertyName); > PropertyOffset get(VM&, const WTF::String& name); >- JS_EXPORT_PRIVATE PropertyOffset get(VM&, PropertyName, unsigned& attributes, JSCell*& specificValue); >+ JS_EXPORT_PRIVATE PropertyOffset get(VM&, PropertyName, unsigned& attributes); > > PropertyOffset getConcurrently(VM&, StringImpl* uid); >- PropertyOffset getConcurrently(VM&, StringImpl* uid, unsigned& attributes, JSCell*& specificValue); >+ PropertyOffset getConcurrently(VM&, StringImpl* uid, unsigned& attributes); > > void setHasGetterSetterPropertiesWithProtoCheck(bool is__proto__) > { >@@ -283,9 +280,6 @@ public: > return !JSC::isValidOffset(m_offset); > } > >- JS_EXPORT_PRIVATE void despecifyDictionaryFunction(VM&, PropertyName); >- void disableSpecificFunctionTracking() { setSpecificFunctionThrashCount(maxSpecificFunctionThrashCount); } >- > void setEnumerationCache(VM&, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h. > JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h. > void getPropertyNamesFromStructure(VM&, PropertyNameArray&, EnumerationMode); >@@ -364,13 +358,17 @@ public: > ASSERT(transitionWatchpointSetIsStillValid()); > m_transitionWatchpointSet.add(watchpoint); > } >- >+ > void notifyTransitionFromThisStructure() const; > > InlineWatchpointSet& transitionWatchpointSet() const > { > return m_transitionWatchpointSet; > } >+ >+ void startWatchingPropertyForReplacements(VM&, PropertyOffset); >+ void didReplaceProperty(PropertyOffset); >+ WatchpointSet* propertyReplacementWatchpointSet(PropertyOffset); > > PassRefPtr<StructureShape> toStructureShape(); > >@@ -406,7 +404,6 @@ public: > DEFINE_BITFIELD(bool, hasReadOnlyOrGetterSetterPropertiesExcludingProto, HasReadOnlyOrGetterSetterPropertiesExcludingProto, 1, 4); > DEFINE_BITFIELD(bool, hasNonEnumerableProperties, HasNonEnumerableProperties, 1, 5); > DEFINE_BITFIELD(unsigned, attributesInPrevious, AttributesInPrevious, 14, 6); >- DEFINE_BITFIELD(unsigned, specificFunctionThrashCount, SpecificFunctionThrashCount, 2, 20); > DEFINE_BITFIELD(bool, preventExtensions, PreventExtensions, 1, 22); > DEFINE_BITFIELD(bool, didTransition, DidTransition, 1, 23); > DEFINE_BITFIELD(bool, staticFunctionsReified, StaticFunctionsReified, 1, 24); >@@ -421,7 +418,7 @@ private: > > static Structure* create(VM&, const Structure*); > >- static Structure* addPropertyTransitionToExistingStructureImpl(Structure*, StringImpl* uid, unsigned attributes, JSCell* specificValue, PropertyOffset&); >+ static Structure* addPropertyTransitionToExistingStructureImpl(Structure*, StringImpl* uid, unsigned attributes, PropertyOffset&); > > // This will return the structure that has a usable property table, that property table, > // and the list of structures that we visited before we got to it. If it returns a >@@ -431,19 +428,16 @@ private: > > static Structure* toDictionaryTransition(VM&, Structure*, DictionaryKind); > >- PropertyOffset putSpecificValue(VM&, PropertyName, unsigned attributes, JSCell* specificValue); >+ PropertyOffset add(VM&, PropertyName, unsigned attributes); > PropertyOffset remove(PropertyName); > > void createPropertyMap(const GCSafeConcurrentJITLocker&, VM&, unsigned keyCount = 0); > void checkConsistency(); > >- bool despecifyFunction(VM&, PropertyName); >- void despecifyAllFunctions(VM&); >- > WriteBarrier<PropertyTable>& propertyTable(); >- PropertyTable* takePropertyTableOrCloneIfPinned(VM&, Structure* owner); >- PropertyTable* copyPropertyTable(VM&, Structure* owner); >- PropertyTable* copyPropertyTableForPinning(VM&, Structure* owner); >+ PropertyTable* takePropertyTableOrCloneIfPinned(VM&); >+ PropertyTable* copyPropertyTable(VM&); >+ PropertyTable* copyPropertyTableForPinning(VM&); > JS_EXPORT_PRIVATE void materializePropertyMap(VM&); > void materializePropertyMapIfNecessary(VM& vm, DeferGC&) > { >@@ -507,8 +501,6 @@ private: > static const int s_maxTransitionLength = 64; > static const int s_maxTransitionLengthForNonEvalPutById = 512; > >- static const unsigned maxSpecificFunctionThrashCount = 3; >- > // These need to be properly aligned at the beginning of the 'Structure' > // part of the object. > StructureIDBlob m_blob; >@@ -521,7 +513,6 @@ private: > WriteBarrier<JSCell> m_previousOrRareData; > > RefPtr<StringImpl> m_nameInPrevious; >- WriteBarrier<JSCell> m_specificValueInPrevious; > > const ClassInfo* m_classInfo; > >Index: Source/JavaScriptCore/runtime/StructureInlines.h >=================================================================== >--- Source/JavaScriptCore/runtime/StructureInlines.h (revision 170724) >+++ Source/JavaScriptCore/runtime/StructureInlines.h (working copy) >@@ -102,9 +102,7 @@ inline PropertyOffset Structure::get(VM& > inline PropertyOffset Structure::getConcurrently(VM& vm, StringImpl* uid) > { > unsigned attributesIgnored; >- JSCell* specificValueIgnored; >- return getConcurrently( >- vm, uid, attributesIgnored, specificValueIgnored); >+ return getConcurrently(vm, uid, attributesIgnored); > } > > inline bool Structure::hasIndexingHeader(const JSCell* cell) const >@@ -223,6 +221,31 @@ ALWAYS_INLINE WriteBarrier<PropertyTable > return m_propertyTableUnsafe; > } > >+inline void Structure::didReplaceProperty(PropertyOffset offset) >+{ >+ if (LIKELY(!hasRareData())) >+ return; >+ StructureRareData::PropertyWatchpointMap* map = rareData()->m_replacementWatchpointSets.get(); >+ if (LIKELY(!map)) >+ return; >+ WatchpointSet* set = map->get(offset); >+ if (LIKELY(!set)) >+ return; >+ set->fireAll("Property did get replaced"); >+} >+ >+inline WatchpointSet* Structure::propertyReplacementWatchpointSet(PropertyOffset offset) >+{ >+ ConcurrentJITLocker locker(m_lock); >+ if (!hasRareData()) >+ return nullptr; >+ WTF::loadLoadFence(); >+ StructureRareData::PropertyWatchpointMap* map = rareData()->m_replacementWatchpointSets.get(); >+ if (!map) >+ return nullptr; >+ return map->get(offset); >+} >+ > ALWAYS_INLINE bool Structure::checkOffsetConsistency() const > { > PropertyTable* propertyTable = m_propertyTableUnsafe.get(); >Index: Source/JavaScriptCore/runtime/StructureRareData.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/StructureRareData.cpp (revision 170724) >+++ Source/JavaScriptCore/runtime/StructureRareData.cpp (working copy) >@@ -46,6 +46,11 @@ StructureRareData* StructureRareData::cr > return rareData; > } > >+void StructureRareData::destroy(JSCell* cell) >+{ >+ static_cast<StructureRareData*>(cell)->StructureRareData::~StructureRareData(); >+} >+ > StructureRareData::StructureRareData(VM& vm, Structure* previous) > : JSCell(vm, vm.structureRareDataStructure.get()) > { >Index: Source/JavaScriptCore/runtime/StructureRareData.h >=================================================================== >--- Source/JavaScriptCore/runtime/StructureRareData.h (revision 170724) >+++ Source/JavaScriptCore/runtime/StructureRareData.h (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2013 Apple Inc. All rights reserved. >+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -29,6 +29,7 @@ > #include "ClassInfo.h" > #include "JSCell.h" > #include "JSTypeInfo.h" >+#include "PropertyOffset.h" > > namespace JSC { > >@@ -40,6 +41,10 @@ class StructureRareData : public JSCell > public: > static StructureRareData* create(VM&, Structure*); > >+ static const bool needsDestruction = true; >+ static const bool hasImmortalStructure = true; >+ static void destroy(JSCell*); >+ > static void visitChildren(JSCell*, SlotVisitor&); > > static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype); >@@ -53,10 +58,12 @@ public: > > JSPropertyNameIterator* enumerationCache(); > void setEnumerationCache(VM&, const Structure* owner, JSPropertyNameIterator* value); >- >+ > DECLARE_EXPORT_INFO; > > private: >+ friend class Structure; >+ > StructureRareData(VM&, Structure*); > > static const unsigned StructureFlags = OverridesVisitChildren | JSCell::StructureFlags; >@@ -64,6 +71,9 @@ private: > WriteBarrier<Structure> m_previous; > WriteBarrier<JSString> m_objectToStringValue; > WriteBarrier<JSPropertyNameIterator> m_enumerationCache; >+ >+ typedef HashMap<PropertyOffset, RefPtr<WatchpointSet>, WTF::IntHash<PropertyOffset>, WTF::UnsignedWithZeroKeyHashTraits<PropertyOffset>> PropertyWatchpointMap; >+ std::unique_ptr<PropertyWatchpointMap> m_replacementWatchpointSets; > }; > > } // namespace JSC
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 134567
:
234289
|
234309
|
234313
|
234315
|
234316
|
234379
|
234388
|
234419
|
234420
|
234427
|
234429
|
234432