WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
the patch
blah.patch (text/plain), 97.03 KB, created by
Filip Pizlo
on 2014-05-20 10:46:49 PDT
(
hide
)
Description:
the patch
Filename:
MIME Type:
Creator:
Filip Pizlo
Created:
2014-05-20 10:46:49 PDT
Size:
97.03 KB
patch
obsolete
>Index: Source/JavaScriptCore/ChangeLog >=================================================================== >--- Source/JavaScriptCore/ChangeLog (revision 169119) >+++ Source/JavaScriptCore/ChangeLog (working copy) >@@ -1,3 +1,162 @@ >+2014-05-20 Filip Pizlo <fpizlo@apple.com> >+ >+ [ftlopt] DFG bytecode parser should turn GetById with nothing but a Getter stub as stuff+handleCall, and handleCall should be allowed to inline if it wants to >+ https://bugs.webkit.org/show_bug.cgi?id=133105 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ - GetByIdStatus now knows about getters and can report intelligent things about them. >+ As is usually the case with how we do these things, GetByIdStatus knows more about >+ getters than the DFG can actually handle: it'll report details about polymorphic >+ getter calls even though the DFG won't be able to handle those. This is fine; the DFG >+ will see those statuses and bail to a generic slow path. >+ >+ - The DFG::ByteCodeParser now knows how to set up and do handleCall() for a getter call. >+ This can, and usually does, result in inlining of getters! >+ >+ - CodeOrigin and OSR exit know about inlined getter calls. When you OSR out of an >+ inlined getter, we set the return PC to a getter return thunk that fixes up the stack. >+ We use the usual offset-true-return-PC trick, where OSR exit places the true return PC >+ of the getter's caller as a phony argument that only the thunk knows how to find. >+ >+ - Removed a bunch of dead monomorphic chain support from StructureStubInfo. >+ >+ - A large chunk of this change is dragging GetGetterSetterByOffset, GetGetter, and >+ GetSetter through the DFG and FTL. GetGetterSetterByOffset is like GetByOffset except >+ that we know that we're returning a GetterSetter cell. GetGetter and GetSetter extract >+ the getter, or setter, from the GetterSetter. >+ >+ Still testing the performance impact. >+ >+ * bytecode/CodeBlock.cpp: >+ (JSC::CodeBlock::printGetByIdCacheStatus): >+ (JSC::CodeBlock::findStubInfo): >+ * bytecode/CodeBlock.h: >+ * bytecode/CodeOrigin.cpp: >+ (WTF::printInternal): >+ * bytecode/CodeOrigin.h: >+ (JSC::InlineCallFrame::specializationKindFor): >+ * bytecode/GetByIdStatus.cpp: >+ (JSC::GetByIdStatus::computeFor): >+ (JSC::GetByIdStatus::computeForStubInfo): >+ (JSC::GetByIdStatus::makesCalls): >+ (JSC::GetByIdStatus::computeForChain): Deleted. >+ * bytecode/GetByIdStatus.h: >+ (JSC::GetByIdStatus::makesCalls): Deleted. >+ * bytecode/GetByIdVariant.cpp: >+ (JSC::GetByIdVariant::~GetByIdVariant): >+ (JSC::GetByIdVariant::GetByIdVariant): >+ (JSC::GetByIdVariant::operator=): >+ (JSC::GetByIdVariant::dumpInContext): >+ * bytecode/GetByIdVariant.h: >+ (JSC::GetByIdVariant::GetByIdVariant): >+ (JSC::GetByIdVariant::callLinkStatus): >+ * bytecode/PolymorphicGetByIdList.cpp: >+ (JSC::GetByIdAccess::fromStructureStubInfo): >+ (JSC::PolymorphicGetByIdList::from): >+ * bytecode/SpeculatedType.h: >+ * bytecode/StructureStubInfo.cpp: >+ (JSC::StructureStubInfo::deref): >+ (JSC::StructureStubInfo::visitWeakReferences): >+ * bytecode/StructureStubInfo.h: >+ (JSC::isGetByIdAccess): >+ (JSC::StructureStubInfo::initGetByIdChain): Deleted. >+ * dfg/DFGAbstractHeap.h: >+ * dfg/DFGAbstractInterpreterInlines.h: >+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): >+ * dfg/DFGByteCodeParser.cpp: >+ (JSC::DFG::ByteCodeParser::addCall): >+ (JSC::DFG::ByteCodeParser::handleCall): >+ (JSC::DFG::ByteCodeParser::handleInlining): >+ (JSC::DFG::ByteCodeParser::handleGetByOffset): >+ (JSC::DFG::ByteCodeParser::handleGetById): >+ (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry): >+ (JSC::DFG::ByteCodeParser::parse): >+ * dfg/DFGCSEPhase.cpp: >+ (JSC::DFG::CSEPhase::getGetterSetterByOffsetLoadElimination): >+ (JSC::DFG::CSEPhase::getInternalFieldLoadElimination): >+ (JSC::DFG::CSEPhase::performNodeCSE): >+ (JSC::DFG::CSEPhase::getTypedArrayByteOffsetLoadElimination): Deleted. >+ * dfg/DFGClobberize.h: >+ (JSC::DFG::clobberize): >+ * dfg/DFGFixupPhase.cpp: >+ (JSC::DFG::FixupPhase::fixupNode): >+ * dfg/DFGJITCompiler.cpp: >+ (JSC::DFG::JITCompiler::linkFunction): >+ * dfg/DFGNode.h: >+ (JSC::DFG::Node::hasStorageAccessData): >+ * dfg/DFGNodeType.h: >+ * dfg/DFGOSRExitCompilerCommon.cpp: >+ (JSC::DFG::reifyInlinedCallFrames): >+ * dfg/DFGPredictionPropagationPhase.cpp: >+ (JSC::DFG::PredictionPropagationPhase::propagate): >+ * dfg/DFGSafeToExecute.h: >+ (JSC::DFG::safeToExecute): >+ * dfg/DFGSpeculativeJIT32_64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * dfg/DFGSpeculativeJIT64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * ftl/FTLAbstractHeapRepository.cpp: >+ * ftl/FTLAbstractHeapRepository.h: >+ * ftl/FTLCapabilities.cpp: >+ (JSC::FTL::canCompile): >+ * ftl/FTLLink.cpp: >+ (JSC::FTL::link): >+ * ftl/FTLLowerDFGToLLVM.cpp: >+ (JSC::FTL::LowerDFGToLLVM::compileNode): >+ (JSC::FTL::LowerDFGToLLVM::compileGetGetter): >+ (JSC::FTL::LowerDFGToLLVM::compileGetSetter): >+ * jit/AccessorCallJITStubRoutine.h: >+ * jit/JIT.cpp: >+ (JSC::JIT::assertStackPointerOffset): >+ (JSC::JIT::privateCompile): >+ * jit/JIT.h: >+ * jit/JITPropertyAccess.cpp: >+ (JSC::JIT::emit_op_get_by_id): >+ * jit/ThunkGenerators.cpp: >+ (JSC::arityFixupGenerator): >+ (JSC::baselineGetterReturnThunkGenerator): >+ (JSC::baselineSetterReturnThunkGenerator): >+ (JSC::arityFixup): Deleted. >+ * jit/ThunkGenerators.h: >+ * runtime/CommonSlowPaths.cpp: >+ (JSC::setupArityCheckData): >+ * tests/stress/exit-from-getter.js: Added. >+ * tests/stress/poly-chain-getter.js: Added. >+ (Cons): >+ (foo): >+ (test): >+ * tests/stress/poly-chain-then-getter.js: Added. >+ (Cons1): >+ (Cons2): >+ (foo): >+ (test): >+ * tests/stress/poly-getter-combo.js: Added. >+ (Cons1): >+ (Cons2): >+ (foo): >+ (test): >+ (.test): >+ * tests/stress/poly-getter-then-chain.js: Added. >+ (Cons1): >+ (Cons2): >+ (foo): >+ (test): >+ * tests/stress/poly-getter-then-self.js: Added. >+ (foo): >+ (test): >+ (.test): >+ * tests/stress/poly-self-getter.js: Added. >+ (foo): >+ (test): >+ (getter): >+ * tests/stress/poly-self-then-getter.js: Added. >+ (foo): >+ (test): >+ * tests/stress/weird-getter-counter.js: Added. >+ (foo): >+ (test): >+ > 2014-05-17 Filip Pizlo <fpizlo@apple.com> > > [ftlopt] Factor out how CallLinkStatus uses exit site data >Index: Source/JavaScriptCore/bytecode/CodeBlock.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/CodeBlock.cpp (revision 169014) >+++ Source/JavaScriptCore/bytecode/CodeBlock.cpp (working copy) >@@ -352,11 +352,6 @@ void CodeBlock::printGetByIdCacheStatus( > out.printf("self"); > baseStructure = stubInfo.u.getByIdSelf.baseObjectStructure.get(); > break; >- case access_get_by_id_chain: >- out.printf("chain"); >- baseStructure = stubInfo.u.getByIdChain.baseObjectStructure.get(); >- chain = stubInfo.u.getByIdChain.chain.get(); >- break; > case access_get_by_id_list: > out.printf("list"); > list = stubInfo.u.getByIdList.list; >@@ -2344,6 +2339,15 @@ StructureStubInfo* CodeBlock::addStubInf > return m_stubInfos.add(); > } > >+StructureStubInfo* CodeBlock::findStubInfo(CodeOrigin codeOrigin) >+{ >+ for (StructureStubInfo* stubInfo : m_stubInfos) { >+ if (stubInfo->codeOrigin == codeOrigin) >+ return stubInfo; >+ } >+ return nullptr; >+} >+ > CallLinkInfo* CodeBlock::addCallLinkInfo() > { > ConcurrentJITLocker locker(m_lock); >Index: Source/JavaScriptCore/bytecode/CodeBlock.h >=================================================================== >--- Source/JavaScriptCore/bytecode/CodeBlock.h (revision 169014) >+++ Source/JavaScriptCore/bytecode/CodeBlock.h (working copy) >@@ -201,6 +201,10 @@ public: > StructureStubInfo* addStubInfo(); > Bag<StructureStubInfo>::iterator stubInfoBegin() { return m_stubInfos.begin(); } > Bag<StructureStubInfo>::iterator stubInfoEnd() { return m_stubInfos.end(); } >+ >+ // O(n) operation. Use getStubInfoMap() unless you really only intend to get one >+ // stub info. >+ StructureStubInfo* findStubInfo(CodeOrigin); > > void resetStub(StructureStubInfo&); > >Index: Source/JavaScriptCore/bytecode/CodeOrigin.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/CodeOrigin.cpp (revision 169014) >+++ Source/JavaScriptCore/bytecode/CodeOrigin.cpp (working copy) >@@ -206,6 +206,12 @@ void printInternal(PrintStream& out, JSC > case JSC::InlineCallFrame::Construct: > out.print("Construct"); > return; >+ case JSC::InlineCallFrame::GetterCall: >+ out.print("GetterCall"); >+ return; >+ case JSC::InlineCallFrame::SetterCall: >+ out.print("SetterCall"); >+ return; > } > RELEASE_ASSERT_NOT_REACHED(); > } >Index: Source/JavaScriptCore/bytecode/CodeOrigin.h >=================================================================== >--- Source/JavaScriptCore/bytecode/CodeOrigin.h (revision 169014) >+++ Source/JavaScriptCore/bytecode/CodeOrigin.h (working copy) >@@ -121,6 +121,11 @@ struct InlineCallFrame { > enum Kind { > Call, > Construct, >+ >+ // For these, the stackOffset incorporates the argument count plus the true return PC >+ // slot. >+ GetterCall, >+ SetterCall > }; > > static Kind kindFor(CodeSpecializationKind kind) >@@ -139,6 +144,8 @@ struct InlineCallFrame { > { > switch (kind) { > case Call: >+ case GetterCall: >+ case SetterCall: > return CodeForCall; > case Construct: > return CodeForConstruct; >@@ -153,7 +160,7 @@ struct InlineCallFrame { > CodeOrigin caller; > BitVector capturedVars; // Indexed by the machine call frame's variable numbering. > signed stackOffset : 30; >- Kind kind : 1; >+ Kind kind : 2; > bool isClosureCall : 1; // If false then we know that callee/scope are constants and the DFG won't treat them as variables, i.e. they have to be recovered manually. > VirtualRegister argumentsRegister; // This is only set if the code uses arguments. The unmodified arguments register follows the unmodifiedArgumentsRegister() convention (see CodeBlock.h). > >Index: Source/JavaScriptCore/bytecode/GetByIdStatus.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/GetByIdStatus.cpp (revision 169014) >+++ Source/JavaScriptCore/bytecode/GetByIdStatus.cpp (working copy) >@@ -26,6 +26,7 @@ > #include "config.h" > #include "GetByIdStatus.h" > >+#include "AccessorCallJITStubRoutine.h" > #include "CodeBlock.h" > #include "JSCInlines.h" > #include "JSScope.h" >@@ -89,57 +90,6 @@ GetByIdStatus GetByIdStatus::computeFrom > #endif > } > >-bool GetByIdStatus::computeForChain(CodeBlock* profiledBlock, StringImpl* uid, PassRefPtr<IntendedStructureChain> passedChain) >-{ >-#if ENABLE(JIT) >- RefPtr<IntendedStructureChain> chain = passedChain; >- >- // Validate the chain. If the chain is invalid, then currently the best thing >- // we can do is to assume that TakesSlow is true. In the future, it might be >- // worth exploring reifying the structure chain from the structure we've got >- // instead of using the one from the cache, since that will do the right things >- // if the structure chain has changed. But that may be harder, because we may >- // then end up having a different type of access altogether. And it currently >- // does not appear to be worth it to do so -- effectively, the heuristic we >- // have now is that if the structure chain has changed between when it was >- // cached on in the baseline JIT and when the DFG tried to inline the access, >- // then we fall back on a polymorphic access. >- if (!chain->isStillValid()) >- return false; >- >- if (chain->head()->takesSlowPathInDFGForImpureProperty()) >- return false; >- size_t chainSize = chain->size(); >- for (size_t i = 0; i < chainSize; i++) { >- if (chain->at(i)->takesSlowPathInDFGForImpureProperty()) >- return false; >- } >- >- JSObject* currentObject = chain->terminalPrototype(); >- Structure* currentStructure = chain->last(); >- >- ASSERT_UNUSED(currentObject, currentObject); >- >- unsigned attributesIgnored; >- JSCell* specificValue; >- >- PropertyOffset offset = currentStructure->getConcurrently( >- *profiledBlock->vm(), uid, attributesIgnored, specificValue); >- if (currentStructure->isDictionary()) >- specificValue = 0; >- if (!isValidOffset(offset)) >- return false; >- >- return appendVariant(GetByIdVariant(StructureSet(chain->head()), offset, specificValue, chain)); >-#else // ENABLE(JIT) >- UNUSED_PARAM(profiledBlock); >- UNUSED_PARAM(uid); >- UNUSED_PARAM(passedChain); >- UNREACHABLE_FOR_PLATFORM(); >- return false; >-#endif // ENABLE(JIT) >-} >- > GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, StubInfoMap& map, unsigned bytecodeIndex, StringImpl* uid) > { > ConcurrentJITLocker locker(profiledBlock->m_lock); >@@ -148,12 +98,13 @@ GetByIdStatus GetByIdStatus::computeFor( > > #if ENABLE(DFG_JIT) > result = computeForStubInfo( >- locker, profiledBlock, map.get(CodeOrigin(bytecodeIndex)), uid); >+ locker, profiledBlock, map.get(CodeOrigin(bytecodeIndex)), uid, >+ CallLinkStatus::computeExitSiteData(locker, profiledBlock, bytecodeIndex)); > > if (!result.takesSlowPath() > && (hasExitSite(locker, profiledBlock, bytecodeIndex) > || profiledBlock->likelyToTakeSlowCase(bytecodeIndex))) >- return GetByIdStatus(TakesSlowPath, true); >+ return GetByIdStatus(result.makesCalls() ? MakesCalls : TakesSlowPath, true); > #else > UNUSED_PARAM(map); > #endif >@@ -166,24 +117,24 @@ GetByIdStatus GetByIdStatus::computeFor( > > #if ENABLE(JIT) > GetByIdStatus GetByIdStatus::computeForStubInfo( >- const ConcurrentJITLocker&, CodeBlock* profiledBlock, StructureStubInfo* stubInfo, >- StringImpl* uid) >+ const ConcurrentJITLocker& locker, CodeBlock* profiledBlock, StructureStubInfo* stubInfo, >+ StringImpl* uid, CallLinkStatus::ExitSiteData callExitSiteData) > { > if (!stubInfo || !stubInfo->seen) > return GetByIdStatus(NoInformation); > >- if (stubInfo->resetByGC) >- return GetByIdStatus(TakesSlowPath, true); >- > PolymorphicGetByIdList* list = 0; >+ State takesSlowPath = TakesSlowPath; > if (stubInfo->accessType == access_get_by_id_list) { > list = stubInfo->u.getByIdList.list; >- for (unsigned i = 0; i < list->size(); ++i) { >- if (list->at(i).doesCalls()) >- return GetByIdStatus(MakesCalls, true); >- } >+ >+ for (unsigned i = 0; i < list->size(); ++i) >+ takesSlowPath = MakesCalls; > } > >+ if (stubInfo->resetByGC) >+ return GetByIdStatus(takesSlowPath, true); >+ > // Finally figure out if we can derive an access strategy. > GetByIdStatus result; > result.m_state = Simple; >@@ -215,8 +166,6 @@ GetByIdStatus GetByIdStatus::computeForS > > case access_get_by_id_list: { > for (unsigned listIndex = 0; listIndex < list->size(); ++listIndex) { >- ASSERT(!list->at(listIndex).doesCalls()); >- > Structure* structure = list->at(listIndex).structure(); > > // FIXME: We should assert that we never see a structure that >@@ -226,70 +175,110 @@ GetByIdStatus GetByIdStatus::computeForS > // https://bugs.webkit.org/show_bug.cgi?id=131810 > > if (structure->takesSlowPathInDFGForImpureProperty()) >- return GetByIdStatus(TakesSlowPath, true); >+ return GetByIdStatus(takesSlowPath, true); > >+ unsigned attributesIgnored; >+ JSCell* specificValue; >+ PropertyOffset myOffset; >+ RefPtr<IntendedStructureChain> chain; >+ > if (list->at(listIndex).chain()) { >- RefPtr<IntendedStructureChain> chain = adoptRef(new IntendedStructureChain( >+ chain = adoptRef(new IntendedStructureChain( > profiledBlock, structure, list->at(listIndex).chain(), > list->at(listIndex).chainCount())); >- if (!result.computeForChain(profiledBlock, uid, chain)) >- return GetByIdStatus(TakesSlowPath, true); >- continue; >+ >+ if (!chain->isStillValid()) >+ return GetByIdStatus(takesSlowPath, true); >+ >+ if (chain->head()->takesSlowPathInDFGForImpureProperty()) >+ return GetByIdStatus(takesSlowPath, true); >+ >+ size_t chainSize = chain->size(); >+ for (size_t i = 0; i < chainSize; i++) { >+ if (chain->at(i)->takesSlowPathInDFGForImpureProperty()) >+ return GetByIdStatus(takesSlowPath, true); >+ } >+ >+ JSObject* currentObject = chain->terminalPrototype(); >+ Structure* currentStructure = chain->last(); >+ >+ ASSERT_UNUSED(currentObject, currentObject); >+ >+ myOffset = currentStructure->getConcurrently( >+ *profiledBlock->vm(), uid, attributesIgnored, specificValue); >+ if (currentStructure->isDictionary()) >+ specificValue = 0; >+ } else { >+ myOffset = structure->getConcurrently( >+ *profiledBlock->vm(), uid, attributesIgnored, specificValue); >+ if (structure->isDictionary()) >+ specificValue = 0; > } > >- unsigned attributesIgnored; >- JSCell* specificValue; >- PropertyOffset myOffset = structure->getConcurrently( >- *profiledBlock->vm(), uid, attributesIgnored, specificValue); >- if (structure->isDictionary()) >- specificValue = 0; >- > if (!isValidOffset(myOffset)) >- return GetByIdStatus(TakesSlowPath, true); >+ return GetByIdStatus(takesSlowPath, true); > >- bool found = false; >- for (unsigned variantIndex = 0; variantIndex < result.m_variants.size(); ++variantIndex) { >- GetByIdVariant& variant = result.m_variants[variantIndex]; >- if (variant.m_chain) >- continue; >+ if (!chain && !list->at(listIndex).doesCalls()) { >+ // For non-chain, non-getter accesses, we try to do some coalescing. >+ bool found = false; >+ for (unsigned variantIndex = 0; variantIndex < result.m_variants.size(); ++variantIndex) { >+ GetByIdVariant& variant = result.m_variants[variantIndex]; >+ if (variant.m_chain) >+ continue; > >- if (variant.m_offset != myOffset) >- continue; >- >- found = true; >- if (variant.m_structureSet.contains(structure)) >- break; >+ if (variant.m_offset != myOffset) >+ continue; > >- if (variant.m_specificValue != JSValue(specificValue)) >- variant.m_specificValue = JSValue(); >+ if (variant.callLinkStatus()) >+ continue; > >- variant.m_structureSet.add(structure); >- break; >+ found = true; >+ if (variant.m_structureSet.contains(structure)) >+ break; >+ >+ if (variant.m_specificValue != JSValue(specificValue)) >+ variant.m_specificValue = JSValue(); >+ >+ variant.m_structureSet.add(structure); >+ break; >+ } >+ >+ if (found) >+ continue; > } > >- if (found) >- continue; >+ std::unique_ptr<CallLinkStatus> callLinkStatus; >+ switch (list->at(listIndex).type()) { >+ case GetByIdAccess::SimpleInline: >+ case GetByIdAccess::SimpleStub: { >+ break; >+ } >+ case GetByIdAccess::Getter: { >+ AccessorCallJITStubRoutine* stub = static_cast<AccessorCallJITStubRoutine*>( >+ list->at(listIndex).stubRoutine()); >+ callLinkStatus = std::make_unique<CallLinkStatus>( >+ CallLinkStatus::computeFor(locker, *stub->m_callLinkInfo, callExitSiteData)); >+ break; >+ } >+ case GetByIdAccess::CustomGetter: { >+ // FIXME: It would be totally sweet to support this at some point in the future. >+ // https://bugs.webkit.org/show_bug.cgi?id=133052 >+ return GetByIdStatus(takesSlowPath, true); >+ } >+ default: >+ RELEASE_ASSERT_NOT_REACHED(); >+ } > >- if (!result.appendVariant(GetByIdVariant(StructureSet(structure), myOffset, specificValue))) >- return GetByIdStatus(TakesSlowPath, true); >+ GetByIdVariant variant( >+ StructureSet(structure), myOffset, specificValue, chain, >+ std::move(callLinkStatus)); >+ if (!result.appendVariant(variant)) >+ return GetByIdStatus(takesSlowPath, true); > } > > return result; > } > >- case access_get_by_id_chain: { >- if (!stubInfo->u.getByIdChain.isDirect) >- return GetByIdStatus(MakesCalls, true); >- RefPtr<IntendedStructureChain> chain = adoptRef(new IntendedStructureChain( >- profiledBlock, >- stubInfo->u.getByIdChain.baseObjectStructure.get(), >- stubInfo->u.getByIdChain.chain.get(), >- stubInfo->u.getByIdChain.count)); >- if (result.computeForChain(profiledBlock, uid, chain)) >- return result; >- return GetByIdStatus(TakesSlowPath, true); >- } >- > default: > return GetByIdStatus(TakesSlowPath, true); > } >@@ -305,10 +294,18 @@ GetByIdStatus GetByIdStatus::computeFor( > { > #if ENABLE(DFG_JIT) > if (dfgBlock) { >+ CallLinkStatus::ExitSiteData exitSiteData; >+ { >+ ConcurrentJITLocker locker(profiledBlock->m_lock); >+ exitSiteData = CallLinkStatus::computeExitSiteData( >+ locker, profiledBlock, codeOrigin.bytecodeIndex, ExitFromFTL); >+ } >+ > GetByIdStatus result; > { > ConcurrentJITLocker locker(dfgBlock->m_lock); >- result = computeForStubInfo(locker, dfgBlock, dfgMap.get(codeOrigin), uid); >+ result = computeForStubInfo( >+ locker, dfgBlock, dfgMap.get(codeOrigin), uid, exitSiteData); > } > > if (result.takesSlowPath()) >@@ -361,6 +358,24 @@ GetByIdStatus GetByIdStatus::computeFor( > Simple, false, GetByIdVariant(StructureSet(structure), offset, specificValue)); > } > >+bool GetByIdStatus::makesCalls() const >+{ >+ switch (m_state) { >+ case NoInformation: >+ case TakesSlowPath: >+ return false; >+ case Simple: >+ for (unsigned i = m_variants.size(); i--;) { >+ if (m_variants[i].callLinkStatus()) >+ return true; >+ } >+ return false; >+ case MakesCalls: >+ return true; >+ } >+ RELEASE_ASSERT_NOT_REACHED(); >+} >+ > void GetByIdStatus::dump(PrintStream& out) const > { > out.print("("); >Index: Source/JavaScriptCore/bytecode/GetByIdStatus.h >=================================================================== >--- Source/JavaScriptCore/bytecode/GetByIdStatus.h (revision 169014) >+++ Source/JavaScriptCore/bytecode/GetByIdStatus.h (working copy) >@@ -26,6 +26,7 @@ > #ifndef GetByIdStatus_h > #define GetByIdStatus_h > >+#include "CallLinkStatus.h" > #include "CodeOrigin.h" > #include "ConcurrentJITLock.h" > #include "ExitingJITType.h" >@@ -83,7 +84,7 @@ public: > const GetByIdVariant& operator[](size_t index) const { return at(index); } > > bool takesSlowPath() const { return m_state == TakesSlowPath || m_state == MakesCalls; } >- bool makesCalls() const { return m_state == MakesCalls; } >+ bool makesCalls() const; > > bool wasSeenInJIT() const { return m_wasSeenInJIT; } > >@@ -94,9 +95,10 @@ private: > static bool hasExitSite(const ConcurrentJITLocker&, CodeBlock*, unsigned bytecodeIndex, ExitingJITType = ExitFromAnything); > #endif > #if ENABLE(JIT) >- static GetByIdStatus computeForStubInfo(const ConcurrentJITLocker&, CodeBlock*, StructureStubInfo*, StringImpl* uid); >+ static GetByIdStatus computeForStubInfo( >+ const ConcurrentJITLocker&, CodeBlock* profiledBlock, StructureStubInfo*, >+ StringImpl* uid, CallLinkStatus::ExitSiteData); > #endif >- bool computeForChain(CodeBlock*, StringImpl* uid, PassRefPtr<IntendedStructureChain>); > static GetByIdStatus computeFromLLInt(CodeBlock*, unsigned bytecodeIndex, StringImpl* uid); > > bool appendVariant(const GetByIdVariant&); >Index: Source/JavaScriptCore/bytecode/GetByIdVariant.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/GetByIdVariant.cpp (revision 169014) >+++ Source/JavaScriptCore/bytecode/GetByIdVariant.cpp (working copy) >@@ -26,10 +26,31 @@ > #include "config.h" > #include "GetByIdVariant.h" > >+#include "CallLinkStatus.h" > #include "JSCInlines.h" > > namespace JSC { > >+GetByIdVariant::~GetByIdVariant() { } >+ >+GetByIdVariant::GetByIdVariant(const GetByIdVariant& other) >+{ >+ *this = other; >+} >+ >+GetByIdVariant& GetByIdVariant::operator=(const GetByIdVariant& other) >+{ >+ m_structureSet = other.m_structureSet; >+ m_chain = other.m_chain; >+ m_specificValue = other.m_specificValue; >+ m_offset = other.m_offset; >+ if (other.m_callLinkStatus) >+ m_callLinkStatus = std::make_unique<CallLinkStatus>(*other.m_callLinkStatus); >+ else >+ m_callLinkStatus = nullptr; >+ return *this; >+} >+ > void GetByIdVariant::dump(PrintStream& out) const > { > dumpInContext(out, 0); >@@ -45,7 +66,10 @@ void GetByIdVariant::dumpInContext(Print > out.print( > "<", inContext(structureSet(), context), ", ", > pointerDumpInContext(chain(), context), ", ", >- inContext(specificValue(), context), ", ", offset(), ">"); >+ inContext(specificValue(), context), ", ", offset()); >+ if (m_callLinkStatus) >+ out.print("call: ", *m_callLinkStatus); >+ out.print(">"); > } > > } // namespace JSC >Index: Source/JavaScriptCore/bytecode/GetByIdVariant.h >=================================================================== >--- Source/JavaScriptCore/bytecode/GetByIdVariant.h (revision 169014) >+++ Source/JavaScriptCore/bytecode/GetByIdVariant.h (working copy) >@@ -26,6 +26,7 @@ > #ifndef GetByIdVariant_h > #define GetByIdVariant_h > >+#include "CallLinkStatus.h" > #include "IntendedStructureChain.h" > #include "JSCJSValue.h" > #include "PropertyOffset.h" >@@ -33,6 +34,7 @@ > > namespace JSC { > >+class CallLinkStatus; > class GetByIdStatus; > struct DumpContext; > >@@ -41,11 +43,13 @@ public: > GetByIdVariant( > const StructureSet& structureSet = StructureSet(), > PropertyOffset offset = invalidOffset, JSValue specificValue = JSValue(), >- PassRefPtr<IntendedStructureChain> chain = nullptr) >+ PassRefPtr<IntendedStructureChain> chain = nullptr, >+ std::unique_ptr<CallLinkStatus> callLinkStatus = nullptr) > : m_structureSet(structureSet) > , m_chain(chain) > , m_specificValue(specificValue) > , m_offset(offset) >+ , m_callLinkStatus(std::move(callLinkStatus)) > { > if (!structureSet.size()) { > ASSERT(offset == invalidOffset); >@@ -54,12 +58,18 @@ public: > } > } > >+ ~GetByIdVariant(); >+ >+ GetByIdVariant(const GetByIdVariant&); >+ GetByIdVariant& operator=(const GetByIdVariant&); >+ > bool isSet() const { return !!m_structureSet.size(); } > bool operator!() const { return !isSet(); } > const StructureSet& structureSet() const { return m_structureSet; } > IntendedStructureChain* chain() const { return const_cast<IntendedStructureChain*>(m_chain.get()); } > JSValue specificValue() const { return m_specificValue; } > PropertyOffset offset() const { return m_offset; } >+ CallLinkStatus* callLinkStatus() const { return m_callLinkStatus.get(); } > > void dump(PrintStream&) const; > void dumpInContext(PrintStream&, DumpContext*) const; >@@ -71,6 +81,7 @@ private: > RefPtr<IntendedStructureChain> m_chain; > JSValue m_specificValue; > PropertyOffset m_offset; >+ std::unique_ptr<CallLinkStatus> m_callLinkStatus; > }; > > } // namespace JSC >Index: Source/JavaScriptCore/bytecode/PolymorphicGetByIdList.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/PolymorphicGetByIdList.cpp (revision 169014) >+++ Source/JavaScriptCore/bytecode/PolymorphicGetByIdList.cpp (working copy) >@@ -58,27 +58,11 @@ GetByIdAccess GetByIdAccess::fromStructu > > GetByIdAccess result; > >- switch (stubInfo.accessType) { >- case access_get_by_id_self: >- result.m_type = SimpleInline; >- result.m_structure.copyFrom(stubInfo.u.getByIdSelf.baseObjectStructure); >- result.m_stubRoutine = JITStubRoutine::createSelfManagedRoutine(initialSlowPath); >- break; >- >- case access_get_by_id_chain: >- result.m_structure.copyFrom(stubInfo.u.getByIdChain.baseObjectStructure); >- result.m_chain.copyFrom(stubInfo.u.getByIdChain.chain); >- result.m_chainCount = stubInfo.u.getByIdChain.count; >- result.m_stubRoutine = stubInfo.stubRoutine; >- if (stubInfo.u.getByIdChain.isDirect) >- result.m_type = SimpleStub; >- else >- result.m_type = Getter; >- break; >- >- default: >- RELEASE_ASSERT_NOT_REACHED(); >- } >+ RELEASE_ASSERT(stubInfo.accessType == access_get_by_id_self); >+ >+ result.m_type = SimpleInline; >+ result.m_structure.copyFrom(stubInfo.u.getByIdSelf.baseObjectStructure); >+ result.m_stubRoutine = JITStubRoutine::createSelfManagedRoutine(initialSlowPath); > > return result; > } >@@ -109,7 +93,6 @@ PolymorphicGetByIdList* PolymorphicGetBy > > ASSERT( > stubInfo.accessType == access_get_by_id_self >- || stubInfo.accessType == access_get_by_id_chain > || stubInfo.accessType == access_unset); > > PolymorphicGetByIdList* result = new PolymorphicGetByIdList(stubInfo); >Index: Source/JavaScriptCore/bytecode/SpeculatedType.h >=================================================================== >--- Source/JavaScriptCore/bytecode/SpeculatedType.h (revision 169014) >+++ Source/JavaScriptCore/bytecode/SpeculatedType.h (working copy) >@@ -59,7 +59,7 @@ static const SpeculatedType SpecObject > static const SpeculatedType SpecStringIdent = 0x00010000; // It's definitely a JSString, and it's an identifier. > static const SpeculatedType SpecStringVar = 0x00020000; // It's definitely a JSString, and it's not an identifier. > static const SpeculatedType SpecString = 0x00030000; // It's definitely a JSString. >-static const SpeculatedType SpecCellOther = 0x00040000; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString. >+static const SpeculatedType SpecCellOther = 0x00040000; // It's definitely a JSCell but not a subclass of JSObject and definitely not a JSString. FIXME: This shouldn't be part of heap-top or bytecode-top. https://bugs.webkit.org/show_bug.cgi?id=133078 > static const SpeculatedType SpecCell = 0x0007ffff; // It's definitely a JSCell. > static const SpeculatedType SpecInt32 = 0x00200000; // It's definitely an Int32. > static const SpeculatedType SpecInt52 = 0x00400000; // It's definitely an Int52 and we intend it to unbox it. >Index: Source/JavaScriptCore/bytecode/StructureStubInfo.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/StructureStubInfo.cpp (revision 169014) >+++ Source/JavaScriptCore/bytecode/StructureStubInfo.cpp (working copy) >@@ -49,7 +49,6 @@ void StructureStubInfo::deref() > return; > } > case access_get_by_id_self: >- case access_get_by_id_chain: > case access_put_by_id_transition_normal: > case access_put_by_id_transition_direct: > case access_put_by_id_replace: >@@ -68,11 +67,6 @@ bool StructureStubInfo::visitWeakReferen > if (!Heap::isMarked(u.getByIdSelf.baseObjectStructure.get())) > return false; > break; >- case access_get_by_id_chain: >- if (!Heap::isMarked(u.getByIdChain.baseObjectStructure.get()) >- || !Heap::isMarked(u.getByIdChain.chain.get())) >- return false; >- break; > case access_get_by_id_list: { > if (!u.getByIdList.list->visitWeak(repatchBuffer)) > return false; >Index: Source/JavaScriptCore/bytecode/StructureStubInfo.h >=================================================================== >--- Source/JavaScriptCore/bytecode/StructureStubInfo.h (revision 169014) >+++ Source/JavaScriptCore/bytecode/StructureStubInfo.h (working copy) >@@ -47,7 +47,6 @@ class PolymorphicPutByIdList; > > enum AccessType { > access_get_by_id_self, >- access_get_by_id_chain, > access_get_by_id_list, > access_put_by_id_transition_normal, > access_put_by_id_transition_direct, >@@ -61,7 +60,6 @@ inline bool isGetByIdAccess(AccessType a > { > switch (accessType) { > case access_get_by_id_self: >- case access_get_by_id_chain: > case access_get_by_id_list: > return true; > default: >@@ -107,16 +105,6 @@ struct StructureStubInfo { > u.getByIdSelf.baseObjectStructure.set(vm, owner, baseObjectStructure); > } > >- void initGetByIdChain(VM& vm, JSCell* owner, Structure* baseObjectStructure, StructureChain* chain, unsigned count, bool isDirect) >- { >- accessType = access_get_by_id_chain; >- >- u.getByIdChain.baseObjectStructure.set(vm, owner, baseObjectStructure); >- u.getByIdChain.chain.set(vm, owner, chain); >- u.getByIdChain.count = count; >- u.getByIdChain.isDirect = isDirect; >- } >- > void initGetByIdList(PolymorphicGetByIdList* list) > { > accessType = access_get_by_id_list; >Index: Source/JavaScriptCore/dfg/DFGAbstractHeap.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAbstractHeap.h (revision 169014) >+++ Source/JavaScriptCore/dfg/DFGAbstractHeap.h (working copy) >@@ -50,6 +50,8 @@ namespace JSC { namespace DFG { > macro(Butterfly_arrayBuffer) \ > macro(Butterfly_publicLength) \ > macro(Butterfly_vectorLength) \ >+ macro(GetterSetter_getter) \ >+ macro(GetterSetter_setter) \ > macro(JSArrayBufferView_length) \ > macro(JSArrayBufferView_mode) \ > macro(JSArrayBufferView_vector) \ >Index: Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (revision 169014) >+++ Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (working copy) >@@ -1415,6 +1415,8 @@ bool AbstractInterpreter<AbstractStateTy > break; > > case GetCallee: >+ case GetGetter: >+ case GetSetter: > forNode(node).setType(SpecFunction); > break; > >@@ -1640,6 +1642,11 @@ bool AbstractInterpreter<AbstractStateTy > break; > } > >+ case GetGetterSetterByOffset: { >+ forNode(node).set(m_graph, m_graph.m_vm.getterSetterStructure.get()); >+ break; >+ } >+ > case MultiGetByOffset: { > AbstractValue& value = forNode(node->child1()); > ASSERT(!(value.m_type & ~SpecCell)); // Edge filtering should have already ensured this. >Index: Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (revision 169014) >+++ Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (working copy) >@@ -171,21 +171,21 @@ private: > bool handleMinMax(int resultOperand, NodeType op, int registerOffset, int argumentCountIncludingThis); > > // Handle calls. This resolves issues surrounding inlining and intrinsics. >+ void handleCall( >+ int result, NodeType op, InlineCallFrame::Kind, unsigned instructionSize, >+ Node* callTarget, int argCount, int registerOffset, CallLinkStatus); > void handleCall(int result, NodeType op, CodeSpecializationKind, unsigned instructionSize, int callee, int argCount, int registerOffset); > void handleCall(Instruction* pc, NodeType op, CodeSpecializationKind); > void emitFunctionChecks(const CallLinkStatus&, Node* callTarget, int registerOffset, CodeSpecializationKind); > void emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis, CodeSpecializationKind); > // Handle inlining. Return true if it succeeded, false if we need to plant a call. >- bool handleInlining(Node* callTargetNode, int resultOperand, const CallLinkStatus&, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, CodeSpecializationKind); >+ bool handleInlining(Node* callTargetNode, int resultOperand, const CallLinkStatus&, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, InlineCallFrame::Kind); > // Handle intrinsic functions. Return true if it succeeded, false if we need to plant a call. > bool handleIntrinsic(int resultOperand, Intrinsic, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction); > bool handleTypedArrayConstructor(int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, TypedArrayType); > bool handleConstantInternalFunction(int resultOperand, InternalFunction*, int registerOffset, int argumentCountIncludingThis, SpeculatedType prediction, CodeSpecializationKind); > Node* handlePutByOffset(Node* base, unsigned identifier, PropertyOffset, Node* value); >- Node* handleGetByOffset(SpeculatedType, Node* base, unsigned identifierNumber, PropertyOffset); >- void handleGetByOffset( >- int destinationOperand, SpeculatedType, Node* base, unsigned identifierNumber, >- PropertyOffset); >+ Node* handleGetByOffset(SpeculatedType, Node* base, unsigned identifierNumber, PropertyOffset, NodeType op = GetByOffset); > void handleGetById( > int destinationOperand, SpeculatedType, Node* base, unsigned identifierNumber, > const GetByIdStatus&); >@@ -811,11 +811,11 @@ private: > m_numPassedVarArgs++; > } > >- Node* addCall(int result, NodeType op, int callee, int argCount, int registerOffset) >+ Node* addCall(int result, NodeType op, Node* callee, int argCount, int registerOffset) > { > SpeculatedType prediction = getPrediction(); > >- addVarArgChild(get(VirtualRegister(callee))); >+ addVarArgChild(callee); > size_t parameterSlots = JSStack::CallFrameHeaderSize - JSStack::CallerFrameAndPCSize + argCount; > if (parameterSlots > m_parameterSlots) > m_parameterSlots = parameterSlots; >@@ -1120,7 +1120,7 @@ private: > VirtualRegister returnValueVR, > VirtualRegister inlineCallFrameStart, > int argumentCountIncludingThis, >- CodeSpecializationKind); >+ InlineCallFrame::Kind); > > ~InlineStackEntry() > { >@@ -1203,26 +1203,35 @@ void ByteCodeParser::handleCall( > int result, NodeType op, CodeSpecializationKind kind, unsigned instructionSize, > int callee, int argumentCountIncludingThis, int registerOffset) > { >- ASSERT(registerOffset <= 0); >- > Node* callTarget = get(VirtualRegister(callee)); > >- CallLinkStatus callLinkStatus; >- >+ CallLinkStatus callLinkStatus = CallLinkStatus::computeFor( >+ m_inlineStackTop->m_profiledBlock, currentCodeOrigin(), >+ m_inlineStackTop->m_callLinkInfos, m_callContextMap); >+ >+ handleCall( >+ result, op, InlineCallFrame::kindFor(kind), instructionSize, callTarget, >+ argumentCountIncludingThis, registerOffset, callLinkStatus); >+} >+ >+void ByteCodeParser::handleCall( >+ int result, NodeType op, InlineCallFrame::Kind kind, unsigned instructionSize, >+ Node* callTarget, int argumentCountIncludingThis, int registerOffset, >+ CallLinkStatus callLinkStatus) >+{ >+ ASSERT(registerOffset <= 0); >+ CodeSpecializationKind specializationKind = InlineCallFrame::specializationKindFor(kind); >+ > if (m_graph.isConstant(callTarget)) { > callLinkStatus = CallLinkStatus( > m_graph.valueOfJSConstant(callTarget)).setIsProved(true); >- } else { >- callLinkStatus = CallLinkStatus::computeFor( >- m_inlineStackTop->m_profiledBlock, currentCodeOrigin(), >- m_inlineStackTop->m_callLinkInfos, m_callContextMap); > } > > if (!callLinkStatus.canOptimize()) { > // Oddly, this conflates calls that haven't executed with calls that behaved sufficiently polymorphically > // that we cannot optimize them. > >- addCall(result, op, callee, argumentCountIncludingThis, registerOffset); >+ addCall(result, op, callTarget, argumentCountIncludingThis, registerOffset); > return; > } > >@@ -1230,28 +1239,28 @@ void ByteCodeParser::handleCall( > SpeculatedType prediction = getPrediction(); > > if (InternalFunction* function = callLinkStatus.internalFunction()) { >- if (handleConstantInternalFunction(result, function, registerOffset, argumentCountIncludingThis, prediction, kind)) { >+ if (handleConstantInternalFunction(result, function, registerOffset, argumentCountIncludingThis, prediction, specializationKind)) { > // This phantoming has to be *after* the code for the intrinsic, to signify that > // the inputs must be kept alive whatever exits the intrinsic may do. > addToGraph(Phantom, callTarget); >- emitArgumentPhantoms(registerOffset, argumentCountIncludingThis, kind); >+ emitArgumentPhantoms(registerOffset, argumentCountIncludingThis, specializationKind); > return; > } > > // Can only handle this using the generic call handler. >- addCall(result, op, callee, argumentCountIncludingThis, registerOffset); >+ addCall(result, op, callTarget, argumentCountIncludingThis, registerOffset); > return; > } > >- Intrinsic intrinsic = callLinkStatus.intrinsicFor(kind); >+ Intrinsic intrinsic = callLinkStatus.intrinsicFor(specializationKind); > if (intrinsic != NoIntrinsic) { >- emitFunctionChecks(callLinkStatus, callTarget, registerOffset, kind); >+ emitFunctionChecks(callLinkStatus, callTarget, registerOffset, specializationKind); > > if (handleIntrinsic(result, intrinsic, registerOffset, argumentCountIncludingThis, prediction)) { > // This phantoming has to be *after* the code for the intrinsic, to signify that > // the inputs must be kept alive whatever exits the intrinsic may do. > addToGraph(Phantom, callTarget); >- emitArgumentPhantoms(registerOffset, argumentCountIncludingThis, kind); >+ emitArgumentPhantoms(registerOffset, argumentCountIncludingThis, specializationKind); > if (m_graph.compilation()) > m_graph.compilation()->noticeInlinedCall(); > return; >@@ -1262,7 +1271,7 @@ void ByteCodeParser::handleCall( > return; > } > >- addCall(result, op, callee, argumentCountIncludingThis, registerOffset); >+ addCall(result, op, callTarget, argumentCountIncludingThis, registerOffset); > } > > void ByteCodeParser::emitFunctionChecks(const CallLinkStatus& callLinkStatus, Node* callTarget, int registerOffset, CodeSpecializationKind kind) >@@ -1297,10 +1306,12 @@ void ByteCodeParser::emitArgumentPhantom > addToGraph(Phantom, get(virtualRegisterForArgument(i, registerOffset))); > } > >-bool ByteCodeParser::handleInlining(Node* callTargetNode, int resultOperand, const CallLinkStatus& callLinkStatus, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, CodeSpecializationKind kind) >+bool ByteCodeParser::handleInlining(Node* callTargetNode, int resultOperand, const CallLinkStatus& callLinkStatus, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, InlineCallFrame::Kind kind) > { > static const bool verbose = false; > >+ CodeSpecializationKind specializationKind = InlineCallFrame::specializationKindFor(kind); >+ > if (verbose) > dataLog("Considering inlining ", callLinkStatus, " into ", currentCodeOrigin(), "\n"); > >@@ -1333,14 +1344,14 @@ bool ByteCodeParser::handleInlining(Node > // if we had a static proof of what was being called; this might happen for example if you call a > // global function, where watchpointing gives us static information. Overall, it's a rare case > // because we expect that any hot callees would have already been compiled. >- CodeBlock* codeBlock = executable->baselineCodeBlockFor(kind); >+ CodeBlock* codeBlock = executable->baselineCodeBlockFor(specializationKind); > if (!codeBlock) { > if (verbose) > dataLog(" Failing because no code block available.\n"); > return false; > } > CapabilityLevel capabilityLevel = inlineFunctionForCapabilityLevel( >- codeBlock, kind, callLinkStatus.isClosureCall()); >+ codeBlock, specializationKind, callLinkStatus.isClosureCall()); > if (!canInline(capabilityLevel)) { > if (verbose) > dataLog(" Failing because the function is not inlineable.\n"); >@@ -1392,7 +1403,7 @@ bool ByteCodeParser::handleInlining(Node > // Now we know without a doubt that we are committed to inlining. So begin the process > // by checking the callee (if necessary) and making sure that arguments and the callee > // are flushed. >- emitFunctionChecks(callLinkStatus, callTargetNode, registerOffset, kind); >+ emitFunctionChecks(callLinkStatus, callTargetNode, registerOffset, specializationKind); > > // FIXME: Don't flush constants! > >@@ -1850,14 +1861,14 @@ bool ByteCodeParser::handleConstantInter > return false; > } > >-Node* ByteCodeParser::handleGetByOffset(SpeculatedType prediction, Node* base, unsigned identifierNumber, PropertyOffset offset) >+Node* ByteCodeParser::handleGetByOffset(SpeculatedType prediction, Node* base, unsigned identifierNumber, PropertyOffset offset, NodeType op) > { > Node* propertyStorage; > if (isInlineOffset(offset)) > propertyStorage = base; > else > propertyStorage = addToGraph(GetButterfly, base); >- Node* getByOffset = addToGraph(GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), propertyStorage, base); >+ Node* getByOffset = addToGraph(op, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(prediction), propertyStorage, base); > > StorageAccessData storageAccessData; > storageAccessData.offset = offset; >@@ -1867,13 +1878,6 @@ Node* ByteCodeParser::handleGetByOffset( > return getByOffset; > } > >-void ByteCodeParser::handleGetByOffset( >- int destinationOperand, SpeculatedType prediction, Node* base, unsigned identifierNumber, >- PropertyOffset offset) >-{ >- set(VirtualRegister(destinationOperand), handleGetByOffset(prediction, base, identifierNumber, offset)); >-} >- > Node* ByteCodeParser::handlePutByOffset(Node* base, unsigned identifier, PropertyOffset offset, Node* value) > { > Node* propertyStorage; >@@ -1910,18 +1914,19 @@ void ByteCodeParser::handleGetById( > int destinationOperand, SpeculatedType prediction, Node* base, unsigned identifierNumber, > const GetByIdStatus& getByIdStatus) > { >+ NodeType getById = getByIdStatus.makesCalls() ? GetByIdFlush : GetById; >+ > if (!getByIdStatus.isSimple() || !Options::enableAccessInlining()) { > set(VirtualRegister(destinationOperand), >- addToGraph( >- getByIdStatus.makesCalls() ? GetByIdFlush : GetById, >- OpInfo(identifierNumber), OpInfo(prediction), base)); >+ addToGraph(getById, OpInfo(identifierNumber), OpInfo(prediction), base)); > return; > } > > if (getByIdStatus.numVariants() > 1) { >- if (!isFTL(m_graph.m_plan.mode) || !Options::enablePolymorphicAccessInlining()) { >+ if (getByIdStatus.makesCalls() || !isFTL(m_graph.m_plan.mode) >+ || !Options::enablePolymorphicAccessInlining()) { > set(VirtualRegister(destinationOperand), >- addToGraph(GetById, OpInfo(identifierNumber), OpInfo(prediction), base)); >+ addToGraph(getById, OpInfo(identifierNumber), OpInfo(prediction), base)); > return; > } > >@@ -1954,7 +1959,7 @@ void ByteCodeParser::handleGetById( > if (m_graph.compilation()) > m_graph.compilation()->noticeInlinedGetById(); > >- Node* originalBaseForBaselineJIT = base; >+ Node* originalBase = base; > > addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.structureSet())), base); > >@@ -1969,18 +1974,59 @@ void ByteCodeParser::handleGetById( > // 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() || originalBaseForBaselineJIT != base) >- addToGraph(Phantom, originalBaseForBaselineJIT); >+ if (variant.specificValue() || originalBase != base) >+ addToGraph(Phantom, originalBase); > >- if (variant.specificValue()) { >- ASSERT(variant.specificValue().isCell()); >- >- set(VirtualRegister(destinationOperand), cellConstant(variant.specificValue().asCell())); >+ Node* loadedValue; >+ if (variant.specificValue()) >+ loadedValue = cellConstant(variant.specificValue().asCell()); >+ else { >+ loadedValue = handleGetByOffset( >+ prediction, base, identifierNumber, variant.offset(), >+ variant.callLinkStatus() ? GetGetterSetterByOffset : GetByOffset); >+ } >+ >+ if (!variant.callLinkStatus()) { >+ set(VirtualRegister(destinationOperand), loadedValue); > return; > } > >- handleGetByOffset( >- destinationOperand, prediction, base, identifierNumber, variant.offset()); >+ Node* getter = addToGraph(GetGetter, loadedValue); >+ >+ // Make a call. We don't try to get fancy with using the smallest operand number because >+ // the stack layout phase should compress the stack anyway. >+ >+ unsigned numberOfParameters = 0; >+ numberOfParameters++; // The 'this' argument. >+ numberOfParameters++; // True return PC. >+ >+ // Start with a register offset that corresponds to the last in-use register. >+ int registerOffset = virtualRegisterForLocal( >+ m_inlineStackTop->m_profiledBlock->m_numCalleeRegisters - 1).offset(); >+ registerOffset -= numberOfParameters; >+ registerOffset -= JSStack::CallFrameHeaderSize; >+ >+ // Get the alignment right. >+ registerOffset = -WTF::roundUpToMultipleOf( >+ stackAlignmentRegisters(), >+ -registerOffset); >+ >+ ensureLocals( >+ m_inlineStackTop->remapOperand( >+ VirtualRegister(registerOffset)).toLocal()); >+ >+ // Issue SetLocals. This has two effects: >+ // 1) That's how handleCall() sees the arguments. >+ // 2) If we inline then this ensures that the arguments are flushed so that if you use >+ // the dreaded arguments object on the getter, the right things happen. Well, sort of - >+ // since we only really care about 'this' in this case. But we're not going to take that >+ // shortcut. >+ int nextRegister = registerOffset + JSStack::CallFrameHeaderSize; >+ set(VirtualRegister(nextRegister++), originalBase, ImmediateNakedSet); >+ >+ handleCall( >+ destinationOperand, Call, InlineCallFrame::GetterCall, OPCODE_LENGTH(op_get_by_id), >+ getter, numberOfParameters - 1, registerOffset, *variant.callLinkStatus()); > } > > void ByteCodeParser::emitPutById( >@@ -3376,7 +3422,7 @@ ByteCodeParser::InlineStackEntry::Inline > VirtualRegister returnValueVR, > VirtualRegister inlineCallFrameStart, > int argumentCountIncludingThis, >- CodeSpecializationKind kind) >+ InlineCallFrame::Kind kind) > : m_byteCodeParser(byteCodeParser) > , m_codeBlock(codeBlock) > , m_profiledBlock(profiledBlock) >@@ -3435,7 +3481,7 @@ ByteCodeParser::InlineStackEntry::Inline > m_inlineCallFrame->isClosureCall = true; > m_inlineCallFrame->caller = byteCodeParser->currentCodeOrigin(); > m_inlineCallFrame->arguments.resize(argumentCountIncludingThis); // Set the number of arguments including this, but don't configure the value recoveries, yet. >- m_inlineCallFrame->kind = InlineCallFrame::kindFor(kind); >+ m_inlineCallFrame->kind = kind; > > if (m_inlineCallFrame->caller.inlineCallFrame) > m_inlineCallFrame->capturedVars = m_inlineCallFrame->caller.inlineCallFrame->capturedVars; >@@ -3674,7 +3720,7 @@ bool ByteCodeParser::parse() > > InlineStackEntry inlineStackEntry( > this, m_codeBlock, m_profiledBlock, 0, 0, VirtualRegister(), VirtualRegister(), >- m_codeBlock->numParameters(), CodeForCall); >+ m_codeBlock->numParameters(), InlineCallFrame::Call); > > parseCodeBlock(); > >Index: Source/JavaScriptCore/dfg/DFGCSEPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGCSEPhase.cpp (revision 169014) >+++ Source/JavaScriptCore/dfg/DFGCSEPhase.cpp (working copy) >@@ -690,6 +690,40 @@ private: > return 0; > } > >+ Node* getGetterSetterByOffsetLoadElimination(unsigned identifierNumber, Node* base) >+ { >+ for (unsigned i = m_indexInBlock; i--;) { >+ Node* node = m_currentBlock->at(i); >+ if (node == base) >+ break; >+ >+ switch (node->op()) { >+ case GetGetterSetterByOffset: >+ if (node->child2() == base >+ && m_graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber == identifierNumber) >+ return node; >+ break; >+ >+ case PutByValDirect: >+ case PutByVal: >+ case PutByValAlias: >+ if (m_graph.byValIsPure(node)) { >+ // If PutByVal speculates that it's accessing an array with an >+ // integer index, then it's impossible for it to cause a structure >+ // change. >+ break; >+ } >+ return 0; >+ >+ default: >+ if (m_graph.clobbersWorld(node)) >+ return 0; >+ break; >+ } >+ } >+ return 0; >+ } >+ > Node* putByOffsetStoreElimination(unsigned identifierNumber, Node* child1) > { > for (unsigned i = m_indexInBlock; i--;) { >@@ -845,25 +879,18 @@ private: > return 0; > } > >- Node* getTypedArrayByteOffsetLoadElimination(Node* child1) >+ Node* getInternalFieldLoadElimination(NodeType op, Node* child1) > { > for (unsigned i = m_indexInBlock; i--;) { > Node* node = m_currentBlock->at(i); > if (node == child1) > break; > >- switch (node->op()) { >- case GetTypedArrayByteOffset: { >- if (node->child1() == child1) >- return node; >- break; >- } >+ if (node->op() == op && node->child1() == child1) >+ return node; > >- default: >- if (m_graph.clobbersWorld(node)) >- return 0; >- break; >- } >+ if (m_graph.clobbersWorld(node)) >+ return 0; > } > return 0; > } >@@ -1401,10 +1428,12 @@ private: > break; > } > >- case GetTypedArrayByteOffset: { >+ case GetTypedArrayByteOffset: >+ case GetGetter: >+ case GetSetter: { > if (cseMode == StoreElimination) > break; >- setReplacement(getTypedArrayByteOffsetLoadElimination(node->child1().node())); >+ setReplacement(getInternalFieldLoadElimination(node->op(), node->child1().node())); > break; > } > >@@ -1420,6 +1449,12 @@ private: > setReplacement(getByOffsetLoadElimination(m_graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber, node->child2().node())); > break; > >+ case GetGetterSetterByOffset: >+ if (cseMode == StoreElimination) >+ break; >+ setReplacement(getGetterSetterByOffsetLoadElimination(m_graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber, node->child2().node())); >+ break; >+ > case MultiGetByOffset: > if (cseMode == StoreElimination) > break; >Index: Source/JavaScriptCore/dfg/DFGClobberize.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGClobberize.h (revision 169014) >+++ Source/JavaScriptCore/dfg/DFGClobberize.h (working copy) >@@ -213,6 +213,14 @@ void clobberize(Graph& graph, Node* node > write(World); > return; > >+ case GetGetter: >+ read(GetterSetter_getter); >+ return; >+ >+ case GetSetter: >+ read(GetterSetter_setter); >+ return; >+ > case GetCallee: > read(AbstractHeap(Variables, JSStack::Callee)); > return; >@@ -481,6 +489,7 @@ void clobberize(Graph& graph, Node* node > return; > > case GetByOffset: >+ case GetGetterSetterByOffset: > read(AbstractHeap(NamedProperties, graph.m_storageAccessData[node->storageAccessDataIndex()].identifierNumber)); > return; > >Index: Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (revision 169014) >+++ Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (working copy) >@@ -885,7 +885,9 @@ private: > case GetClosureRegisters: > case SkipTopScope: > case SkipScope: >- case GetScope: { >+ case GetScope: >+ case GetGetter: >+ case GetSetter: { > fixEdge<KnownCellUse>(node->child1()); > break; > } >@@ -945,7 +947,8 @@ private: > break; > } > >- case GetByOffset: { >+ case GetByOffset: >+ case GetGetterSetterByOffset: { > if (!node->child1()->hasStorageResult()) > fixEdge<KnownCellUse>(node->child1()); > fixEdge<KnownCellUse>(node->child2()); >@@ -1034,6 +1037,8 @@ private: > Node* globalObjectNode = m_insertionSet.insertNode( > m_indexInBlock, SpecNone, WeakJSConstant, node->origin, > OpInfo(m_graph.globalObjectFor(node->origin.semantic))); >+ // FIXME: This probably shouldn't have an unconditional barrier. >+ // https://bugs.webkit.org/show_bug.cgi?id=133104 > Node* barrierNode = m_graph.addNode( > SpecNone, StoreBarrier, m_currentNode->origin, > Edge(globalObjectNode, KnownCellUse)); >Index: Source/JavaScriptCore/dfg/DFGJITCompiler.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGJITCompiler.cpp (revision 169014) >+++ Source/JavaScriptCore/dfg/DFGJITCompiler.cpp (working copy) >@@ -417,7 +417,7 @@ void JITCompiler::linkFunction() > m_jitCode->shrinkToFit(); > codeBlock()->shrinkToFit(CodeBlock::LateShrink); > >- linkBuffer->link(m_callArityFixup, FunctionPtr((m_vm->getCTIStub(arityFixup)).code().executableAddress())); >+ linkBuffer->link(m_callArityFixup, FunctionPtr((m_vm->getCTIStub(arityFixupGenerator)).code().executableAddress())); > > disassemble(*linkBuffer); > >Index: Source/JavaScriptCore/dfg/DFGNode.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGNode.h (revision 169014) >+++ Source/JavaScriptCore/dfg/DFGNode.h (working copy) >@@ -1146,7 +1146,7 @@ struct Node { > > bool hasStorageAccessData() > { >- return op() == GetByOffset || op() == PutByOffset; >+ return op() == GetByOffset || op() == GetGetterSetterByOffset || op() == PutByOffset; > } > > unsigned storageAccessDataIndex() >Index: Source/JavaScriptCore/dfg/DFGNodeType.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGNodeType.h (revision 169014) >+++ Source/JavaScriptCore/dfg/DFGNodeType.h (working copy) >@@ -176,7 +176,10 @@ namespace JSC { namespace DFG { > macro(GetIndexedPropertyStorage, NodeResultStorage) \ > macro(ConstantStoragePointer, NodeResultStorage) \ > macro(TypedArrayWatchpoint, NodeMustGenerate) \ >+ macro(GetGetter, NodeResultJS) \ >+ macro(GetSetter, NodeResultJS) \ > macro(GetByOffset, NodeResultJS) \ >+ macro(GetGetterSetterByOffset, NodeResultJS) \ > macro(MultiGetByOffset, NodeResultJS) \ > macro(PutByOffset, NodeMustGenerate) \ > macro(MultiPutByOffset, NodeMustGenerate) \ >Index: Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp (revision 169014) >+++ Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp (working copy) >@@ -108,12 +108,44 @@ void reifyInlinedCallFrames(CCallHelpers > InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; > CodeBlock* baselineCodeBlock = jit.baselineCodeBlockFor(codeOrigin); > CodeBlock* baselineCodeBlockForCaller = jit.baselineCodeBlockFor(inlineCallFrame->caller); >+ void* jumpTarget; >+ void* trueReturnPC = nullptr; >+ > unsigned callBytecodeIndex = inlineCallFrame->caller.bytecodeIndex; >- CallLinkInfo* callLinkInfo = >- baselineCodeBlockForCaller->getCallLinkInfoForBytecodeIndex(callBytecodeIndex); >- RELEASE_ASSERT(callLinkInfo); > >- void* jumpTarget = callLinkInfo->callReturnLocation.executableAddress(); >+ switch (inlineCallFrame->kind) { >+ case InlineCallFrame::Call: >+ case InlineCallFrame::Construct: { >+ CallLinkInfo* callLinkInfo = >+ baselineCodeBlockForCaller->getCallLinkInfoForBytecodeIndex(callBytecodeIndex); >+ RELEASE_ASSERT(callLinkInfo); >+ >+ jumpTarget = callLinkInfo->callReturnLocation.executableAddress(); >+ break; >+ } >+ >+ case InlineCallFrame::GetterCall: >+ case InlineCallFrame::SetterCall: { >+ StructureStubInfo* stubInfo = >+ baselineCodeBlockForCaller->findStubInfo(CodeOrigin(callBytecodeIndex)); >+ RELEASE_ASSERT(stubInfo); >+ >+ switch (inlineCallFrame->kind) { >+ case InlineCallFrame::GetterCall: >+ jumpTarget = jit.vm()->getCTIStub(baselineGetterReturnThunkGenerator).code().executableAddress(); >+ break; >+ case InlineCallFrame::SetterCall: >+ jumpTarget = jit.vm()->getCTIStub(baselineSetterReturnThunkGenerator).code().executableAddress(); >+ break; >+ default: >+ RELEASE_ASSERT_NOT_REACHED(); >+ break; >+ } >+ >+ trueReturnPC = stubInfo->callReturnLocation.labelAtOffset( >+ stubInfo->patch.deltaCallToDone).executableAddress(); >+ break; >+ } } > > GPRReg callerFrameGPR; > if (inlineCallFrame->caller.inlineCallFrame) { >@@ -122,12 +154,15 @@ void reifyInlinedCallFrames(CCallHelpers > } else > callerFrameGPR = GPRInfo::callFrameRegister; > >+ jit.storePtr(AssemblyHelpers::TrustedImmPtr(jumpTarget), AssemblyHelpers::addressForByteOffset(inlineCallFrame->returnPCOffset())); >+ if (trueReturnPC) >+ jit.storePtr(AssemblyHelpers::TrustedImmPtr(trueReturnPC), AssemblyHelpers::addressFor(inlineCallFrame->stackOffset + virtualRegisterForArgument(inlineCallFrame->arguments.size()).offset())); >+ > #if USE(JSVALUE64) > jit.storePtr(AssemblyHelpers::TrustedImmPtr(baselineCodeBlock), AssemblyHelpers::addressFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::CodeBlock))); > if (!inlineCallFrame->isClosureCall) > jit.store64(AssemblyHelpers::TrustedImm64(JSValue::encode(JSValue(inlineCallFrame->calleeConstant()->scope()))), AssemblyHelpers::addressFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ScopeChain))); > jit.store64(callerFrameGPR, AssemblyHelpers::addressForByteOffset(inlineCallFrame->callerFrameOffset())); >- jit.storePtr(AssemblyHelpers::TrustedImmPtr(jumpTarget), AssemblyHelpers::addressForByteOffset(inlineCallFrame->returnPCOffset())); > uint32_t locationBits = CallFrame::Location::encodeAsBytecodeOffset(codeOrigin.bytecodeIndex); > jit.store32(AssemblyHelpers::TrustedImm32(locationBits), AssemblyHelpers::tagFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ArgumentCount))); > jit.store32(AssemblyHelpers::TrustedImm32(inlineCallFrame->arguments.size()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ArgumentCount))); >@@ -143,7 +178,6 @@ void reifyInlinedCallFrames(CCallHelpers > if (!inlineCallFrame->isClosureCall) > jit.storePtr(AssemblyHelpers::TrustedImmPtr(inlineCallFrame->calleeConstant()->scope()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ScopeChain))); > jit.storePtr(callerFrameGPR, AssemblyHelpers::addressForByteOffset(inlineCallFrame->callerFrameOffset())); >- jit.storePtr(AssemblyHelpers::TrustedImmPtr(jumpTarget), AssemblyHelpers::addressForByteOffset(inlineCallFrame->returnPCOffset())); > Instruction* instruction = baselineCodeBlock->instructions().begin() + codeOrigin.bytecodeIndex; > uint32_t locationBits = CallFrame::Location::encodeAsBytecodeInstruction(instruction); > jit.store32(AssemblyHelpers::TrustedImm32(locationBits), AssemblyHelpers::tagFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ArgumentCount))); >Index: Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (revision 169014) >+++ Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (working copy) >@@ -188,6 +188,20 @@ private: > changed |= setPrediction(node->getHeapPrediction()); > break; > } >+ >+ case GetGetterSetterByOffset: { >+ changed |= setPrediction(SpecCellOther); >+ break; >+ } >+ >+ case GetGetter: >+ case GetSetter: >+ case GetCallee: >+ case NewFunctionNoCheck: >+ case NewFunctionExpression: { >+ changed |= setPrediction(SpecFunction); >+ break; >+ } > > case StringCharCodeAt: { > changed |= setPrediction(SpecInt32); >@@ -423,11 +437,6 @@ private: > break; > } > >- case GetCallee: { >- changed |= setPrediction(SpecFunction); >- break; >- } >- > case CreateThis: > case NewObject: { > changed |= setPrediction(SpecFinalObject); >@@ -490,12 +499,6 @@ private: > break; > } > >- case NewFunctionNoCheck: >- case NewFunctionExpression: { >- changed |= setPrediction(SpecFunction); >- break; >- } >- > case PutByValAlias: > case GetArrayLength: > case GetTypedArrayByteOffset: >Index: Source/JavaScriptCore/dfg/DFGSafeToExecute.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSafeToExecute.h (revision 169014) >+++ Source/JavaScriptCore/dfg/DFGSafeToExecute.h (working copy) >@@ -253,6 +253,8 @@ bool safeToExecute(AbstractStateType& st > case ValueRep: > case DoubleRep: > case Int52Rep: >+ case GetGetter: >+ case GetSetter: > return true; > > case GetByVal: >@@ -285,6 +287,7 @@ bool safeToExecute(AbstractStateType& st > StructureSet(node->structureTransitionData().previousStructure)); > > case GetByOffset: >+ case GetGetterSetterByOffset: > case PutByOffset: > return state.forNode(node->child1()).m_currentKnownStructure.isValidOffset( > graph.m_storageAccessData[node->storageAccessDataIndex()].offset); >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (revision 169014) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (working copy) >@@ -35,6 +35,7 @@ > #include "DFGOperations.h" > #include "DFGSlowPathGenerator.h" > #include "Debugger.h" >+#include "GetterSetter.h" > #include "JSActivation.h" > #include "ObjectPrototype.h" > #include "JSCInlines.h" >@@ -3792,6 +3793,47 @@ void SpeculativeJIT::compile(Node* node) > break; > } > >+ case GetGetterSetterByOffset: { >+ StorageOperand storage(this, node->child1()); >+ GPRTemporary resultPayload(this); >+ >+ GPRReg storageGPR = storage.gpr(); >+ GPRReg resultPayloadGPR = resultPayload.gpr(); >+ >+ StorageAccessData& storageAccessData = m_jit.graph().m_storageAccessData[node->storageAccessDataIndex()]; >+ >+ m_jit.load32(JITCompiler::Address(storageGPR, offsetRelativeToBase(storageAccessData.offset) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)), resultPayloadGPR); >+ >+ cellResult(resultPayloadGPR, node); >+ break; >+ } >+ >+ case GetGetter: { >+ SpeculateCellOperand op1(this, node->child1()); >+ GPRTemporary result(this, Reuse, op1); >+ >+ GPRReg op1GPR = op1.gpr(); >+ GPRReg resultGPR = result.gpr(); >+ >+ m_jit.loadPtr(JITCompiler::Address(op1GPR, GetterSetter::offsetOfGetter()), resultGPR); >+ >+ cellResult(resultGPR, node); >+ break; >+ } >+ >+ case GetSetter: { >+ SpeculateCellOperand op1(this, node->child1()); >+ GPRTemporary result(this, Reuse, op1); >+ >+ GPRReg op1GPR = op1.gpr(); >+ GPRReg resultGPR = result.gpr(); >+ >+ m_jit.loadPtr(JITCompiler::Address(op1GPR, GetterSetter::offsetOfSetter()), resultGPR); >+ >+ cellResult(resultGPR, node); >+ break; >+ } >+ > case PutByOffset: { > StorageOperand storage(this, node->child1()); > JSValueOperand value(this, node->child3()); >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (revision 169014) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (working copy) >@@ -35,6 +35,7 @@ > #include "DFGOperations.h" > #include "DFGSlowPathGenerator.h" > #include "Debugger.h" >+#include "GetterSetter.h" > #include "JSCInlines.h" > #include "ObjectPrototype.h" > #include "SpillRegistersMode.h" >@@ -3853,7 +3854,8 @@ void SpeculativeJIT::compile(Node* node) > break; > } > >- case GetByOffset: { >+ case GetByOffset: >+ case GetGetterSetterByOffset: { > StorageOperand storage(this, node->child1()); > GPRTemporary result(this, Reuse, storage); > >@@ -3868,6 +3870,32 @@ void SpeculativeJIT::compile(Node* node) > break; > } > >+ case GetGetter: { >+ SpeculateCellOperand op1(this, node->child1()); >+ GPRTemporary result(this, Reuse, op1); >+ >+ GPRReg op1GPR = op1.gpr(); >+ GPRReg resultGPR = result.gpr(); >+ >+ m_jit.loadPtr(JITCompiler::Address(op1GPR, GetterSetter::offsetOfGetter()), resultGPR); >+ >+ cellResult(resultGPR, node); >+ break; >+ } >+ >+ case GetSetter: { >+ SpeculateCellOperand op1(this, node->child1()); >+ GPRTemporary result(this, Reuse, op1); >+ >+ GPRReg op1GPR = op1.gpr(); >+ GPRReg resultGPR = result.gpr(); >+ >+ m_jit.loadPtr(JITCompiler::Address(op1GPR, GetterSetter::offsetOfSetter()), resultGPR); >+ >+ cellResult(resultGPR, node); >+ break; >+ } >+ > case PutByOffset: { > StorageOperand storage(this, node->child1()); > JSValueOperand value(this, node->child3()); >Index: Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.cpp (revision 169014) >+++ Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.cpp (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 >@@ -28,6 +28,7 @@ > > #if ENABLE(FTL_JIT) > >+#include "GetterSetter.h" > #include "JSScope.h" > #include "JSVariableObject.h" > #include "JSCInlines.h" >Index: Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h >=================================================================== >--- Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h (revision 169014) >+++ Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.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 >@@ -46,6 +46,8 @@ namespace JSC { namespace FTL { > macro(Butterfly_publicLength, Butterfly::offsetOfPublicLength()) \ > macro(Butterfly_vectorLength, Butterfly::offsetOfVectorLength()) \ > macro(CallFrame_callerFrame, CallFrame::callerFrameOffset()) \ >+ macro(GetterSetter_getter, GetterSetter::offsetOfGetter()) \ >+ macro(GetterSetter_setter, GetterSetter::offsetOfSetter()) \ > macro(JSArrayBufferView_length, JSArrayBufferView::offsetOfLength()) \ > macro(JSArrayBufferView_mode, JSArrayBufferView::offsetOfMode()) \ > macro(JSArrayBufferView_vector, JSArrayBufferView::offsetOfVector()) \ >Index: Source/JavaScriptCore/ftl/FTLCapabilities.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLCapabilities.cpp (revision 169014) >+++ Source/JavaScriptCore/ftl/FTLCapabilities.cpp (working copy) >@@ -72,6 +72,9 @@ inline CapabilityLevel canCompile(Node* > case NewArray: > case NewArrayBuffer: > case GetByOffset: >+ case GetGetterSetterByOffset: >+ case GetGetter: >+ case GetSetter: > case PutByOffset: > case GetGlobalVar: > case PutGlobalVar: >Index: Source/JavaScriptCore/ftl/FTLLink.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLLink.cpp (revision 169014) >+++ Source/JavaScriptCore/ftl/FTLLink.cpp (working copy) >@@ -178,7 +178,7 @@ void link(State& state) > > linkBuffer = adoptPtr(new LinkBuffer(vm, &jit, codeBlock, JITCompilationMustSucceed)); > linkBuffer->link(callArityCheck, codeBlock->m_isConstructor ? operationConstructArityCheck : operationCallArityCheck); >- linkBuffer->link(callArityFixup, FunctionPtr((vm.getCTIStub(arityFixup)).code().executableAddress())); >+ linkBuffer->link(callArityFixup, FunctionPtr((vm.getCTIStub(arityFixupGenerator)).code().executableAddress())); > linkBuffer->link(mainPathJumps, CodeLocationLabel(bitwise_cast<void*>(state.generatedFunction))); > > state.jitCode->initializeAddressForCall(MacroAssemblerCodePtr(bitwise_cast<void*>(state.generatedFunction))); >Index: Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (revision 169014) >+++ Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (working copy) >@@ -493,8 +493,15 @@ private: > compileStringCharCodeAt(); > break; > case GetByOffset: >+ case GetGetterSetterByOffset: > compileGetByOffset(); > break; >+ case GetGetter: >+ compileGetGetter(); >+ break; >+ case GetSetter: >+ compileGetSetter(); >+ break; > case MultiGetByOffset: > compileMultiGetByOffset(); > break; >@@ -3141,6 +3148,16 @@ private: > lowStorage(m_node->child1()), data.identifierNumber, data.offset)); > } > >+ void compileGetGetter() >+ { >+ setJSValue(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.GetterSetter_getter)); >+ } >+ >+ void compileGetSetter() >+ { >+ setJSValue(m_out.loadPtr(lowCell(m_node->child1()), m_heaps.GetterSetter_setter)); >+ } >+ > void compileMultiGetByOffset() > { > LValue base = lowCell(m_node->child1()); >Index: Source/JavaScriptCore/jit/AccessorCallJITStubRoutine.h >=================================================================== >--- Source/JavaScriptCore/jit/AccessorCallJITStubRoutine.h (revision 169014) >+++ Source/JavaScriptCore/jit/AccessorCallJITStubRoutine.h (working copy) >@@ -46,7 +46,6 @@ public: > > virtual bool visitWeak(RepatchBuffer&) override; > >-private: > std::unique_ptr<CallLinkInfo> m_callLinkInfo; > }; > >Index: Source/JavaScriptCore/jit/JIT.cpp >=================================================================== >--- Source/JavaScriptCore/jit/JIT.cpp (revision 169014) >+++ Source/JavaScriptCore/jit/JIT.cpp (working copy) >@@ -108,6 +108,17 @@ void JIT::emitEnterOptimizationCheck() > } > #endif > >+void JIT::assertStackPointerOffset() >+{ >+ if (ASSERT_DISABLED) >+ return; >+ >+ addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock) * sizeof(Register)), callFrameRegister, regT0); >+ Jump ok = branchPtr(Equal, regT0, stackPointerRegister); >+ breakpoint(); >+ ok.link(this); >+} >+ > #define NEXT_OPCODE(name) \ > m_bytecodeOffset += OPCODE_LENGTH(name); \ > break; >@@ -570,7 +581,7 @@ CompilationResult JIT::privateCompile(JI > #endif > move(TrustedImmPtr(m_vm->arityCheckFailReturnThunks->returnPCsFor(*m_vm, m_codeBlock->numParameters())), thunkReg); > loadPtr(BaseIndex(thunkReg, regT0, timesPtr()), thunkReg); >- emitNakedCall(m_vm->getCTIStub(arityFixup).code()); >+ emitNakedCall(m_vm->getCTIStub(arityFixupGenerator).code()); > > #if !ASSERT_DISABLED > m_bytecodeOffset = (unsigned)-1; // Reset this, in order to guard its use with ASSERTs. >Index: Source/JavaScriptCore/jit/JIT.h >=================================================================== >--- Source/JavaScriptCore/jit/JIT.h (revision 169014) >+++ Source/JavaScriptCore/jit/JIT.h (working copy) >@@ -242,7 +242,7 @@ namespace JSC { > > static unsigned frameRegisterCountFor(CodeBlock*); > static int stackPointerOffsetFor(CodeBlock*); >- >+ > private: > JIT(VM*, CodeBlock* = 0); > >@@ -446,6 +446,8 @@ namespace JSC { > > void emit_compareAndJump(OpcodeID, int op1, int op2, unsigned target, RelationalCondition); > void emit_compareAndJumpSlow(int op1, int op2, unsigned target, DoubleCondition, size_t (JIT_OPERATION *operation)(ExecState*, EncodedJSValue, EncodedJSValue), bool invert, Vector<SlowCaseEntry>::iterator&); >+ >+ void assertStackPointerOffset(); > > void emit_op_touch_entry(Instruction*); > void emit_op_add(Instruction*); >Index: Source/JavaScriptCore/jit/JITPropertyAccess.cpp >=================================================================== >--- Source/JavaScriptCore/jit/JITPropertyAccess.cpp (revision 169014) >+++ Source/JavaScriptCore/jit/JITPropertyAccess.cpp (working copy) >@@ -528,6 +528,7 @@ void JIT::emit_op_get_by_id(Instruction* > > emitValueProfilingSite(); > emitPutVirtualRegister(resultVReg); >+ assertStackPointerOffset(); > } > > void JIT::emitSlow_op_get_by_id(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) >Index: Source/JavaScriptCore/jit/ThunkGenerators.cpp >=================================================================== >--- Source/JavaScriptCore/jit/ThunkGenerators.cpp (revision 169014) >+++ Source/JavaScriptCore/jit/ThunkGenerators.cpp (working copy) >@@ -430,7 +430,7 @@ MacroAssemblerCodeRef nativeConstructGen > return nativeForGenerator(vm, CodeForConstruct); > } > >-MacroAssemblerCodeRef arityFixup(VM* vm) >+MacroAssemblerCodeRef arityFixupGenerator(VM* vm) > { > JSInterfaceJIT jit(vm); > >@@ -533,6 +533,83 @@ MacroAssemblerCodeRef arityFixup(VM* vm) > return FINALIZE_CODE(patchBuffer, ("fixup arity")); > } > >+MacroAssemblerCodeRef baselineGetterReturnThunkGenerator(VM* vm) >+{ >+ JSInterfaceJIT jit(vm); >+ >+#if USE(JSVALUE64) >+ jit.move(GPRInfo::returnValueGPR, GPRInfo::regT0); >+#else >+ jit.setupResults(GPRInfo::regT0, GPRInfo::regT1); >+#endif >+ >+ unsigned numberOfParameters = 0; >+ numberOfParameters++; // The 'this' argument. >+ numberOfParameters++; // The true return PC. >+ >+ unsigned numberOfRegsForCall = >+ JSStack::CallFrameHeaderSize + numberOfParameters; >+ >+ unsigned numberOfBytesForCall = >+ numberOfRegsForCall * sizeof(Register) - sizeof(CallerFrameAndPC); >+ >+ unsigned alignedNumberOfBytesForCall = >+ WTF::roundUpToMultipleOf(stackAlignmentBytes(), numberOfBytesForCall); >+ >+ // The real return address is stored above the arguments. We passed one argument, which is >+ // 'this'. So argument at index 1 is the return address. >+ jit.loadPtr( >+ AssemblyHelpers::Address( >+ AssemblyHelpers::stackPointerRegister, >+ (virtualRegisterForArgument(1).offset() - JSStack::CallerFrameAndPCSize) * sizeof(Register)), >+ GPRInfo::regT2); >+ >+ jit.addPtr( >+ AssemblyHelpers::TrustedImm32(alignedNumberOfBytesForCall), >+ AssemblyHelpers::stackPointerRegister); >+ >+ jit.jump(GPRInfo::regT2); >+ >+ LinkBuffer patchBuffer(*vm, &jit, GLOBAL_THUNK_ID); >+ return FINALIZE_CODE(patchBuffer, ("baseline getter return thunk")); >+} >+ >+MacroAssemblerCodeRef baselineSetterReturnThunkGenerator(VM* vm) >+{ >+ JSInterfaceJIT jit(vm); >+ >+ unsigned numberOfParameters = 0; >+ numberOfParameters++; // The 'this' argument. >+ numberOfParameters++; // The value to set. >+ numberOfParameters++; // The true return PC. >+ >+ unsigned numberOfRegsForCall = >+ JSStack::CallFrameHeaderSize + numberOfParameters; >+ >+ unsigned numberOfBytesForCall = >+ numberOfRegsForCall * sizeof(Register) - sizeof(CallerFrameAndPC); >+ >+ unsigned alignedNumberOfBytesForCall = >+ WTF::roundUpToMultipleOf(stackAlignmentBytes(), numberOfBytesForCall); >+ >+ // The real return address is stored above the arguments. We passed two arguments, so >+ // the argument at index 2 is the return address. >+ jit.loadPtr( >+ AssemblyHelpers::Address( >+ AssemblyHelpers::stackPointerRegister, >+ (virtualRegisterForArgument(2).offset() - JSStack::CallerFrameAndPCSize) * sizeof(Register)), >+ GPRInfo::regT2); >+ >+ jit.addPtr( >+ AssemblyHelpers::TrustedImm32(alignedNumberOfBytesForCall), >+ AssemblyHelpers::stackPointerRegister); >+ >+ jit.jump(GPRInfo::regT2); >+ >+ LinkBuffer patchBuffer(*vm, &jit, GLOBAL_THUNK_ID); >+ return FINALIZE_CODE(patchBuffer, ("baseline setter return thunk")); >+} >+ > static void stringCharLoad(SpecializedThunkJIT& jit, VM* vm) > { > // load string >Index: Source/JavaScriptCore/jit/ThunkGenerators.h >=================================================================== >--- Source/JavaScriptCore/jit/ThunkGenerators.h (revision 169014) >+++ Source/JavaScriptCore/jit/ThunkGenerators.h (working copy) >@@ -113,7 +113,10 @@ inline ThunkGenerator virtualThunkGenera > MacroAssemblerCodeRef nativeCallGenerator(VM*); > MacroAssemblerCodeRef nativeConstructGenerator(VM*); > MacroAssemblerCodeRef nativeTailCallGenerator(VM*); >-MacroAssemblerCodeRef arityFixup(VM*); >+MacroAssemblerCodeRef arityFixupGenerator(VM*); >+ >+MacroAssemblerCodeRef baselineGetterReturnThunkGenerator(VM* vm); >+MacroAssemblerCodeRef baselineSetterReturnThunkGenerator(VM* vm); > > MacroAssemblerCodeRef charCodeAtThunkGenerator(VM*); > MacroAssemblerCodeRef charAtThunkGenerator(VM*); >Index: Source/JavaScriptCore/runtime/CommonSlowPaths.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/CommonSlowPaths.cpp (revision 169014) >+++ Source/JavaScriptCore/runtime/CommonSlowPaths.cpp (working copy) >@@ -170,7 +170,7 @@ static CommonSlowPaths::ArityCheckData* > result->paddedStackSpace = slotsToAdd; > #if ENABLE(JIT) > if (vm.canUseJIT()) { >- result->thunkToCall = vm.getCTIStub(arityFixup).code().executableAddress(); >+ result->thunkToCall = vm.getCTIStub(arityFixupGenerator).code().executableAddress(); > result->returnPC = vm.arityCheckFailReturnThunks->returnPCFor(vm, slotsToAdd * stackAlignmentRegisters()).executableAddress(); > } else > #endif >Index: Source/JavaScriptCore/tests/stress/exit-from-getter.js >=================================================================== >--- Source/JavaScriptCore/tests/stress/exit-from-getter.js (revision 0) >+++ Source/JavaScriptCore/tests/stress/exit-from-getter.js (working copy) >@@ -0,0 +1,23 @@ >+(function() { >+ var o = {_f:42}; >+ o.__defineGetter__("f", function() { return this._f * 100; }); >+ var result = 0; >+ var n = 50000; >+ function foo(o) { >+ return o.f + 11; >+ } >+ noInline(foo); >+ for (var i = 0; i < n; ++i) { >+ result += foo(o); >+ } >+ if (result != n * (42 * 100 + 11)) >+ throw "Error: bad result: " + result; >+ o._f = 1000000000; >+ result = 0; >+ for (var i = 0; i < n; ++i) { >+ result += foo(o); >+ } >+ if (result != n * (1000000000 * 100 + 11)) >+ throw "Error: bad result (2): " + result; >+})(); >+ >Index: Source/JavaScriptCore/tests/stress/poly-chain-getter.js >=================================================================== >--- Source/JavaScriptCore/tests/stress/poly-chain-getter.js (revision 0) >+++ Source/JavaScriptCore/tests/stress/poly-chain-getter.js (working copy) >@@ -0,0 +1,30 @@ >+function Cons() { >+} >+Cons.prototype.__defineGetter__("f", function() { >+ counter++; >+ return 84; >+}); >+ >+function foo(o) { >+ return o.f; >+} >+ >+noInline(foo); >+ >+var counter = 0; >+ >+function test(o, expected, expectedCount) { >+ var result = foo(o); >+ if (result != expected) >+ throw new Error("Bad result: " + result); >+ if (counter != expectedCount) >+ throw new Error("Bad counter value: " + counter); >+} >+ >+for (var i = 0; i < 100000; ++i) { >+ test(new Cons(), 84, counter + 1); >+ >+ var o = new Cons(); >+ o.g = 54; >+ test(o, 84, counter + 1); >+} >Index: Source/JavaScriptCore/tests/stress/poly-chain-then-getter.js >=================================================================== >--- Source/JavaScriptCore/tests/stress/poly-chain-then-getter.js (revision 0) >+++ Source/JavaScriptCore/tests/stress/poly-chain-then-getter.js (working copy) >@@ -0,0 +1,31 @@ >+function Cons1() { >+} >+Cons1.prototype.f = 42; >+ >+function Cons2() { >+} >+Cons2.prototype.__defineGetter__("f", function() { >+ counter++; >+ return 84; >+}); >+ >+function foo(o) { >+ return o.f; >+} >+ >+noInline(foo); >+ >+var counter = 0; >+ >+function test(o, expected, expectedCount) { >+ var result = foo(o); >+ if (result != expected) >+ throw new Error("Bad result: " + result); >+ if (counter != expectedCount) >+ throw new Error("Bad counter value: " + counter); >+} >+ >+for (var i = 0; i < 100000; ++i) { >+ test(new Cons1(), 42, counter); >+ test(new Cons2(), 84, counter + 1); >+} >Index: Source/JavaScriptCore/tests/stress/poly-getter-combo.js >=================================================================== >--- Source/JavaScriptCore/tests/stress/poly-getter-combo.js (revision 0) >+++ Source/JavaScriptCore/tests/stress/poly-getter-combo.js (working copy) >@@ -0,0 +1,40 @@ >+function Cons1() { >+} >+Cons1.prototype.f = 42; >+ >+function Cons2() { >+} >+Cons2.prototype.__defineGetter__("f", function() { >+ counter++; >+ return 84; >+}); >+ >+function foo(o) { >+ return o.f; >+} >+ >+noInline(foo); >+ >+var counter = 0; >+ >+function test(o, expected, expectedCount) { >+ var result = foo(o); >+ if (result != expected) >+ throw new Error("Bad result: " + result); >+ if (counter != expectedCount) >+ throw new Error("Bad counter value: " + counter); >+} >+ >+for (var i = 0; i < 100000; ++i) { >+ test(new Cons1(), 42, counter); >+ test(new Cons2(), 84, counter + 1); >+ >+ var o = {}; >+ o.__defineGetter__("f", function() { >+ counter++; >+ return 84; >+ }); >+ test(o, 84, counter + 1); >+ >+ test({f: 42}, 42, counter); >+} >Index: Source/JavaScriptCore/tests/stress/poly-getter-then-chain.js >=================================================================== >--- Source/JavaScriptCore/tests/stress/poly-getter-then-chain.js (revision 0) >+++ Source/JavaScriptCore/tests/stress/poly-getter-then-chain.js (working copy) >@@ -0,0 +1,31 @@ >+function Cons1() { >+} >+Cons1.prototype.f = 42; >+ >+function Cons2() { >+} >+Cons2.prototype.__defineGetter__("f", function() { >+ counter++; >+ return 84; >+}); >+ >+function foo(o) { >+ return o.f; >+} >+ >+noInline(foo); >+ >+var counter = 0; >+ >+function test(o, expected, expectedCount) { >+ var result = foo(o); >+ if (result != expected) >+ throw new Error("Bad result: " + result); >+ if (counter != expectedCount) >+ throw new Error("Bad counter value: " + counter); >+} >+ >+for (var i = 0; i < 100000; ++i) { >+ test(new Cons2(), 84, counter + 1); >+ test(new Cons1(), 42, counter); >+} >Index: Source/JavaScriptCore/tests/stress/poly-getter-then-self.js >=================================================================== >--- Source/JavaScriptCore/tests/stress/poly-getter-then-self.js (revision 0) >+++ Source/JavaScriptCore/tests/stress/poly-getter-then-self.js (working copy) >@@ -0,0 +1,26 @@ >+function foo(o) { >+ return o.f; >+} >+ >+noInline(foo); >+ >+var counter = 0; >+ >+function test(o, expected, expectedCount) { >+ var result = foo(o); >+ if (result != expected) >+ throw new Error("Bad result: " + result); >+ if (counter != expectedCount) >+ throw new Error("Bad counter value: " + counter); >+} >+ >+for (var i = 0; i < 100000; ++i) { >+ var o = {}; >+ o.__defineGetter__("f", function() { >+ counter++; >+ return 84; >+ }); >+ test(o, 84, counter + 1); >+ >+ test({f: 42}, 42, counter); >+} >Index: Source/JavaScriptCore/tests/stress/poly-self-getter.js >=================================================================== >--- Source/JavaScriptCore/tests/stress/poly-self-getter.js (revision 0) >+++ Source/JavaScriptCore/tests/stress/poly-self-getter.js (working copy) >@@ -0,0 +1,31 @@ >+function foo(o) { >+ return o.f; >+} >+ >+noInline(foo); >+ >+var counter = 0; >+ >+function test(o, expected, expectedCount) { >+ var result = foo(o); >+ if (result != expected) >+ throw new Error("Bad result: " + result); >+ if (counter != expectedCount) >+ throw new Error("Bad counter value: " + counter); >+} >+ >+function getter() { >+ counter++; >+ return 84; >+} >+ >+for (var i = 0; i < 100000; ++i) { >+ var o = {}; >+ o.__defineGetter__("f", getter); >+ test(o, 84, counter + 1); >+ >+ var o = {}; >+ o.__defineGetter__("f", getter); >+ o.g = 54; >+ test(o, 84, counter + 1); >+} >Index: Source/JavaScriptCore/tests/stress/poly-self-then-getter.js >=================================================================== >--- Source/JavaScriptCore/tests/stress/poly-self-then-getter.js (revision 0) >+++ Source/JavaScriptCore/tests/stress/poly-self-then-getter.js (working copy) >@@ -0,0 +1,26 @@ >+function foo(o) { >+ return o.f; >+} >+ >+noInline(foo); >+ >+var counter = 0; >+ >+function test(o, expected, expectedCount) { >+ var result = foo(o); >+ if (result != expected) >+ throw new Error("Bad result: " + result); >+ if (counter != expectedCount) >+ throw new Error("Bad counter value: " + counter); >+} >+ >+for (var i = 0; i < 100000; ++i) { >+ test({f: 42}, 42, counter); >+ >+ var o = {}; >+ o.__defineGetter__("f", function() { >+ counter++; >+ return 84; >+ }); >+ test(o, 84, counter + 1); >+} >Index: Source/JavaScriptCore/tests/stress/weird-getter-counter.js >=================================================================== >--- Source/JavaScriptCore/tests/stress/weird-getter-counter.js (revision 0) >+++ Source/JavaScriptCore/tests/stress/weird-getter-counter.js (working copy) >@@ -0,0 +1,24 @@ >+function foo(o) { >+ return o.f; >+} >+ >+noInline(foo); >+ >+var counter = 0; >+ >+function test(o, expected, expectedCount) { >+ var result = foo(o); >+ if (result != expected) >+ throw new Error("Bad result: " + result); >+ if (counter != expectedCount) >+ throw new Error("Bad counter value: " + counter); >+} >+ >+for (var i = 0; i < 100000; ++i) { >+ var o = {}; >+ o.__defineGetter__("f", function() { >+ counter++; >+ return 84; >+ }); >+ test(o, 84, counter + 1); >+} >Index: Source/WTF/ChangeLog >=================================================================== >--- Source/WTF/ChangeLog (revision 169119) >+++ Source/WTF/ChangeLog (working copy) >@@ -1,3 +1,13 @@ >+2014-05-19 Filip Pizlo <fpizlo@apple.com> >+ >+ [ftlopt] DFG bytecode parser should turn GetById with nothing but a Getter stub as stuff+handleCall, and handleCall should be allowed to inline if it wants to >+ https://bugs.webkit.org/show_bug.cgi?id=133105 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * wtf/Bag.h: >+ (WTF::Bag::iterator::operator!=): >+ > 2014-05-07 Filip Pizlo <fpizlo@apple.com> > > UNREACHABLE_FOR_PLATFORM() is meant to be a release crash. >Index: Source/WTF/wtf/Bag.h >=================================================================== >--- Source/WTF/wtf/Bag.h (revision 169014) >+++ Source/WTF/wtf/Bag.h (working copy) >@@ -83,6 +83,11 @@ public: > { > return m_node == other.m_node; > } >+ >+ bool operator!=(const iterator& other) const >+ { >+ return !(*this == other); >+ } > private: > template<typename U> friend class WTF::Bag; > Node* m_node; >Index: LayoutTests/ChangeLog >=================================================================== >--- LayoutTests/ChangeLog (revision 169119) >+++ LayoutTests/ChangeLog (working copy) >@@ -1,3 +1,14 @@ >+2014-05-19 Filip Pizlo <fpizlo@apple.com> >+ >+ [ftlopt] DFG bytecode parser should turn GetById with nothing but a Getter stub as stuff+handleCall, and handleCall should be allowed to inline if it wants to >+ https://bugs.webkit.org/show_bug.cgi?id=133105 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * js/regress/getter-no-activation-expected.txt: Added. >+ * js/regress/getter-no-activation.html: Added. >+ * js/regress/script-tests/getter-no-activation.js: Added. >+ > 2014-05-08 Filip Pizlo <fpizlo@apple.com> > > jsSubstring() should be lazy >Index: LayoutTests/js/regress/getter-no-activation-expected.txt >=================================================================== >--- LayoutTests/js/regress/getter-no-activation-expected.txt (revision 0) >+++ LayoutTests/js/regress/getter-no-activation-expected.txt (working copy) >@@ -0,0 +1,10 @@ >+JSRegress/getter-no-activation >+ >+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". >+ >+ >+PASS no exception thrown >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+ >Index: LayoutTests/js/regress/getter-no-activation.html >=================================================================== >--- LayoutTests/js/regress/getter-no-activation.html (revision 0) >+++ LayoutTests/js/regress/getter-no-activation.html (working copy) >@@ -0,0 +1,12 @@ >+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> >+<html> >+<head> >+<script src="../../resources/js-test-pre.js"></script> >+</head> >+<body> >+<script src="../../resources/regress-pre.js"></script> >+<script src="script-tests/getter-no-activation.js"></script> >+<script src="../../resources/regress-post.js"></script> >+<script src="../../resources/js-test-post.js"></script> >+</body> >+</html> >Index: LayoutTests/js/regress/script-tests/getter-no-activation.js >=================================================================== >--- LayoutTests/js/regress/script-tests/getter-no-activation.js (revision 0) >+++ LayoutTests/js/regress/script-tests/getter-no-activation.js (working copy) >@@ -0,0 +1,13 @@ >+(function() { >+ var o = {_f:42}; >+ o.__defineGetter__("f", function() { return this._f; }); >+ (function() { >+ var result = 0; >+ var n = 2000000; >+ for (var i = 0; i < n; ++i) >+ result += o.f; >+ if (result != n * 42) >+ throw "Error: bad result: " + result; >+ })(); >+})(); >+
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
Flags:
msaboff
:
review+
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 133105
:
231750
| 231776