WebKit Bugzilla
Attachment 341849 Details for
Bug 164904
: We should support CreateThis in the FTL
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
rebased patch
blah.patch (text/plain), 194.45 KB, created by
Filip Pizlo
on 2018-06-02 12:45:13 PDT
(
hide
)
Description:
rebased patch
Filename:
MIME Type:
Creator:
Filip Pizlo
Created:
2018-06-02 12:45:13 PDT
Size:
194.45 KB
patch
obsolete
>Index: JSTests/ChangeLog >=================================================================== >--- JSTests/ChangeLog (revision 232441) >+++ JSTests/ChangeLog (working copy) >@@ -1,3 +1,30 @@ >+2018-06-02 Filip Pizlo <fpizlo@apple.com> >+ >+ We should support CreateThis in the FTL >+ https://bugs.webkit.org/show_bug.cgi?id=164904 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * microbenchmarks/polyvariant-get-by-id-shorter-tower.js: Added. >+ (polyvariant): >+ (Foo.prototype.func): >+ (Foo): >+ (foo): >+ (Bar.prototype.func): >+ (Bar): >+ (bar): >+ * microbenchmarks/polyvariant-get-by-id-tower.js: Added. >+ (polyvariant): >+ (Foo.prototype.func): >+ (Foo): >+ (foo): >+ (Bar.prototype.func): >+ (Bar): >+ (bar): >+ (Baz.prototype.func): >+ (Baz): >+ (baz): >+ > 2018-06-02 Caio Lima <ticaiolima@gmail.com> > > [ESNext][BigInt] Implement support for addition operations >Index: JSTests/microbenchmarks/polyvariant-get-by-id-shorter-tower.js >=================================================================== >--- JSTests/microbenchmarks/polyvariant-get-by-id-shorter-tower.js (nonexistent) >+++ JSTests/microbenchmarks/polyvariant-get-by-id-shorter-tower.js (working copy) >@@ -0,0 +1,46 @@ >+(function() { >+ var globalO; >+ >+ function polyvariant() >+ { >+ return globalO.func(); >+ } >+ >+ class Foo { >+ func() >+ { >+ return 42; >+ } >+ } >+ >+ var fooO = new Foo(); >+ >+ function foo() >+ { >+ globalO = fooO; >+ return polyvariant(); >+ } >+ >+ class Bar { >+ func() >+ { >+ return foo(); >+ } >+ } >+ >+ var barO = new Bar(); >+ >+ function bar() >+ { >+ globalO = barO; >+ return polyvariant(); >+ } >+ >+ var count = 1000000; >+ var result = 0; >+ for (var i = 0; i < count; ++i) >+ result += bar(); >+ >+ if (result != count * 42) >+ throw "Error: bad result: " + result; >+})(); >Index: JSTests/microbenchmarks/polyvariant-get-by-id-tower.js >=================================================================== >--- JSTests/microbenchmarks/polyvariant-get-by-id-tower.js (nonexistent) >+++ JSTests/microbenchmarks/polyvariant-get-by-id-tower.js (working copy) >@@ -0,0 +1,61 @@ >+(function() { >+ var globalO; >+ >+ function polyvariant() >+ { >+ return globalO.func(); >+ } >+ >+ class Foo { >+ func() >+ { >+ return 42; >+ } >+ } >+ >+ var fooO = new Foo(); >+ >+ function foo() >+ { >+ globalO = fooO; >+ return polyvariant(); >+ } >+ >+ class Bar { >+ func() >+ { >+ return foo(); >+ } >+ } >+ >+ var barO = new Bar(); >+ >+ function bar() >+ { >+ globalO = barO; >+ return polyvariant(); >+ } >+ >+ class Baz { >+ func() >+ { >+ return bar(); >+ } >+ } >+ >+ var bazO = new Baz(); >+ >+ function baz() >+ { >+ globalO = bazO; >+ return polyvariant(); >+ } >+ >+ var count = 1000000; >+ var result = 0; >+ for (var i = 0; i < count; ++i) >+ result += baz(); >+ >+ if (result != count * 42) >+ throw "Error: bad result: " + result; >+})(); >Index: Source/JavaScriptCore/ChangeLog >=================================================================== >--- Source/JavaScriptCore/ChangeLog (revision 232441) >+++ Source/JavaScriptCore/ChangeLog (working copy) >@@ -1,3 +1,289 @@ >+2018-06-02 Filip Pizlo <fpizlo@apple.com> >+ >+ We should support CreateThis in the FTL >+ https://bugs.webkit.org/show_bug.cgi?id=164904 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ This started with Saam's patch to implement CreateThis in the FTL, but turned into a type >+ inference adventure. >+ >+ CreateThis in the FTL was a massive regression in raytrace because it disturbed that >+ benchmark's extremely perverse way of winning at type inference: >+ >+ - The benchmark wanted polyvariant devirtualization of an object construction helper. But, >+ the polyvariant profiler wasn't powerful enough to reliably devirtualize that code. So, the >+ benchmark was falling back to other mechanisms... >+ >+ - The construction helper could not tier up into the FTL. When the DFG compiled it, it would >+ see that the IC had 4 cases. That's too polymorphic for the DFG. So, the DFG would emit a >+ GetById. Shortly after the DFG compile, that get_by_id would see many more cases, but now >+ that the helper was compiled by the DFG, the baseline get_by_id would not see those cases. >+ The DFG's GetById would "hide" those cases. The number of cases the DFG's GetById would see >+ is larger than our polymorphic list limit (limit = 8, case count = 13, I think). >+ >+ Note that if the FTL compiles that construction helper, it sees the 4 cases, turns them >+ into a MultiGetByOffset, then suffers from exits when the new cases hit, and then exits to >+ baseline, which then sees those cases. Luckily, the FTL was not compiling the construction >+ helper because it had a CreateThis. >+ >+ - Compilations that inlined the construction helper would have gotten super lucky with >+ parse-time constant folding, so they knew what structure the input to the get_by_id would >+ have at parse time. This is only profitable if the get_by_id parsing computed a >+ GetByIdStatus that had a finite number of cases. Because the 13 cases were being hidden by >+ the DFG GetById and GetByIdStatus would only look at the baseline get_by_id, which had 4 >+ cases, we would indeed get a finite number of cases. The parser would then prune those >+ cases to just one - based on its knowledge of the structure - and that would result in that >+ get_by_id being folded at parse time to a constant. >+ >+ - The subsequent op_call would inline based on parse-time knowledge of that constant. >+ >+ This patch comprehensively fixes these issues, as well as other issues that come up along the >+ way: >+ >+ - Polyvariant profiling now consults every DFG or FTL code block that participated in any >+ subset of the inline stack that includes the IC we're profiling. For example, if we have >+ an inline stack like foo->bar->baz, with baz on top, then we will consult DFG or FTL >+ compilations for foo, bar, and baz. In foo, we'll look up foo->bar->baz; in bar we'll look >+ up bar->baz; etc. This fixes two problems encountered in raytrace. First, it ensures that >+ a DFG GetById cannot hide anything from the profiling of that get_by_id, since the >+ polyvariant profiling code will always consult it. Second, it enables raytrace to benefit >+ from polyvariant profling. Previously, the polyvariant profiler would only look at the >+ previous DFG compilation of foo and look up foo->bar->baz. But that only works if DFG-foo >+ had inlined bar and then baz. It may not have done that, because those calls could have >+ required polyvariant profiling that was only available in the FTL. >+ >+ - Inlining an inline cache now preserves as much information as profiling. One challenge of >+ polyvariant profiling is that the FTL compile for bar (that includes bar->baz) could have >+ inlined an inline cache based on polyvariant profiling. So, when the FTL compile for foo >+ (that includes foo->bar->baz) asks bar what it knows about that IC inside bar->baz, it will >+ say "I don't have such an IC". At this point the DFG compilation that included that IC that >+ gave us the information that we used to inline the IC is no longer alive. To keep us from >+ losing the information we learned about the IC, there is now a RecordedStatuses data >+ structure that preserves the statuses we use for inlining ICs. We also filter those >+ statuses according to things we learn from AI. This further reduces the risk of information >+ about an IC being forgotten. >+ >+ - Exit profiling now considers whether or not an exit happened from inline code. This >+ protects us in the case where the not-inlined version of an IC exited a lot because of >+ polymorphism that doesn't exist in the inlined version. So, when using polyvariant >+ profiling data, we consider only inlined exits. >+ >+ Altogether this patch is performance-neutral in run-jsc-benchmarks, except for speed-ups in >+ microbenchmarks and a compile time regression. Octane/boyer speeds up by 4.7%, but I'm not >+ sure if that's real. Also, it's a 1.2% regression on V8Spider-CompileTime. That's a smaller >+ regression than recent compile time progressions, so I think that's an OK trade-off. Also, I >+ would expect a compile time regression anytime we fill in FTL coverage. >+ >+ * CMakeLists.txt: >+ * JavaScriptCore.xcodeproj/project.pbxproj: >+ * Sources.txt: >+ * bytecode/ByValInfo.h: >+ * bytecode/BytecodeDumper.cpp: >+ (JSC::BytecodeDumper<Block>::printGetByIdCacheStatus): >+ (JSC::BytecodeDumper<Block>::printPutByIdCacheStatus): >+ (JSC::BytecodeDumper<Block>::printInByIdCacheStatus): >+ (JSC::BytecodeDumper<Block>::dumpCallLinkStatus): >+ (JSC::BytecodeDumper<CodeBlock>::dumpCallLinkStatus): >+ (JSC::BytecodeDumper<Block>::printCallOp): >+ (JSC::BytecodeDumper<Block>::dumpBytecode): >+ (JSC::BytecodeDumper<Block>::dumpBlock): >+ * bytecode/BytecodeDumper.h: >+ * bytecode/CallLinkInfo.h: >+ * bytecode/CallLinkStatus.cpp: >+ (JSC::CallLinkStatus::computeFor): >+ (JSC::CallLinkStatus::computeExitSiteData): >+ (JSC::CallLinkStatus::computeFromCallLinkInfo): >+ (JSC::CallLinkStatus::accountForExits): >+ (JSC::CallLinkStatus::finalize): >+ (JSC::CallLinkStatus::filter): >+ (JSC::CallLinkStatus::computeDFGStatuses): Deleted. >+ * bytecode/CallLinkStatus.h: >+ (JSC::CallLinkStatus::operator bool const): >+ (JSC::CallLinkStatus::operator! const): Deleted. >+ * bytecode/CallVariant.cpp: >+ (JSC::CallVariant::finalize): >+ (JSC::CallVariant::filter): >+ * bytecode/CallVariant.h: >+ (JSC::CallVariant::operator bool const): >+ (JSC::CallVariant::operator! const): Deleted. >+ * bytecode/CodeBlock.cpp: >+ (JSC::CodeBlock::dumpBytecode): >+ (JSC::CodeBlock::propagateTransitions): >+ (JSC::CodeBlock::finalizeUnconditionally): >+ (JSC::CodeBlock::getICStatusMap): >+ (JSC::CodeBlock::resetJITData): >+ (JSC::CodeBlock::getStubInfoMap): Deleted. >+ (JSC::CodeBlock::getCallLinkInfoMap): Deleted. >+ (JSC::CodeBlock::getByValInfoMap): Deleted. >+ * bytecode/CodeBlock.h: >+ * bytecode/CodeOrigin.cpp: >+ (JSC::CodeOrigin::isApproximatelyEqualTo const): >+ (JSC::CodeOrigin::approximateHash const): >+ * bytecode/CodeOrigin.h: >+ (JSC::CodeOrigin::exitingInlineKind const): >+ * bytecode/DFGExitProfile.cpp: >+ (JSC::DFG::FrequentExitSite::dump const): >+ (JSC::DFG::ExitProfile::add): >+ * bytecode/DFGExitProfile.h: >+ (JSC::DFG::FrequentExitSite::FrequentExitSite): >+ (JSC::DFG::FrequentExitSite::operator== const): >+ (JSC::DFG::FrequentExitSite::subsumes const): >+ (JSC::DFG::FrequentExitSite::hash const): >+ (JSC::DFG::FrequentExitSite::inlineKind const): >+ (JSC::DFG::FrequentExitSite::withInlineKind const): >+ (JSC::DFG::QueryableExitProfile::hasExitSite const): >+ (JSC::DFG::QueryableExitProfile::hasExitSiteWithSpecificJITType const): >+ (JSC::DFG::QueryableExitProfile::hasExitSiteWithSpecificInlineKind const): >+ * bytecode/ExitFlag.cpp: Added. >+ (JSC::ExitFlag::dump const): >+ * bytecode/ExitFlag.h: Added. >+ (JSC::ExitFlag::ExitFlag): >+ (JSC::ExitFlag::operator| const): >+ (JSC::ExitFlag::operator|=): >+ (JSC::ExitFlag::operator& const): >+ (JSC::ExitFlag::operator&=): >+ (JSC::ExitFlag::operator bool const): >+ (JSC::ExitFlag::isSet const): >+ * bytecode/ExitingInlineKind.cpp: Added. >+ (WTF::printInternal): >+ * bytecode/ExitingInlineKind.h: Added. >+ * bytecode/GetByIdStatus.cpp: >+ (JSC::GetByIdStatus::computeFor): >+ (JSC::GetByIdStatus::computeForStubInfo): >+ (JSC::GetByIdStatus::slowVersion const): >+ (JSC::GetByIdStatus::markIfCheap): >+ (JSC::GetByIdStatus::finalize): >+ (JSC::GetByIdStatus::hasExitSite): Deleted. >+ * bytecode/GetByIdStatus.h: >+ * bytecode/GetByIdVariant.cpp: >+ (JSC::GetByIdVariant::markIfCheap): >+ (JSC::GetByIdVariant::finalize): >+ * bytecode/GetByIdVariant.h: >+ * bytecode/ICStatusMap.cpp: Added. >+ (JSC::ICStatusContext::get const): >+ (JSC::ICStatusContext::isInlined const): >+ (JSC::ICStatusContext::inlineKind const): >+ * bytecode/ICStatusMap.h: Added. >+ * bytecode/ICStatusUtils.cpp: Added. >+ (JSC::hasBadCacheExitSite): >+ * bytecode/ICStatusUtils.h: >+ * bytecode/InstanceOfStatus.cpp: >+ (JSC::InstanceOfStatus::computeFor): >+ * bytecode/InstanceOfStatus.h: >+ * bytecode/PolyProtoAccessChain.h: >+ * bytecode/PutByIdStatus.cpp: >+ (JSC::PutByIdStatus::hasExitSite): >+ (JSC::PutByIdStatus::computeFor): >+ (JSC::PutByIdStatus::slowVersion const): >+ (JSC::PutByIdStatus::markIfCheap): >+ (JSC::PutByIdStatus::finalize): >+ (JSC::PutByIdStatus::filter): >+ * bytecode/PutByIdStatus.h: >+ * bytecode/PutByIdVariant.cpp: >+ (JSC::PutByIdVariant::markIfCheap): >+ (JSC::PutByIdVariant::finalize): >+ * bytecode/PutByIdVariant.h: >+ (JSC::PutByIdVariant::structureSet const): >+ * bytecode/RecordedStatuses.cpp: Added. >+ (JSC::RecordedStatuses::operator=): >+ (JSC::RecordedStatuses::RecordedStatuses): >+ (JSC::RecordedStatuses::addCallLinkStatus): >+ (JSC::RecordedStatuses::addGetByIdStatus): >+ (JSC::RecordedStatuses::addPutByIdStatus): >+ (JSC::RecordedStatuses::markIfCheap): >+ (JSC::RecordedStatuses::finalizeWithoutDeleting): >+ (JSC::RecordedStatuses::finalize): >+ (JSC::RecordedStatuses::shrinkToFit): >+ * bytecode/RecordedStatuses.h: Added. >+ (JSC::RecordedStatuses::RecordedStatuses): >+ (JSC::RecordedStatuses::forEachVector): >+ * bytecode/StructureSet.cpp: >+ (JSC::StructureSet::markIfCheap const): >+ (JSC::StructureSet::isStillAlive const): >+ * bytecode/StructureSet.h: >+ * bytecode/TerminatedCodeOrigin.h: Added. >+ (JSC::TerminatedCodeOrigin::TerminatedCodeOrigin): >+ (JSC::TerminatedCodeOriginHashTranslator::hash): >+ (JSC::TerminatedCodeOriginHashTranslator::equal): >+ * bytecode/Watchpoint.cpp: >+ (WTF::printInternal): >+ * bytecode/Watchpoint.h: >+ * dfg/DFGAbstractInterpreter.h: >+ * dfg/DFGAbstractInterpreterInlines.h: >+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): >+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::filterICStatus): >+ * dfg/DFGByteCodeParser.cpp: >+ (JSC::DFG::ByteCodeParser::handleCall): >+ (JSC::DFG::ByteCodeParser::handleVarargsCall): >+ (JSC::DFG::ByteCodeParser::handleDOMJITGetter): >+ (JSC::DFG::ByteCodeParser::handleModuleNamespaceLoad): >+ (JSC::DFG::ByteCodeParser::handleGetById): >+ (JSC::DFG::ByteCodeParser::handlePutById): >+ (JSC::DFG::ByteCodeParser::parseBlock): >+ (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry): >+ (JSC::DFG::ByteCodeParser::InlineStackEntry::~InlineStackEntry): >+ (JSC::DFG::ByteCodeParser::parse): >+ * dfg/DFGClobberize.h: >+ (JSC::DFG::clobberize): >+ * dfg/DFGClobbersExitState.cpp: >+ (JSC::DFG::clobbersExitState): >+ * dfg/DFGCommonData.h: >+ * dfg/DFGConstantFoldingPhase.cpp: >+ (JSC::DFG::ConstantFoldingPhase::foldConstants): >+ * dfg/DFGDesiredWatchpoints.h: >+ (JSC::DFG::SetPointerAdaptor::hasBeenInvalidated): >+ * dfg/DFGDoesGC.cpp: >+ (JSC::DFG::doesGC): >+ * dfg/DFGFixupPhase.cpp: >+ (JSC::DFG::FixupPhase::fixupNode): >+ * dfg/DFGGraph.cpp: >+ (JSC::DFG::Graph::dump): >+ * dfg/DFGMayExit.cpp: >+ * dfg/DFGNode.h: >+ (JSC::DFG::Node::hasCallLinkStatus): >+ (JSC::DFG::Node::callLinkStatus): >+ (JSC::DFG::Node::hasGetByIdStatus): >+ (JSC::DFG::Node::getByIdStatus): >+ (JSC::DFG::Node::hasPutByIdStatus): >+ (JSC::DFG::Node::putByIdStatus): >+ * dfg/DFGNodeType.h: >+ * dfg/DFGOSRExitBase.cpp: >+ (JSC::DFG::OSRExitBase::considerAddingAsFrequentExitSiteSlow): >+ * dfg/DFGObjectAllocationSinkingPhase.cpp: >+ * dfg/DFGPlan.cpp: >+ (JSC::DFG::Plan::reallyAdd): >+ (JSC::DFG::Plan::checkLivenessAndVisitChildren): >+ (JSC::DFG::Plan::finalizeInGC): >+ * dfg/DFGPlan.h: >+ * dfg/DFGPredictionPropagationPhase.cpp: >+ * dfg/DFGSafeToExecute.h: >+ (JSC::DFG::safeToExecute): >+ * dfg/DFGSpeculativeJIT32_64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * dfg/DFGSpeculativeJIT64.cpp: >+ (JSC::DFG::SpeculativeJIT::compile): >+ * dfg/DFGStrengthReductionPhase.cpp: >+ (JSC::DFG::StrengthReductionPhase::handleNode): >+ * dfg/DFGWorklist.cpp: >+ (JSC::DFG::Worklist::removeDeadPlans): >+ * ftl/FTLAbstractHeapRepository.h: >+ * ftl/FTLCapabilities.cpp: >+ (JSC::FTL::canCompile): >+ * ftl/FTLLowerDFGToB3.cpp: >+ (JSC::FTL::DFG::LowerDFGToB3::compileNode): >+ (JSC::FTL::DFG::LowerDFGToB3::compileCreateThis): >+ (JSC::FTL::DFG::LowerDFGToB3::compileFilterICStatus): >+ * jit/PolymorphicCallStubRoutine.cpp: >+ (JSC::PolymorphicCallStubRoutine::hasEdges const): >+ (JSC::PolymorphicCallStubRoutine::edges const): >+ * jit/PolymorphicCallStubRoutine.h: >+ * profiler/ProfilerBytecodeSequence.cpp: >+ (JSC::Profiler::BytecodeSequence::BytecodeSequence): >+ * runtime/FunctionRareData.cpp: >+ (JSC::FunctionRareData::initializeObjectAllocationProfile): >+ * runtime/Options.h: >+ > 2018-06-02 Caio Lima <ticaiolima@gmail.com> > > [ESNext][BigInt] Implement support for addition operations >Index: Source/JavaScriptCore/CMakeLists.txt >=================================================================== >--- Source/JavaScriptCore/CMakeLists.txt (revision 232441) >+++ Source/JavaScriptCore/CMakeLists.txt (working copy) >@@ -440,6 +440,7 @@ set(JavaScriptCore_PRIVATE_FRAMEWORK_HEA > bytecode/ExecutableToCodeBlockEdge.h > bytecode/ExecutionCounter.h > bytecode/ExitKind.h >+ bytecode/ExitingInlineKind.h > bytecode/ExitingJITType.h > bytecode/ExpressionRangeInfo.h > bytecode/HandlerInfo.h >Index: Source/JavaScriptCore/Sources.txt >=================================================================== >--- Source/JavaScriptCore/Sources.txt (revision 232441) >+++ Source/JavaScriptCore/Sources.txt (working copy) >@@ -212,13 +212,17 @@ bytecode/DirectEvalCodeCache.cpp > bytecode/EvalCodeBlock.cpp > bytecode/ExecutableToCodeBlockEdge.cpp > bytecode/ExecutionCounter.cpp >+bytecode/ExitFlag.cpp > bytecode/ExitKind.cpp >+bytecode/ExitingInlineKind.cpp > bytecode/ExitingJITType.cpp > bytecode/FullCodeOrigin.cpp > bytecode/FunctionCodeBlock.cpp > bytecode/GetByIdStatus.cpp > bytecode/GetByIdVariant.cpp > bytecode/GetterSetterAccessCase.cpp >+bytecode/ICStatusMap.cpp >+bytecode/ICStatusUtils.cpp > bytecode/InByIdStatus.cpp > bytecode/InByIdVariant.cpp > bytecode/InlineAccess.cpp >@@ -247,6 +251,7 @@ bytecode/ProxyableAccessCase.cpp > bytecode/PutByIdFlags.cpp > bytecode/PutByIdStatus.cpp > bytecode/PutByIdVariant.cpp >+bytecode/RecordedStatuses.cpp > bytecode/ReduceWhitespace.cpp > bytecode/SpecialPointer.cpp > bytecode/SpeculatedType.cpp >Index: Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >=================================================================== >--- Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (revision 232441) >+++ Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (working copy) >@@ -297,6 +297,11 @@ > 0F426A491460CBB700131F8F /* VirtualRegister.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F426A461460CBAB00131F8F /* VirtualRegister.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 0F426A4B1460CD6E00131F8F /* DataFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F426A4A1460CD6B00131F8F /* DataFormat.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 0F431738146BAC69007E3890 /* ListableHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F431736146BAC65007E3890 /* ListableHandler.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ 0F44A7B020BF68620022B171 /* ExitFlag.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F44A7AE20BF685F0022B171 /* ExitFlag.h */; }; >+ 0F44A7B120BF68C90022B171 /* ExitingInlineKind.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F44A7A720BF685D0022B171 /* ExitingInlineKind.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ 0F44A7B220BF68CE0022B171 /* ICStatusMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F44A7AF20BF685F0022B171 /* ICStatusMap.h */; }; >+ 0F44A7B320BF68D10022B171 /* RecordedStatuses.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F44A7AA20BF685E0022B171 /* RecordedStatuses.h */; }; >+ 0F44A7B420BF68D90022B171 /* TerminatedCodeOrigin.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F44A7A820BF685E0022B171 /* TerminatedCodeOrigin.h */; }; > 0F4570391BE44C910062A629 /* AirEliminateDeadCode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F4570371BE44C910062A629 /* AirEliminateDeadCode.h */; }; > 0F45703D1BE45F0A0062A629 /* AirReportUsedRegisters.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F45703B1BE45F0A0062A629 /* AirReportUsedRegisters.h */; }; > 0F4570411BE584CA0062A629 /* B3TimingScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F45703F1BE584CA0062A629 /* B3TimingScope.h */; }; >@@ -2289,6 +2294,16 @@ > 0F426A4A1460CD6B00131F8F /* DataFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataFormat.h; sourceTree = "<group>"; }; > 0F42B3C0201EB50900357031 /* Allocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Allocator.cpp; sourceTree = "<group>"; }; > 0F431736146BAC65007E3890 /* ListableHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ListableHandler.h; sourceTree = "<group>"; }; >+ 0F44A7A720BF685D0022B171 /* ExitingInlineKind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExitingInlineKind.h; sourceTree = "<group>"; }; >+ 0F44A7A820BF685E0022B171 /* TerminatedCodeOrigin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TerminatedCodeOrigin.h; sourceTree = "<group>"; }; >+ 0F44A7A920BF685E0022B171 /* ExitFlag.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExitFlag.cpp; sourceTree = "<group>"; }; >+ 0F44A7AA20BF685E0022B171 /* RecordedStatuses.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecordedStatuses.h; sourceTree = "<group>"; }; >+ 0F44A7AB20BF685E0022B171 /* ICStatusMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ICStatusMap.cpp; sourceTree = "<group>"; }; >+ 0F44A7AC20BF685F0022B171 /* ExitingInlineKind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExitingInlineKind.cpp; sourceTree = "<group>"; }; >+ 0F44A7AD20BF685F0022B171 /* RecordedStatuses.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RecordedStatuses.cpp; sourceTree = "<group>"; }; >+ 0F44A7AE20BF685F0022B171 /* ExitFlag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExitFlag.h; sourceTree = "<group>"; }; >+ 0F44A7AF20BF685F0022B171 /* ICStatusMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ICStatusMap.h; sourceTree = "<group>"; }; >+ 0F44A7B520C0BE3F0022B171 /* ICStatusUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ICStatusUtils.cpp; sourceTree = "<group>"; }; > 0F4570361BE44C910062A629 /* AirEliminateDeadCode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirEliminateDeadCode.cpp; path = b3/air/AirEliminateDeadCode.cpp; sourceTree = "<group>"; }; > 0F4570371BE44C910062A629 /* AirEliminateDeadCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AirEliminateDeadCode.h; path = b3/air/AirEliminateDeadCode.h; sourceTree = "<group>"; }; > 0F45703A1BE45F0A0062A629 /* AirReportUsedRegisters.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirReportUsedRegisters.cpp; path = b3/air/AirReportUsedRegisters.cpp; sourceTree = "<group>"; }; >@@ -7664,6 +7679,10 @@ > 0F60FE8E1FFC36FD0003320A /* ExecutableToCodeBlockEdge.h */, > 0F56A1D415001CF2002992B1 /* ExecutionCounter.cpp */, > 0F56A1D115000F31002992B1 /* ExecutionCounter.h */, >+ 0F44A7A920BF685E0022B171 /* ExitFlag.cpp */, >+ 0F44A7AE20BF685F0022B171 /* ExitFlag.h */, >+ 0F44A7AC20BF685F0022B171 /* ExitingInlineKind.cpp */, >+ 0F44A7A720BF685D0022B171 /* ExitingInlineKind.h */, > 0F0332BF18ADFAE1005F979A /* ExitingJITType.cpp */, > 0F3AC753188E5EC80032029F /* ExitingJITType.h */, > 0FB105821675480C00F8AB6E /* ExitKind.cpp */, >@@ -7680,6 +7699,9 @@ > 0F0332C218B01763005F979A /* GetByIdVariant.h */, > 14AD91081DCA92940014F9FE /* GlobalCodeBlock.h */, > 0F0B83A814BCF55E00885B4F /* HandlerInfo.h */, >+ 0F44A7AB20BF685E0022B171 /* ICStatusMap.cpp */, >+ 0F44A7AF20BF685F0022B171 /* ICStatusMap.h */, >+ 0F44A7B520C0BE3F0022B171 /* ICStatusUtils.cpp */, > 0FB399BD20AF6B380017E213 /* ICStatusUtils.h */, > E3305FB220B0F78800CEB82B /* InByIdStatus.cpp */, > E3305FAF20B0F78700CEB82B /* InByIdStatus.h */, >@@ -7740,6 +7762,8 @@ > 0F93B4A718B92C4D00178A3F /* PutByIdVariant.cpp */, > 0F93B4A818B92C4D00178A3F /* PutByIdVariant.h */, > 0F9FC8C114E1B5FB00D52AE0 /* PutKind.h */, >+ 0F44A7AD20BF685F0022B171 /* RecordedStatuses.cpp */, >+ 0F44A7AA20BF685E0022B171 /* RecordedStatuses.h */, > 0FF60ABF16740F8100029779 /* ReduceWhitespace.cpp */, > 0FF60AC016740F8100029779 /* ReduceWhitespace.h */, > 0F5541AF1613C1FB00CE3E25 /* SpecialPointer.cpp */, >@@ -7754,6 +7778,7 @@ > BCCF0D070EF0AAB900413C8F /* StructureStubInfo.h */, > 0F4A38F71C8E13DF00190318 /* SuperSampler.cpp */, > 0F4A38F81C8E13DF00190318 /* SuperSampler.h */, >+ 0F44A7A820BF685E0022B171 /* TerminatedCodeOrigin.h */, > 0F2D4DE519832DAC007D4B19 /* ToThisStatus.cpp */, > 0F2D4DE619832DAC007D4B19 /* ToThisStatus.h */, > 0F952ABA1B487A7700C367C5 /* TrackedReferences.cpp */, >@@ -8410,6 +8435,7 @@ > 53D444DC1DAF08AB00B92784 /* B3WasmAddressValue.h in Headers */, > 5341FC721DAC343C00E7E4D7 /* B3WasmBoundsCheckValue.h in Headers */, > 0F2C63B21E60AE4700C13839 /* B3Width.h in Headers */, >+ 0F44A7B220BF68CE0022B171 /* ICStatusMap.h in Headers */, > 52678F8F1A031009006A306D /* BasicBlockLocation.h in Headers */, > 147B83AC0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h in Headers */, > 86976E5F1FA3E8BC00E7C4E1 /* BigIntConstructor.h in Headers */, >@@ -8630,6 +8656,7 @@ > 86EC9DC61328DF82002B2AD7 /* DFGGenerationInfo.h in Headers */, > 86EC9DC81328DF82002B2AD7 /* DFGGraph.h in Headers */, > 0F2FCCFA18A60070001A27F8 /* DFGGraphSafepoint.h in Headers */, >+ 0F44A7B120BF68C90022B171 /* ExitingInlineKind.h in Headers */, > 0FB17661196B8F9E0091052A /* DFGHeapLocation.h in Headers */, > 0FC841691BA8C3210061837D /* DFGInferredTypeCheck.h in Headers */, > 0FB14E211812570B009B6B4D /* DFGInlineCacheWrapper.h in Headers */, >@@ -8780,6 +8807,7 @@ > A7A8AF3817ADB5F3005AB174 /* Float32Array.h in Headers */, > A7A8AF3917ADB5F3005AB174 /* Float64Array.h in Headers */, > 0F24E54317EA9F5900ABB217 /* FPRInfo.h in Headers */, >+ 0F44A7B320BF68D10022B171 /* RecordedStatuses.h in Headers */, > E34EDBF71DB5FFC900DC87A5 /* FrameTracers.h in Headers */, > 0F5513A61D5A682C00C32BD8 /* FreeList.h in Headers */, > 0F6585E11EE0805A0095176D /* FreeListInlines.h in Headers */, >@@ -9129,6 +9157,7 @@ > 7013CA8C1B491A9400CAE613 /* JSJob.h in Headers */, > BC18C4160E16F5CD00B34460 /* JSLexicalEnvironment.h in Headers */, > BC18C4230E16F5CD00B34460 /* JSLock.h in Headers */, >+ 0F44A7B020BF68620022B171 /* ExitFlag.h in Headers */, > C25D709C16DE99F400FCA6BC /* JSManagedValue.h in Headers */, > 2A4BB7F318A41179008A0FCD /* JSManagedValueInternal.h in Headers */, > A700874217CBE8EB00C3E643 /* JSMap.h in Headers */, >@@ -9445,6 +9474,7 @@ > A7299DA217D12848005F5FF9 /* SetPrototype.h in Headers */, > 0FEE98411A8865B700754E93 /* SetupVarargsFrame.h in Headers */, > DC17E8181C9C91D9008A6AB3 /* ShadowChicken.h in Headers */, >+ 0F44A7B420BF68D90022B171 /* TerminatedCodeOrigin.h in Headers */, > DC17E8191C9C91DB008A6AB3 /* ShadowChickenInlines.h in Headers */, > FE3022D31E3D73A500BAC493 /* SigillCrashAnalyzer.h in Headers */, > 0F4D8C781FCA3CFA001D32AC /* SimpleMarkingConstraint.h in Headers */, >Index: Source/JavaScriptCore/bytecode/ByValInfo.h >=================================================================== >--- Source/JavaScriptCore/bytecode/ByValInfo.h (revision 232441) >+++ Source/JavaScriptCore/bytecode/ByValInfo.h (working copy) >@@ -266,12 +266,6 @@ inline unsigned getByValInfoBytecodeInde > return info->bytecodeIndex; > } > >-typedef HashMap<CodeOrigin, ByValInfo*, CodeOriginApproximateHash> ByValInfoMap; >- >-#else // ENABLE(JIT) >- >-typedef HashMap<int, void*> ByValInfoMap; >- > #endif // ENABLE(JIT) > > } // namespace JSC >Index: Source/JavaScriptCore/bytecode/BytecodeDumper.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/BytecodeDumper.cpp (revision 232441) >+++ Source/JavaScriptCore/bytecode/BytecodeDumper.cpp (working copy) >@@ -1,6 +1,6 @@ > /* > * Copyright (C) 2017 Yusuke Suzuki <utatane.tea@gmail.com> >- * Copyright (C) 2017 Apple Inc. All rights reserved. >+ * Copyright (C) 2017-2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -427,7 +427,7 @@ static void dumpChain(PrintStream& out, > } > > template<class Block> >-void BytecodeDumper<Block>::printGetByIdCacheStatus(PrintStream& out, int location, const StubInfoMap& map) >+void BytecodeDumper<Block>::printGetByIdCacheStatus(PrintStream& out, int location, const ICStatusMap& statusMap) > { > const auto* instruction = instructionsBegin() + location; > >@@ -447,7 +447,7 @@ void BytecodeDumper<Block>::printGetById > } > > #if ENABLE(JIT) >- if (StructureStubInfo* stubPtr = map.get(CodeOrigin(location))) { >+ if (StructureStubInfo* stubPtr = statusMap.get(CodeOrigin(location)).stubInfo) { > StructureStubInfo& stubInfo = *stubPtr; > if (stubInfo.resetByGC) > out.print(" (Reset By GC)"); >@@ -488,12 +488,12 @@ void BytecodeDumper<Block>::printGetById > out.printf(")"); > } > #else >- UNUSED_PARAM(map); >+ UNUSED_PARAM(statusMap); > #endif > } > > template<class Block> >-void BytecodeDumper<Block>::printPutByIdCacheStatus(PrintStream& out, int location, const StubInfoMap& map) >+void BytecodeDumper<Block>::printPutByIdCacheStatus(PrintStream& out, int location, const ICStatusMap& statusMap) > { > const auto* instruction = instructionsBegin() + location; > >@@ -521,7 +521,7 @@ void BytecodeDumper<Block>::printPutById > } > > #if ENABLE(JIT) >- if (StructureStubInfo* stubPtr = map.get(CodeOrigin(location))) { >+ if (StructureStubInfo* stubPtr = statusMap.get(CodeOrigin(location)).stubInfo) { > StructureStubInfo& stubInfo = *stubPtr; > if (stubInfo.resetByGC) > out.print(" (Reset By GC)"); >@@ -547,12 +547,12 @@ void BytecodeDumper<Block>::printPutById > out.printf(")"); > } > #else >- UNUSED_PARAM(map); >+ UNUSED_PARAM(statusMap); > #endif > } > > template<class Block> >-void BytecodeDumper<Block>::printInByIdCacheStatus(PrintStream& out, int location, const StubInfoMap& map) >+void BytecodeDumper<Block>::printInByIdCacheStatus(PrintStream& out, int location, const ICStatusMap& statusMap) > { > const auto* instruction = instructionsBegin() + location; > >@@ -561,7 +561,7 @@ void BytecodeDumper<Block>::printInByIdC > UNUSED_PARAM(ident); // tell the compiler to shut up in certain platform configurations. > > #if ENABLE(JIT) >- if (StructureStubInfo* stubPtr = map.get(CodeOrigin(location))) { >+ if (StructureStubInfo* stubPtr = statusMap.get(CodeOrigin(location)).stubInfo) { > StructureStubInfo& stubInfo = *stubPtr; > if (stubInfo.resetByGC) > out.print(" (Reset By GC)"); >@@ -600,26 +600,26 @@ void BytecodeDumper<Block>::printInByIdC > } > #else > UNUSED_PARAM(out); >- UNUSED_PARAM(map); >+ UNUSED_PARAM(statusMap); > #endif > } > > #if ENABLE(JIT) > template<typename Block> >-void BytecodeDumper<Block>::dumpCallLinkStatus(PrintStream&, unsigned, const CallLinkInfoMap&) >+void BytecodeDumper<Block>::dumpCallLinkStatus(PrintStream&, unsigned, const ICStatusMap&) > { > } > > template<> >-void BytecodeDumper<CodeBlock>::dumpCallLinkStatus(PrintStream& out, unsigned location, const CallLinkInfoMap& map) >+void BytecodeDumper<CodeBlock>::dumpCallLinkStatus(PrintStream& out, unsigned location, const ICStatusMap& statusMap) > { > if (block()->jitType() != JITCode::FTLJIT) >- out.print(" status(", CallLinkStatus::computeFor(block(), location, map), ")"); >+ out.print(" status(", CallLinkStatus::computeFor(block(), location, statusMap), ")"); > } > #endif > > template<class Block> >-void BytecodeDumper<Block>::printCallOp(PrintStream& out, int location, const typename Block::Instruction*& it, const char* op, CacheDumpMode cacheDumpMode, bool& hasPrintedProfiling, const CallLinkInfoMap& map) >+void BytecodeDumper<Block>::printCallOp(PrintStream& out, int location, const typename Block::Instruction*& it, const char* op, CacheDumpMode cacheDumpMode, bool& hasPrintedProfiling, const ICStatusMap& statusMap) > { > int dst = (++it)->u.operand; > int func = (++it)->u.operand; >@@ -638,7 +638,7 @@ void BytecodeDumper<Block>::printCallOp( > out.printf(" llint(%p)", object); > } > #if ENABLE(JIT) >- if (CallLinkInfo* info = map.get(CodeOrigin(location))) { >+ if (CallLinkInfo* info = statusMap.get(CodeOrigin(location)).callLinkInfo) { > if (info->haveLastSeenCallee()) { > JSObject* object = info->lastSeenCallee(); > if (auto* function = jsDynamicCast<JSFunction*>(*vm(), object)) >@@ -648,9 +648,9 @@ void BytecodeDumper<Block>::printCallOp( > } > } > >- dumpCallLinkStatus(out, location, map); >+ dumpCallLinkStatus(out, location, statusMap); > #else >- UNUSED_PARAM(map); >+ UNUSED_PARAM(statusMap); > #endif > } > ++it; >@@ -678,7 +678,7 @@ void BytecodeDumper<Block>::printLocatio > } > > template<class Block> >-void BytecodeDumper<Block>::dumpBytecode(PrintStream& out, const typename Block::Instruction* begin, const typename Block::Instruction*& it, const StubInfoMap& stubInfos, const CallLinkInfoMap& callLinkInfos) >+void BytecodeDumper<Block>::dumpBytecode(PrintStream& out, const typename Block::Instruction* begin, const typename Block::Instruction*& it, const ICStatusMap& statusMap) > { > int location = it - begin; > bool hasPrintedProfiling = false; >@@ -1071,7 +1071,7 @@ void BytecodeDumper<Block>::dumpBytecode > int id0 = (++it)->u.operand; > printLocationAndOp(out, location, it, "in_by_id"); > out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), idName(id0, identifier(id0)).data()); >- printInByIdCacheStatus(out, location, stubInfos); >+ printInByIdCacheStatus(out, location, statusMap); > break; > } > case op_in_by_val: { >@@ -1095,7 +1095,7 @@ void BytecodeDumper<Block>::dumpBytecode > printLocationAndOp(out, location, it, "get_by_id_direct"); > out.printf("%s, %s, %s", registerName(r0).data(), registerName(r1).data(), idName(id0, identifier(id0)).data()); > it += 2; // Increment up to the value profiler. >- printGetByIdCacheStatus(out, location, stubInfos); >+ printGetByIdCacheStatus(out, location, statusMap); > dumpValueProfiling(out, it, hasPrintedProfiling); > break; > } >@@ -1104,7 +1104,7 @@ void BytecodeDumper<Block>::dumpBytecode > case op_get_by_id_unset: > case op_get_array_length: { > printGetByIdOp(out, location, it); >- printGetByIdCacheStatus(out, location, stubInfos); >+ printGetByIdCacheStatus(out, location, statusMap); > dumpValueProfiling(out, it, hasPrintedProfiling); > break; > } >@@ -1130,7 +1130,7 @@ void BytecodeDumper<Block>::dumpBytecode > } > case op_put_by_id: { > printPutByIdOp(out, location, it, "put_by_id"); >- printPutByIdCacheStatus(out, location, stubInfos); >+ printPutByIdCacheStatus(out, location, statusMap); > break; > } > case op_put_by_id_with_this: { >@@ -1476,15 +1476,15 @@ void BytecodeDumper<Block>::dumpBytecode > break; > } > case op_call: { >- printCallOp(out, location, it, "call", DumpCaches, hasPrintedProfiling, callLinkInfos); >+ printCallOp(out, location, it, "call", DumpCaches, hasPrintedProfiling, statusMap); > break; > } > case op_tail_call: { >- printCallOp(out, location, it, "tail_call", DumpCaches, hasPrintedProfiling, callLinkInfos); >+ printCallOp(out, location, it, "tail_call", DumpCaches, hasPrintedProfiling, statusMap); > break; > } > case op_call_eval: { >- printCallOp(out, location, it, "call_eval", DontDumpCaches, hasPrintedProfiling, callLinkInfos); >+ printCallOp(out, location, it, "call_eval", DontDumpCaches, hasPrintedProfiling, statusMap); > break; > } > >@@ -1523,7 +1523,7 @@ void BytecodeDumper<Block>::dumpBytecode > break; > } > case op_construct: { >- printCallOp(out, location, it, "construct", DumpCaches, hasPrintedProfiling, callLinkInfos); >+ printCallOp(out, location, it, "construct", DumpCaches, hasPrintedProfiling, statusMap); > break; > } > case op_strcat: { >@@ -1778,10 +1778,10 @@ void BytecodeDumper<Block>::dumpBytecode > } > > template<class Block> >-void BytecodeDumper<Block>::dumpBytecode(Block* block, PrintStream& out, const typename Block::Instruction* begin, const typename Block::Instruction*& it, const StubInfoMap& stubInfos, const CallLinkInfoMap& callLinkInfos) >+void BytecodeDumper<Block>::dumpBytecode(Block* block, PrintStream& out, const typename Block::Instruction* begin, const typename Block::Instruction*& it, const ICStatusMap& statusMap) > { > BytecodeDumper dumper(block, begin); >- dumper.dumpBytecode(out, begin, it, stubInfos, callLinkInfos); >+ dumper.dumpBytecode(out, begin, it, statusMap); > } > > template<class Block> >@@ -1890,7 +1890,7 @@ void BytecodeDumper<Block>::dumpStringSw > } > > template<class Block> >-void BytecodeDumper<Block>::dumpBlock(Block* block, const typename Block::UnpackedInstructions& instructions, PrintStream& out, const StubInfoMap& stubInfos, const CallLinkInfoMap& callLinkInfos) >+void BytecodeDumper<Block>::dumpBlock(Block* block, const typename Block::UnpackedInstructions& instructions, PrintStream& out, const ICStatusMap& statusMap) > { > size_t instructionCount = 0; > >@@ -1910,7 +1910,7 @@ void BytecodeDumper<Block>::dumpBlock(Bl > const auto* end = instructions.end(); > BytecodeDumper<Block> dumper(block, begin); > for (const auto* it = begin; it != end; ++it) >- dumper.dumpBytecode(out, begin, it, stubInfos, callLinkInfos); >+ dumper.dumpBytecode(out, begin, it, statusMap); > > dumper.dumpIdentifiers(out); > dumper.dumpConstants(out); >Index: Source/JavaScriptCore/bytecode/BytecodeDumper.h >=================================================================== >--- Source/JavaScriptCore/bytecode/BytecodeDumper.h (revision 232441) >+++ Source/JavaScriptCore/bytecode/BytecodeDumper.h (working copy) >@@ -1,5 +1,6 @@ > /* > * Copyright (C) 2017 Yusuke Suzuki <utatane.tea@gmail.com> >+ * Copyright (C) 2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -26,6 +27,7 @@ > #pragma once > > #include "CallLinkInfo.h" >+#include "ICStatusMap.h" > #include "StructureStubInfo.h" > > namespace JSC { >@@ -37,8 +39,8 @@ class BytecodeDumper { > public: > typedef typename Block::Instruction Instruction; > >- static void dumpBytecode(Block*, PrintStream& out, const Instruction* begin, const Instruction*& it, const StubInfoMap& = StubInfoMap(), const CallLinkInfoMap& = CallLinkInfoMap()); >- static void dumpBlock(Block*, const typename Block::UnpackedInstructions&, PrintStream& out, const StubInfoMap& = StubInfoMap(), const CallLinkInfoMap& = CallLinkInfoMap()); >+ static void dumpBytecode(Block*, PrintStream& out, const Instruction* begin, const Instruction*& it, const ICStatusMap& statusMap = ICStatusMap()); >+ static void dumpBlock(Block*, const typename Block::UnpackedInstructions&, PrintStream& out, const ICStatusMap& statusMap = ICStatusMap()); > > private: > BytecodeDumper(Block* block, const Instruction* instructionsBegin) >@@ -69,14 +71,14 @@ private: > void printConditionalJump(PrintStream& out, const Instruction*, const Instruction*& it, int location, const char* op); > void printCompareJump(PrintStream& out, const Instruction*, const Instruction*& it, int location, const char* op); > void printGetByIdOp(PrintStream& out, int location, const Instruction*& it); >- void printGetByIdCacheStatus(PrintStream& out, int location, const StubInfoMap&); >- void printPutByIdCacheStatus(PrintStream& out, int location, const StubInfoMap&); >- void printInByIdCacheStatus(PrintStream& out, int location, const StubInfoMap&); >+ void printGetByIdCacheStatus(PrintStream& out, int location, const ICStatusMap&); >+ void printPutByIdCacheStatus(PrintStream& out, int location, const ICStatusMap&); >+ void printInByIdCacheStatus(PrintStream& out, int location, const ICStatusMap&); > enum CacheDumpMode { DumpCaches, DontDumpCaches }; >- void printCallOp(PrintStream& out, int location, const Instruction*& it, const char* op, CacheDumpMode, bool& hasPrintedProfiling, const CallLinkInfoMap&); >+ void printCallOp(PrintStream& out, int location, const Instruction*& it, const char* op, CacheDumpMode, bool& hasPrintedProfiling, const ICStatusMap&); > void printPutByIdOp(PrintStream& out, int location, const Instruction*& it, const char* op); > void printLocationOpAndRegisterOperand(PrintStream& out, int location, const Instruction*& it, const char* op, int operand); >- void dumpBytecode(PrintStream& out, const Instruction* begin, const Instruction*& it, const StubInfoMap&, const CallLinkInfoMap&); >+ void dumpBytecode(PrintStream& out, const Instruction* begin, const Instruction*& it, const ICStatusMap&); > > void dumpValueProfiling(PrintStream&, const Instruction*&, bool& hasPrintedProfiling); > void dumpArrayProfiling(PrintStream&, const Instruction*&, bool& hasPrintedProfiling); >@@ -85,7 +87,7 @@ private: > void* actualPointerFor(Special::Pointer) const; > > #if ENABLE(JIT) >- void dumpCallLinkStatus(PrintStream&, unsigned location, const CallLinkInfoMap&); >+ void dumpCallLinkStatus(PrintStream&, unsigned location, const ICStatusMap&); > #endif > > Block* m_block; >Index: Source/JavaScriptCore/bytecode/CallLinkInfo.h >=================================================================== >--- Source/JavaScriptCore/bytecode/CallLinkInfo.h (revision 232441) >+++ Source/JavaScriptCore/bytecode/CallLinkInfo.h (working copy) >@@ -352,12 +352,6 @@ inline CodeOrigin getCallLinkInfoCodeOri > return callLinkInfo.codeOrigin(); > } > >-typedef HashMap<CodeOrigin, CallLinkInfo*, CodeOriginApproximateHash> CallLinkInfoMap; >- >-#else // ENABLE(JIT) >- >-typedef HashMap<int, void*> CallLinkInfoMap; >- > #endif // ENABLE(JIT) > > } // namespace JSC >Index: Source/JavaScriptCore/bytecode/CallLinkStatus.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/CallLinkStatus.cpp (revision 232441) >+++ Source/JavaScriptCore/bytecode/CallLinkStatus.cpp (working copy) >@@ -77,7 +77,8 @@ CallLinkStatus CallLinkStatus::computeFr > } > > CallLinkStatus CallLinkStatus::computeFor( >- CodeBlock* profiledBlock, unsigned bytecodeIndex, const CallLinkInfoMap& map) >+ CodeBlock* profiledBlock, unsigned bytecodeIndex, const ICStatusMap& map, >+ ExitSiteData exitSiteData) > { > ConcurrentJSLocker locker(profiledBlock->m_lock); > >@@ -85,9 +86,7 @@ CallLinkStatus CallLinkStatus::computeFo > UNUSED_PARAM(bytecodeIndex); > UNUSED_PARAM(map); > #if ENABLE(DFG_JIT) >- ExitSiteData exitSiteData = computeExitSiteData(profiledBlock, bytecodeIndex); >- >- CallLinkInfo* callLinkInfo = map.get(CodeOrigin(bytecodeIndex)); >+ CallLinkInfo* callLinkInfo = map.get(CodeOrigin(bytecodeIndex)).callLinkInfo; > if (!callLinkInfo) { > if (exitSiteData.takesSlowPath) > return takesSlowPath(); >@@ -100,6 +99,12 @@ CallLinkStatus CallLinkStatus::computeFo > #endif > } > >+CallLinkStatus CallLinkStatus::computeFor( >+ CodeBlock* profiledBlock, unsigned bytecodeIndex, const ICStatusMap& map) >+{ >+ return computeFor(profiledBlock, bytecodeIndex, map, computeExitSiteData(profiledBlock, bytecodeIndex)); >+} >+ > CallLinkStatus::ExitSiteData CallLinkStatus::computeExitSiteData(CodeBlock* profiledBlock, unsigned bytecodeIndex) > { > ExitSiteData exitSiteData; >@@ -107,11 +112,21 @@ CallLinkStatus::ExitSiteData CallLinkSta > UnlinkedCodeBlock* codeBlock = profiledBlock->unlinkedCodeBlock(); > ConcurrentJSLocker locker(codeBlock->m_lock); > >- exitSiteData.takesSlowPath = >- codeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadType)) >- || codeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadExecutable)); >- exitSiteData.badFunction = >- codeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCell)); >+ auto takesSlowPath = [&] (ExitingInlineKind inlineKind) -> ExitFlag { >+ return ExitFlag( >+ codeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadType, ExitFromAnything, inlineKind)) >+ || codeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadExecutable, ExitFromAnything, inlineKind)), >+ inlineKind); >+ }; >+ >+ auto badFunction = [&] (ExitingInlineKind inlineKind) -> ExitFlag { >+ return ExitFlag(codeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCell, ExitFromAnything, inlineKind)), inlineKind); >+ }; >+ >+ exitSiteData.takesSlowPath |= takesSlowPath(ExitFromNotInlined); >+ exitSiteData.takesSlowPath |= takesSlowPath(ExitFromInlined); >+ exitSiteData.badFunction |= badFunction(ExitFromNotInlined); >+ exitSiteData.badFunction |= badFunction(ExitFromInlined); > #else > UNUSED_PARAM(profiledBlock); > UNUSED_PARAM(bytecodeIndex); >@@ -135,6 +150,10 @@ CallLinkStatus CallLinkStatus::computeFo > CallLinkStatus CallLinkStatus::computeFromCallLinkInfo( > const ConcurrentJSLocker&, CallLinkInfo& callLinkInfo) > { >+ // We cannot tell you anything about direct calls. >+ if (callLinkInfo.isDirect()) >+ return CallLinkStatus(); >+ > if (callLinkInfo.clearedByGC()) > return takesSlowPath(); > >@@ -158,6 +177,19 @@ CallLinkStatus CallLinkStatus::computeFr > if (PolymorphicCallStubRoutine* stub = callLinkInfo.stub()) { > WTF::loadLoadFence(); > >+ if (!stub->hasEdges()) { >+ // This means we have an FTL profile, which has incomplete information. >+ // >+ // It's not clear if takesSlowPath() or CallLinkStatus() are appropriate here, but I >+ // think that takesSlowPath() is a narrow winner. >+ // >+ // Either way, this is telling us that the FTL had been led to believe that it's >+ // profitable not to inline anything. >+ // >+ // >+ return takesSlowPath(); >+ } >+ > CallEdgeList edges = stub->edges(); > > // Now that we've loaded the edges list, there are no further concurrency concerns. We will >@@ -227,83 +259,122 @@ CallLinkStatus CallLinkStatus::computeFr > > CallLinkStatus CallLinkStatus::computeFor( > const ConcurrentJSLocker& locker, CodeBlock* profiledBlock, CallLinkInfo& callLinkInfo, >- ExitSiteData exitSiteData) >+ ExitSiteData exitSiteData, ExitingInlineKind inlineKind) > { > CallLinkStatus result = computeFor(locker, profiledBlock, callLinkInfo); >- if (exitSiteData.badFunction) { >- if (result.isBasedOnStub()) { >+ result.accountForExits(exitSiteData, inlineKind); >+ return result; >+} >+#endif >+ >+void CallLinkStatus::accountForExits(ExitSiteData exitSiteData, ExitingInlineKind inlineKind) >+{ >+ if (exitSiteData.badFunction.isSet(inlineKind)) { >+ if (isBasedOnStub()) { > // If we have a polymorphic stub, then having an exit site is not quite so useful. In > // most cases, the information in the stub has higher fidelity. >- result.makeClosureCall(); >+ makeClosureCall(); > } else { > // We might not have a polymorphic stub for any number of reasons. When this happens, we > // are in less certain territory, so exit sites mean a lot. >- result.m_couldTakeSlowPath = true; >+ m_couldTakeSlowPath = true; > } > } >- if (exitSiteData.takesSlowPath) >- result.m_couldTakeSlowPath = true; > >- return result; >+ if (exitSiteData.takesSlowPath.isSet(inlineKind)) >+ m_couldTakeSlowPath = true; > } >-#endif > >-void CallLinkStatus::computeDFGStatuses( >- CodeBlock* dfgCodeBlock, CallLinkStatus::ContextMap& map) >+CallLinkStatus CallLinkStatus::computeFor( >+ CodeBlock* profiledBlock, CodeOrigin codeOrigin, >+ const ICStatusMap& baselineMap, const ICStatusContextStack& optimizedStack) > { >-#if ENABLE(DFG_JIT) >- RELEASE_ASSERT(dfgCodeBlock->jitType() == JITCode::DFGJIT); >- CodeBlock* baselineCodeBlock = dfgCodeBlock->alternative(); >- for (auto iter = dfgCodeBlock->callLinkInfosBegin(); !!iter; ++iter) { >- CallLinkInfo& info = **iter; >- if (info.isDirect()) { >- // If the DFG was able to get a direct call then probably so will we. However, there is >- // a remote chance that it's bad news to lose information about what the DFG did. We'd >- // ideally like to just know that the DFG had emitted a DirectCall. >- continue; >- } >- CodeOrigin codeOrigin = info.codeOrigin(); >- >- // Check if we had already previously made a terrible mistake in the FTL for this >- // code origin. Note that this is approximate because we could have a monovariant >- // inline in the FTL that ended up failing. We should fix that at some point by >- // having data structures to track the context of frequent exits. This is currently >- // challenging because it would require creating a CodeOrigin-based database in >- // baseline CodeBlocks, but those CodeBlocks don't really have a place to put the >- // InlineCallFrames. >- CodeBlock* currentBaseline = >- baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, baselineCodeBlock); >- ExitSiteData exitSiteData = computeExitSiteData(currentBaseline, codeOrigin.bytecodeIndex); >- >- { >- ConcurrentJSLocker locker(dfgCodeBlock->m_lock); >- map.add(info.codeOrigin(), computeFor(locker, dfgCodeBlock, info, exitSiteData)); >- } >+ if (CallLinkStatusInternal::verbose) >+ dataLog("Figuring out call profiling for ", codeOrigin, "\n"); >+ ExitSiteData exitSiteData = computeExitSiteData(profiledBlock, codeOrigin.bytecodeIndex); >+ if (CallLinkStatusInternal::verbose) { >+ dataLog("takesSlowPath = ", exitSiteData.takesSlowPath, "\n"); >+ dataLog("badFunction = ", exitSiteData.badFunction, "\n"); > } >-#else >- UNUSED_PARAM(dfgCodeBlock); >-#endif // ENABLE(DFG_JIT) > >- if (CallLinkStatusInternal::verbose) { >- dataLog("Context map:\n"); >- ContextMap::iterator iter = map.begin(); >- ContextMap::iterator end = map.end(); >- for (; iter != end; ++iter) { >- dataLog(" ", iter->key, ":\n"); >- dataLog(" ", iter->value, "\n"); >+ for (const ICStatusContext* context : optimizedStack) { >+ if (CallLinkStatusInternal::verbose) >+ dataLog("Examining status in ", pointerDump(context->optimizedCodeBlock), "\n"); >+ ICStatus status = context->get(codeOrigin); >+ >+ // If we have both a CallLinkStatus and a callLinkInfo for the same origin, then it means one >+ // of two things: >+ // >+ // 1) We initially thought that we'd be able to inline this call so we recorded a status but >+ // then we realized that it was pointless and gave up and emitted a normal call anyway. >+ // >+ // 2) We did a polymorphic call inline that had a slow path case. >+ // >+ // In the first case, it's essential that we use the callLinkInfo, since the status may be >+ // polymorphic but the link info benefits from polyvariant profiling. >+ // >+ // In the second case, it's essential that we use the status, since the callLinkInfo >+ // corresponds to the slow case. >+ // >+ // It would be annoying to distinguish those two cases. However, we know that: >+ // >+ // If the first case happens in the FTL, then it means that even with polyvariant profiling, >+ // we failed to do anything useful. That suggests that in the FTL, it's OK to prioritize the >+ // status. That status will again tell us to not do anything useful. >+ // >+ // The second case only happens in the FTL. >+ // >+ // Therefore, we prefer the status in the FTL and the info in the DFG. >+ // >+ // Luckily, this case doesn't matter for the other ICStatuses, since they never do the >+ // fast-path-slow-path control-flow-diamond style of IC inlining. It's either all fast path >+ // or it's a full IC. So, for them, if there is an IC status then it means case (1). >+ >+ bool checkStatusFirst = context->optimizedCodeBlock->jitType() == JITCode::FTLJIT; >+ >+ auto checkInfo = [&] () -> CallLinkStatus { >+ if (!status.callLinkInfo) >+ return CallLinkStatus(); >+ >+ if (CallLinkStatusInternal::verbose) >+ dataLog("Have CallLinkInfo with CodeOrigin = ", status.callLinkInfo->codeOrigin(), "\n"); >+ ConcurrentJSLocker locker(context->optimizedCodeBlock->m_lock); >+ CallLinkStatus result = computeFor( >+ locker, context->optimizedCodeBlock, *status.callLinkInfo, exitSiteData, >+ codeOrigin.exitingInlineKind()); >+ if (CallLinkStatusInternal::verbose) >+ dataLog("Got result: ", result, "\n"); >+ return result; >+ }; >+ >+ auto checkStatus = [&] () -> CallLinkStatus { >+ if (!status.callStatus) >+ return CallLinkStatus(); >+ CallLinkStatus result = *status.callStatus; >+ if (CallLinkStatusInternal::verbose) >+ dataLog("Have callStatus: ", result, "\n"); >+ result.accountForExits(exitSiteData, codeOrigin.exitingInlineKind()); >+ return result; >+ }; >+ >+ if (checkStatusFirst) { >+ if (CallLinkStatus result = checkStatus()) >+ return result; >+ if (CallLinkStatus result = checkInfo()) >+ return result; >+ continue; > } >+ >+ if (CallLinkStatus result = checkInfo()) >+ return result; >+ if (CallLinkStatus result = checkStatus()) >+ return result; > } >-} >- >-CallLinkStatus CallLinkStatus::computeFor( >- CodeBlock* profiledBlock, CodeOrigin codeOrigin, >- const CallLinkInfoMap& baselineMap, const CallLinkStatus::ContextMap& dfgMap) >-{ >- auto iter = dfgMap.find(codeOrigin); >- if (iter != dfgMap.end()) >- return iter->value; > >- return computeFor(profiledBlock, codeOrigin.bytecodeIndex, baselineMap); >+ CallLinkStatus result = computeFor(profiledBlock, codeOrigin.bytecodeIndex, baselineMap, exitSiteData); >+ if (CallLinkStatusInternal::verbose) >+ dataLog("Computed from baseline: ", result, "\n"); >+ return result; > } > > void CallLinkStatus::setProvenConstantCallee(CallVariant variant) >@@ -327,6 +398,24 @@ void CallLinkStatus::makeClosureCall() > m_variants = despecifiedVariantList(m_variants); > } > >+bool CallLinkStatus::finalize() >+{ >+ for (CallVariant& variant : m_variants) { >+ if (!variant.finalize()) >+ return false; >+ } >+ return true; >+} >+ >+void CallLinkStatus::filter(VM& vm, JSValue value) >+{ >+ m_variants.removeAllMatching( >+ [&] (CallVariant& variant) -> bool { >+ variant.filter(vm, value); >+ return !variant; >+ }); >+} >+ > void CallLinkStatus::dump(PrintStream& out) const > { > if (!isSet()) { >Index: Source/JavaScriptCore/bytecode/CallLinkStatus.h >=================================================================== >--- Source/JavaScriptCore/bytecode/CallLinkStatus.h (revision 232441) >+++ Source/JavaScriptCore/bytecode/CallLinkStatus.h (working copy) >@@ -29,6 +29,8 @@ > #include "CallVariant.h" > #include "CodeOrigin.h" > #include "ConcurrentJSLock.h" >+#include "ExitFlag.h" >+#include "ICStatusMap.h" > #include "JSCJSValue.h" > > namespace JSC { >@@ -60,39 +62,33 @@ public: > { > } > >- static CallLinkStatus computeFor( >- CodeBlock*, unsigned bytecodeIndex, const CallLinkInfoMap&); >- > struct ExitSiteData { >- bool takesSlowPath { false }; >- bool badFunction { false }; >+ ExitFlag takesSlowPath; >+ ExitFlag badFunction; > }; > static ExitSiteData computeExitSiteData(CodeBlock*, unsigned bytecodeIndex); > >+ static CallLinkStatus computeFor(CodeBlock*, unsigned bytecodeIndex, const ICStatusMap&, ExitSiteData); >+ static CallLinkStatus computeFor(CodeBlock*, unsigned bytecodeIndex, const ICStatusMap&); >+ > #if ENABLE(JIT) > // Computes the status assuming that we never took slow path and never previously > // exited. > static CallLinkStatus computeFor(const ConcurrentJSLocker&, CodeBlock*, CallLinkInfo&); >+ >+ // Computes the status accounting for exits. > static CallLinkStatus computeFor( >- const ConcurrentJSLocker&, CodeBlock*, CallLinkInfo&, ExitSiteData); >+ const ConcurrentJSLocker&, CodeBlock*, CallLinkInfo&, ExitSiteData, ExitingInlineKind = ExitFromAnyInlineKind); > #endif > >- typedef HashMap<CodeOrigin, CallLinkStatus, CodeOriginApproximateHash> ContextMap; >- >- // Computes all of the statuses of the DFG code block. Doesn't include statuses that had >- // no information. Currently we use this when compiling FTL code, to enable polyvariant >- // inlining. >- static void computeDFGStatuses(CodeBlock* dfgCodeBlock, ContextMap&); >- >- // Helper that first consults the ContextMap and then does computeFor(). > static CallLinkStatus computeFor( >- CodeBlock*, CodeOrigin, const CallLinkInfoMap&, const ContextMap&); >+ CodeBlock*, CodeOrigin, const ICStatusMap&, const ICStatusContextStack&); > > void setProvenConstantCallee(CallVariant); > > bool isSet() const { return !m_variants.isEmpty() || m_couldTakeSlowPath; } > >- bool operator!() const { return !isSet(); } >+ explicit operator bool() const { return isSet(); } > > bool couldTakeSlowPath() const { return m_couldTakeSlowPath; } > >@@ -110,6 +106,10 @@ public: > > unsigned maxNumArguments() const { return m_maxNumArguments; } > >+ bool finalize(); >+ >+ void filter(VM&, JSValue); >+ > void dump(PrintStream&) const; > > private: >@@ -121,6 +121,8 @@ private: > const ConcurrentJSLocker&, CallLinkInfo&); > #endif > >+ void accountForExits(ExitSiteData, ExitingInlineKind); >+ > CallVariantList m_variants; > bool m_couldTakeSlowPath { false }; > bool m_isProved { false }; >Index: Source/JavaScriptCore/bytecode/CallVariant.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/CallVariant.cpp (revision 232441) >+++ Source/JavaScriptCore/bytecode/CallVariant.cpp (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2014, 2015 Apple Inc. All rights reserved. >+ * Copyright (C) 2014-2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -31,6 +31,35 @@ > > namespace JSC { > >+bool CallVariant::finalize() >+{ >+ if (m_callee && !Heap::isMarked(m_callee)) >+ return false; >+ return true; >+} >+ >+void CallVariant::filter(VM& vm, JSValue value) >+{ >+ if (!*this) >+ return; >+ >+ if (!isClosureCall()) { >+ if (nonExecutableCallee() != value) >+ *this = CallVariant(); >+ return; >+ } >+ >+ if (JSFunction* function = jsDynamicCast<JSFunction*>(vm, value)) { >+ if (function->executable() == executable()) >+ *this = CallVariant(function); >+ else >+ *this = CallVariant(); >+ return; >+ } >+ >+ *this = CallVariant(); >+} >+ > void CallVariant::dump(PrintStream& out) const > { > if (!*this) { >Index: Source/JavaScriptCore/bytecode/CallVariant.h >=================================================================== >--- Source/JavaScriptCore/bytecode/CallVariant.h (revision 232441) >+++ Source/JavaScriptCore/bytecode/CallVariant.h (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2014, 2015 Apple Inc. All rights reserved. >+ * Copyright (C) 2014-2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -71,7 +71,7 @@ public: > { > } > >- bool operator!() const { return !m_callee; } >+ explicit operator bool() const { return !!m_callee; } > > // If this variant refers to a function, change it to refer to its executable. > ALWAYS_INLINE CallVariant despecifiedClosure() const >@@ -136,6 +136,10 @@ public: > return nullptr; > } > >+ bool finalize(); >+ >+ void filter(VM&, JSValue); >+ > void dump(PrintStream& out) const; > > bool isHashTableDeletedValue() const >Index: Source/JavaScriptCore/bytecode/CodeBlock.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/CodeBlock.cpp (revision 232441) >+++ Source/JavaScriptCore/bytecode/CodeBlock.cpp (working copy) >@@ -238,24 +238,20 @@ void CodeBlock::dumpBytecode() > > void CodeBlock::dumpBytecode(PrintStream& out) > { >- StubInfoMap stubInfos; >- CallLinkInfoMap callLinkInfos; >- getStubInfoMap(stubInfos); >- getCallLinkInfoMap(callLinkInfos); >- BytecodeDumper<CodeBlock>::dumpBlock(this, instructions(), out, stubInfos, callLinkInfos); >+ ICStatusMap statusMap; >+ getICStatusMap(statusMap); >+ BytecodeDumper<CodeBlock>::dumpBlock(this, instructions(), out, statusMap); > } > >-void CodeBlock::dumpBytecode(PrintStream& out, const Instruction* begin, const Instruction*& it, const StubInfoMap& stubInfos, const CallLinkInfoMap& callLinkInfos) >+void CodeBlock::dumpBytecode(PrintStream& out, const Instruction* begin, const Instruction*& it, const ICStatusMap& statusMap) > { >- BytecodeDumper<CodeBlock>::dumpBytecode(this, out, begin, it, stubInfos, callLinkInfos); >+ BytecodeDumper<CodeBlock>::dumpBytecode(this, out, begin, it, statusMap); > } > >-void CodeBlock::dumpBytecode( >- PrintStream& out, unsigned bytecodeOffset, >- const StubInfoMap& stubInfos, const CallLinkInfoMap& callLinkInfos) >+void CodeBlock::dumpBytecode(PrintStream& out, unsigned bytecodeOffset, const ICStatusMap& statusMap) > { > const Instruction* it = &instructions()[bytecodeOffset]; >- dumpBytecode(out, instructions().begin(), it, stubInfos, callLinkInfos); >+ dumpBytecode(out, instructions().begin(), it, statusMap); > } > > #define FOR_EACH_MEMBER_VECTOR(macro) \ >@@ -1166,6 +1162,9 @@ void CodeBlock::propagateTransitions(con > #if ENABLE(DFG_JIT) > if (JITCode::isOptimizingJIT(jitType())) { > DFG::CommonData* dfgCommon = m_jitCode->dfgCommon(); >+ >+ dfgCommon->recordedStatuses.markIfCheap(visitor); >+ > for (auto& weakReference : dfgCommon->weakStructureReferences) > weakReference->markIfCheap(visitor); > >@@ -1416,57 +1415,45 @@ void CodeBlock::finalizeUnconditionally( > finalizeBaselineJITInlineCaches(); > #endif > >- VM::SpaceAndFinalizerSet::finalizerSetFor(*subspace()).remove(this); >-} >- >-void CodeBlock::getStubInfoMap(const ConcurrentJSLocker&, StubInfoMap& result) >-{ >-#if ENABLE(JIT) >- if (JITCode::isJIT(jitType())) >- toHashMap(m_stubInfos, getStructureStubInfoCodeOrigin, result); >-#else >- UNUSED_PARAM(result); >-#endif >-} >- >-void CodeBlock::getStubInfoMap(StubInfoMap& result) >-{ >- ConcurrentJSLocker locker(m_lock); >- getStubInfoMap(locker, result); >-} >- >-void CodeBlock::getCallLinkInfoMap(const ConcurrentJSLocker&, CallLinkInfoMap& result) >-{ >-#if ENABLE(JIT) >- if (JITCode::isJIT(jitType())) >- toHashMap(m_callLinkInfos, getCallLinkInfoCodeOrigin, result); >-#else >- UNUSED_PARAM(result); >-#endif >-} >+ if (JITCode::isOptimizingJIT(jitType())) { >+ DFG::CommonData* dfgCommon = m_jitCode->dfgCommon(); >+ dfgCommon->recordedStatuses.finalize(); >+ } > >-void CodeBlock::getCallLinkInfoMap(CallLinkInfoMap& result) >-{ >- ConcurrentJSLocker locker(m_lock); >- getCallLinkInfoMap(locker, result); >+ VM::SpaceAndFinalizerSet::finalizerSetFor(*subspace()).remove(this); > } > >-void CodeBlock::getByValInfoMap(const ConcurrentJSLocker&, ByValInfoMap& result) >+void CodeBlock::getICStatusMap(const ConcurrentJSLocker&, ICStatusMap& result) > { > #if ENABLE(JIT) > if (JITCode::isJIT(jitType())) { >- for (auto* byValInfo : m_byValInfos) >- result.add(CodeOrigin(byValInfo->bytecodeIndex), byValInfo); >+ for (StructureStubInfo* stubInfo : m_stubInfos) >+ result.add(stubInfo->codeOrigin, ICStatus()).iterator->value.stubInfo = stubInfo; >+ for (CallLinkInfo* callLinkInfo : m_callLinkInfos) >+ result.add(callLinkInfo->codeOrigin(), ICStatus()).iterator->value.callLinkInfo = callLinkInfo; >+ for (ByValInfo* byValInfo : m_byValInfos) >+ result.add(CodeOrigin(byValInfo->bytecodeIndex), ICStatus()).iterator->value.byValInfo = byValInfo; >+ if (JITCode::isOptimizingJIT(jitType())) { >+ DFG::CommonData* dfgCommon = m_jitCode->dfgCommon(); >+ for (auto& pair : dfgCommon->recordedStatuses.calls) >+ result.add(pair.first, ICStatus()).iterator->value.callStatus = pair.second.get(); >+ for (auto& pair : dfgCommon->recordedStatuses.gets) >+ result.add(pair.first, ICStatus()).iterator->value.getStatus = pair.second.get(); >+ for (auto& pair : dfgCommon->recordedStatuses.puts) >+ result.add(pair.first, ICStatus()).iterator->value.putStatus = pair.second.get(); >+ for (auto& pair : dfgCommon->recordedStatuses.ins) >+ result.add(pair.first, ICStatus()).iterator->value.inStatus = pair.second.get(); >+ } > } > #else > UNUSED_PARAM(result); > #endif > } > >-void CodeBlock::getByValInfoMap(ByValInfoMap& result) >+void CodeBlock::getICStatusMap(ICStatusMap& result) > { > ConcurrentJSLocker locker(m_lock); >- getByValInfoMap(locker, result); >+ getICStatusMap(locker, result); > } > > #if ENABLE(JIT) >@@ -1533,7 +1520,7 @@ void CodeBlock::resetJITData() > > // We can clear these because no other thread will have references to any stub infos, call > // link infos, or by val infos if we don't have JIT code. Attempts to query these data >- // structures using the concurrent API (getStubInfoMap and friends) will return nothing if we >+ // structures using the concurrent API (getICStatusMap and friends) will return nothing if we > // don't have JIT code. > m_stubInfos.clear(); > m_callLinkInfos.clear(); >Index: Source/JavaScriptCore/bytecode/CodeBlock.h >=================================================================== >--- Source/JavaScriptCore/bytecode/CodeBlock.h (revision 232441) >+++ Source/JavaScriptCore/bytecode/CodeBlock.h (working copy) >@@ -45,6 +45,7 @@ > #include "ExpressionRangeInfo.h" > #include "FunctionExecutable.h" > #include "HandlerInfo.h" >+#include "ICStatusMap.h" > #include "Instruction.h" > #include "JITCode.h" > #include "JITCodeMap.h" >@@ -96,8 +97,6 @@ enum class AccessType : int8_t; > > struct ArithProfile; > >-typedef HashMap<CodeOrigin, StructureStubInfo*, CodeOriginApproximateHash> StubInfoMap; >- > enum ReoptimizationMode { DontCountReoptimization, CountReoptimization }; > > class CodeBlock : public JSCell { >@@ -196,8 +195,8 @@ public: > > void dumpBytecode(); > void dumpBytecode(PrintStream&); >- void dumpBytecode(PrintStream& out, const Instruction* begin, const Instruction*& it, const StubInfoMap& = StubInfoMap(), const CallLinkInfoMap& = CallLinkInfoMap()); >- void dumpBytecode(PrintStream& out, unsigned bytecodeOffset, const StubInfoMap& = StubInfoMap(), const CallLinkInfoMap& = CallLinkInfoMap()); >+ void dumpBytecode(PrintStream& out, const Instruction* begin, const Instruction*& it, const ICStatusMap& = ICStatusMap()); >+ void dumpBytecode(PrintStream& out, unsigned bytecodeOffset, const ICStatusMap& = ICStatusMap()); > > void dumpExceptionHandlers(PrintStream&); > void printStructures(PrintStream&, const Instruction*); >@@ -237,14 +236,8 @@ public: > > std::optional<unsigned> bytecodeOffsetFromCallSiteIndex(CallSiteIndex); > >- void getStubInfoMap(const ConcurrentJSLocker&, StubInfoMap& result); >- void getStubInfoMap(StubInfoMap& result); >- >- void getCallLinkInfoMap(const ConcurrentJSLocker&, CallLinkInfoMap& result); >- void getCallLinkInfoMap(CallLinkInfoMap& result); >- >- void getByValInfoMap(const ConcurrentJSLocker&, ByValInfoMap& result); >- void getByValInfoMap(ByValInfoMap& result); >+ void getICStatusMap(const ConcurrentJSLocker&, ICStatusMap& result); >+ void getICStatusMap(ICStatusMap& result); > > #if ENABLE(JIT) > JITAddIC* addJITAddIC(ArithProfile*, Instruction*); >Index: Source/JavaScriptCore/bytecode/CodeOrigin.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/CodeOrigin.cpp (revision 232441) >+++ Source/JavaScriptCore/bytecode/CodeOrigin.cpp (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2012-2015 Apple Inc. All rights reserved. >+ * Copyright (C) 2012-2018 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,7 +46,7 @@ unsigned CodeOrigin::inlineDepth() const > return inlineDepthForCallFrame(inlineCallFrame); > } > >-bool CodeOrigin::isApproximatelyEqualTo(const CodeOrigin& other) const >+bool CodeOrigin::isApproximatelyEqualTo(const CodeOrigin& other, InlineCallFrame* terminal) const > { > CodeOrigin a = *this; > CodeOrigin b = other; >@@ -68,10 +68,12 @@ bool CodeOrigin::isApproximatelyEqualTo( > if (a.bytecodeIndex != b.bytecodeIndex) > return false; > >- if ((!!a.inlineCallFrame) != (!!b.inlineCallFrame)) >+ bool aHasInlineCallFrame = !!a.inlineCallFrame && a.inlineCallFrame != terminal; >+ bool bHasInlineCallFrame = !!b.inlineCallFrame; >+ if (aHasInlineCallFrame != bHasInlineCallFrame) > return false; > >- if (!a.inlineCallFrame) >+ if (!aHasInlineCallFrame) > return true; > > if (a.inlineCallFrame->baselineCodeBlock.get() != b.inlineCallFrame->baselineCodeBlock.get()) >@@ -82,7 +84,7 @@ bool CodeOrigin::isApproximatelyEqualTo( > } > } > >-unsigned CodeOrigin::approximateHash() const >+unsigned CodeOrigin::approximateHash(InlineCallFrame* terminal) const > { > if (!isSet()) > return 0; >@@ -97,6 +99,9 @@ unsigned CodeOrigin::approximateHash() c > if (!codeOrigin.inlineCallFrame) > return result; > >+ if (codeOrigin.inlineCallFrame == terminal) >+ return result; >+ > result += WTF::PtrHash<JSCell*>::hash(codeOrigin.inlineCallFrame->baselineCodeBlock.get()); > > codeOrigin = codeOrigin.inlineCallFrame->directCaller; >Index: Source/JavaScriptCore/bytecode/CodeOrigin.h >=================================================================== >--- Source/JavaScriptCore/bytecode/CodeOrigin.h (revision 232441) >+++ Source/JavaScriptCore/bytecode/CodeOrigin.h (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2011-2015 Apple Inc. All rights reserved. >+ * Copyright (C) 2011-2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -26,6 +26,7 @@ > #pragma once > > #include "CodeBlockHash.h" >+#include "ExitingInlineKind.h" > #include <limits.h> > #include <wtf/HashMap.h> > #include <wtf/PrintStream.h> >@@ -88,15 +89,20 @@ struct CodeOrigin { > > static unsigned inlineDepthForCallFrame(InlineCallFrame*); > >+ ExitingInlineKind exitingInlineKind() const >+ { >+ return inlineCallFrame ? ExitFromInlined : ExitFromNotInlined; >+ } >+ > unsigned hash() const; > bool operator==(const CodeOrigin& other) const; > bool operator!=(const CodeOrigin& other) const { return !(*this == other); } > > // This checks if the two code origins correspond to the same stack trace snippets, > // but ignore whether the InlineCallFrame's are identical. >- bool isApproximatelyEqualTo(const CodeOrigin& other) const; >+ bool isApproximatelyEqualTo(const CodeOrigin& other, InlineCallFrame* terminal = nullptr) const; > >- unsigned approximateHash() const; >+ unsigned approximateHash(InlineCallFrame* terminal = nullptr) const; > > template <typename Function> > void walkUpInlineStack(const Function&); >@@ -106,7 +112,7 @@ struct CodeOrigin { > > JS_EXPORT_PRIVATE void dump(PrintStream&) const; > void dumpInContext(PrintStream&, DumpContext*) const; >- >+ > private: > static InlineCallFrame* deletedMarker() > { >Index: Source/JavaScriptCore/bytecode/DFGExitProfile.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/DFGExitProfile.cpp (revision 232441) >+++ Source/JavaScriptCore/bytecode/DFGExitProfile.cpp (working copy) >@@ -35,7 +35,7 @@ namespace JSC { namespace DFG { > > void FrequentExitSite::dump(PrintStream& out) const > { >- out.print("bc#", m_bytecodeOffset, ": ", m_kind, "/", m_jitType); >+ out.print("bc#", m_bytecodeOffset, ": ", m_kind, "/", m_jitType, "/", m_inlineKind); > } > > ExitProfile::ExitProfile() { } >@@ -43,8 +43,10 @@ ExitProfile::~ExitProfile() { } > > bool ExitProfile::add(CodeBlock* owner, const FrequentExitSite& site) > { >+ RELEASE_ASSERT(site.jitType() != ExitFromAnything); >+ RELEASE_ASSERT(site.inlineKind() != ExitFromAnyInlineKind); >+ > ConcurrentJSLocker locker(owner->unlinkedCodeBlock()->m_lock); >- ASSERT(site.jitType() != ExitFromAnything); > > CODEBLOCK_LOG_EVENT(owner, "frequentExit", (site)); > >Index: Source/JavaScriptCore/bytecode/DFGExitProfile.h >=================================================================== >--- Source/JavaScriptCore/bytecode/DFGExitProfile.h (revision 232441) >+++ Source/JavaScriptCore/bytecode/DFGExitProfile.h (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2011-2014, 2016 Apple Inc. All rights reserved. >+ * Copyright (C) 2011-2018 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 "ConcurrentJSLock.h" > #include "ExitKind.h" >+#include "ExitingInlineKind.h" > #include "ExitingJITType.h" > #include <wtf/HashSet.h> > #include <wtf/Vector.h> >@@ -41,6 +42,7 @@ public: > : m_bytecodeOffset(0) // 0 = empty value > , m_kind(ExitKindUnset) > , m_jitType(ExitFromAnything) >+ , m_inlineKind(ExitFromAnyInlineKind) > { > } > >@@ -48,13 +50,15 @@ public: > : m_bytecodeOffset(1) // 1 = deleted value > , m_kind(ExitKindUnset) > , m_jitType(ExitFromAnything) >+ , m_inlineKind(ExitFromAnyInlineKind) > { > } > >- explicit FrequentExitSite(unsigned bytecodeOffset, ExitKind kind, ExitingJITType jitType = ExitFromAnything) >+ explicit FrequentExitSite(unsigned bytecodeOffset, ExitKind kind, ExitingJITType jitType = ExitFromAnything, ExitingInlineKind inlineKind = ExitFromAnyInlineKind) > : m_bytecodeOffset(bytecodeOffset) > , m_kind(kind) > , m_jitType(jitType) >+ , m_inlineKind(inlineKind) > { > if (m_kind == ArgumentsEscaped) { > // Count this one globally. It doesn't matter where in the code block the arguments excaped; >@@ -65,10 +69,11 @@ public: > > // Use this constructor if you wish for the exit site to be counted globally within its > // code block. >- explicit FrequentExitSite(ExitKind kind, ExitingJITType jitType = ExitFromAnything) >+ explicit FrequentExitSite(ExitKind kind, ExitingJITType jitType = ExitFromAnything, ExitingInlineKind inlineKind = ExitFromAnyInlineKind) > : m_bytecodeOffset(0) > , m_kind(kind) > , m_jitType(jitType) >+ , m_inlineKind(inlineKind) > { > } > >@@ -81,7 +86,8 @@ public: > { > return m_bytecodeOffset == other.m_bytecodeOffset > && m_kind == other.m_kind >- && m_jitType == other.m_jitType; >+ && m_jitType == other.m_jitType >+ && m_inlineKind == other.m_inlineKind; > } > > bool subsumes(const FrequentExitSite& other) const >@@ -90,19 +96,24 @@ public: > return false; > if (m_kind != other.m_kind) > return false; >- if (m_jitType == ExitFromAnything) >- return true; >- return m_jitType == other.m_jitType; >+ if (m_jitType != ExitFromAnything >+ && m_jitType != other.m_jitType) >+ return false; >+ if (m_inlineKind != ExitFromAnyInlineKind >+ && m_inlineKind != other.m_inlineKind) >+ return false; >+ return true; > } > > unsigned hash() const > { >- return WTF::intHash(m_bytecodeOffset) + m_kind + static_cast<std::underlying_type_t<ExitingJITType>>(m_jitType) * 7; >+ return WTF::intHash(m_bytecodeOffset) + m_kind + static_cast<unsigned>(m_jitType) * 7 + static_cast<unsigned>(m_inlineKind) * 11; > } > > unsigned bytecodeOffset() const { return m_bytecodeOffset; } > ExitKind kind() const { return m_kind; } > ExitingJITType jitType() const { return m_jitType; } >+ ExitingInlineKind inlineKind() const { return m_inlineKind; } > > FrequentExitSite withJITType(ExitingJITType jitType) const > { >@@ -111,6 +122,13 @@ public: > return result; > } > >+ FrequentExitSite withInlineKind(ExitingInlineKind inlineKind) const >+ { >+ FrequentExitSite result = *this; >+ result.m_inlineKind = inlineKind; >+ return result; >+ } >+ > bool isHashTableDeletedValue() const > { > return m_kind == ExitKindUnset && m_bytecodeOffset; >@@ -122,6 +140,7 @@ private: > unsigned m_bytecodeOffset; > ExitKind m_kind; > ExitingJITType m_jitType; >+ ExitingInlineKind m_inlineKind; > }; > > struct FrequentExitSiteHash { >@@ -192,10 +211,10 @@ public: > bool hasExitSite(const FrequentExitSite& site) const > { > if (site.jitType() == ExitFromAnything) { >- return hasExitSite(site.withJITType(ExitFromDFG)) >- || hasExitSite(site.withJITType(ExitFromFTL)); >+ return hasExitSiteWithSpecificJITType(site.withJITType(ExitFromDFG)) >+ || hasExitSiteWithSpecificJITType(site.withJITType(ExitFromFTL)); > } >- return m_frequentExitSites.find(site) != m_frequentExitSites.end(); >+ return hasExitSiteWithSpecificJITType(site); > } > > bool hasExitSite(ExitKind kind) const >@@ -208,6 +227,20 @@ public: > return hasExitSite(FrequentExitSite(bytecodeIndex, kind)); > } > private: >+ bool hasExitSiteWithSpecificJITType(const FrequentExitSite& site) const >+ { >+ if (site.inlineKind() == ExitFromAnyInlineKind) { >+ return hasExitSiteWithSpecificInlineKind(site.withInlineKind(ExitFromNotInlined)) >+ || hasExitSiteWithSpecificInlineKind(site.withInlineKind(ExitFromInlined)); >+ } >+ return hasExitSiteWithSpecificInlineKind(site); >+ } >+ >+ bool hasExitSiteWithSpecificInlineKind(const FrequentExitSite& site) const >+ { >+ return m_frequentExitSites.find(site) != m_frequentExitSites.end(); >+ } >+ > HashSet<FrequentExitSite> m_frequentExitSites; > }; > >Index: Source/JavaScriptCore/bytecode/ExitFlag.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/ExitFlag.cpp (nonexistent) >+++ Source/JavaScriptCore/bytecode/ExitFlag.cpp (working copy) >@@ -0,0 +1,48 @@ >+/* >+ * Copyright (C) 2018 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "ExitFlag.h" >+ >+#include <wtf/CommaPrinter.h> >+ >+namespace JSC { >+ >+void ExitFlag::dump(PrintStream& out) const >+{ >+ if (!m_bits) { >+ out.print("false"); >+ return; >+ } >+ >+ CommaPrinter comma("|"); >+ if (isSet(ExitFromNotInlined)) >+ out.print(comma, "notInlined"); >+ if (isSet(ExitFromInlined)) >+ out.print(comma, "inlined"); >+} >+ >+} // namespace JSC >+ >Index: Source/JavaScriptCore/bytecode/ExitFlag.h >=================================================================== >--- Source/JavaScriptCore/bytecode/ExitFlag.h (nonexistent) >+++ Source/JavaScriptCore/bytecode/ExitFlag.h (working copy) >@@ -0,0 +1,100 @@ >+/* >+ * Copyright (C) 2018 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#include "ExitingInlineKind.h" >+ >+namespace JSC { >+ >+class ExitFlag { >+public: >+ ExitFlag() { } >+ >+ ExitFlag(bool value, ExitingInlineKind inlineKind) >+ { >+ if (!value) >+ return; >+ >+ switch (inlineKind) { >+ case ExitFromAnyInlineKind: >+ m_bits = trueNotInlined | trueInlined; >+ break; >+ case ExitFromNotInlined: >+ m_bits = trueNotInlined; >+ break; >+ case ExitFromInlined: >+ m_bits = trueInlined; >+ break; >+ } >+ } >+ >+ ExitFlag operator|(const ExitFlag& other) const >+ { >+ ExitFlag result; >+ result.m_bits = m_bits | other.m_bits; >+ return result; >+ } >+ >+ ExitFlag& operator|=(const ExitFlag& other) >+ { >+ *this = *this | other; >+ return *this; >+ } >+ >+ ExitFlag operator&(const ExitFlag& other) const >+ { >+ ExitFlag result; >+ result.m_bits = m_bits & other.m_bits; >+ return result; >+ } >+ >+ ExitFlag& operator&=(const ExitFlag& other) >+ { >+ *this = *this & other; >+ return *this; >+ } >+ >+ explicit operator bool() const >+ { >+ return !!m_bits; >+ } >+ >+ bool isSet(ExitingInlineKind inlineKind) const >+ { >+ return !!(*this & ExitFlag(true, inlineKind)); >+ } >+ >+ void dump(PrintStream&) const; >+ >+private: >+ static constexpr uint8_t trueNotInlined = 1; >+ static constexpr uint8_t trueInlined = 2; >+ >+ uint8_t m_bits { 0 }; >+}; >+ >+} // namespace JSC >+ >Index: Source/JavaScriptCore/bytecode/ExitingInlineKind.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/ExitingInlineKind.cpp (nonexistent) >+++ Source/JavaScriptCore/bytecode/ExitingInlineKind.cpp (working copy) >@@ -0,0 +1,52 @@ >+/* >+ * Copyright (C) 2018 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "ExitingInlineKind.h" >+ >+#include <wtf/PrintStream.h> >+ >+namespace WTF { >+ >+using namespace JSC; >+ >+void printInternal(PrintStream& out, ExitingInlineKind type) >+{ >+ switch (type) { >+ case ExitFromAnyInlineKind: >+ out.print("FromAnyInlineKind"); >+ return; >+ case ExitFromNotInlined: >+ out.print("FromNotInlined"); >+ return; >+ case ExitFromInlined: >+ out.print("FromInlined"); >+ return; >+ } >+ RELEASE_ASSERT_NOT_REACHED(); >+} >+ >+} // namespace WTF >+ >Index: Source/JavaScriptCore/bytecode/ExitingInlineKind.h >=================================================================== >--- Source/JavaScriptCore/bytecode/ExitingInlineKind.h (nonexistent) >+++ Source/JavaScriptCore/bytecode/ExitingInlineKind.h (working copy) >@@ -0,0 +1,46 @@ >+/* >+ * Copyright (C) 2018 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+namespace JSC { >+ >+enum ExitingInlineKind : uint8_t { >+ ExitFromAnyInlineKind, >+ ExitFromNotInlined, >+ ExitFromInlined, >+}; >+ >+} // namespace JSC >+ >+namespace WTF { >+ >+class PrintStream; >+void printInternal(PrintStream&, JSC::ExitingInlineKind); >+ >+} // namespace WTF >+ >+ >+ >Index: Source/JavaScriptCore/bytecode/GetByIdStatus.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/GetByIdStatus.cpp (revision 232441) >+++ Source/JavaScriptCore/bytecode/GetByIdStatus.cpp (working copy) >@@ -51,16 +51,6 @@ bool GetByIdStatus::appendVariant(const > return appendICStatusVariant(m_variants, variant); > } > >-#if ENABLE(DFG_JIT) >-bool GetByIdStatus::hasExitSite(CodeBlock* profiledBlock, unsigned bytecodeIndex) >-{ >- UnlinkedCodeBlock* unlinkedCodeBlock = profiledBlock->unlinkedCodeBlock(); >- ConcurrentJSLocker locker(unlinkedCodeBlock->m_lock); >- return unlinkedCodeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCache)) >- || unlinkedCodeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadConstantCache)); >-} >-#endif >- > GetByIdStatus GetByIdStatus::computeFromLLInt(CodeBlock* profiledBlock, unsigned bytecodeIndex, UniquedStringImpl* uid) > { > VM& vm = *profiledBlock->vm(); >@@ -105,7 +95,7 @@ GetByIdStatus GetByIdStatus::computeFrom > } > } > >-GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, StubInfoMap& map, unsigned bytecodeIndex, UniquedStringImpl* uid) >+GetByIdStatus GetByIdStatus::computeFor(CodeBlock* profiledBlock, ICStatusMap& map, unsigned bytecodeIndex, UniquedStringImpl* uid, ExitFlag didExit, CallLinkStatus::ExitSiteData callExitSiteData) > { > ConcurrentJSLocker locker(profiledBlock->m_lock); > >@@ -113,12 +103,11 @@ GetByIdStatus GetByIdStatus::computeFor( > > #if ENABLE(DFG_JIT) > result = computeForStubInfoWithoutExitSiteFeedback( >- locker, profiledBlock, map.get(CodeOrigin(bytecodeIndex)), uid, >- CallLinkStatus::computeExitSiteData(profiledBlock, bytecodeIndex)); >+ locker, profiledBlock, map.get(CodeOrigin(bytecodeIndex)).stubInfo, uid, >+ callExitSiteData); > >- if (!result.takesSlowPath() >- && hasExitSite(profiledBlock, bytecodeIndex)) >- return GetByIdStatus(result.makesCalls() ? MakesCalls : TakesSlowPath, true); >+ if (didExit) >+ return result.slowVersion(); > #else > UNUSED_PARAM(map); > #endif >@@ -136,8 +125,8 @@ GetByIdStatus GetByIdStatus::computeForS > locker, profiledBlock, stubInfo, uid, > CallLinkStatus::computeExitSiteData(profiledBlock, codeOrigin.bytecodeIndex)); > >- if (!result.takesSlowPath() && GetByIdStatus::hasExitSite(profiledBlock, codeOrigin.bytecodeIndex)) >- return GetByIdStatus(result.makesCalls() ? GetByIdStatus::MakesCalls : GetByIdStatus::TakesSlowPath, true); >+ if (!result.takesSlowPath() && hasBadCacheExitSite(profiledBlock, codeOrigin.bytecodeIndex)) >+ return result.slowVersion(); > return result; > } > #endif // ENABLE(DFG_JIT) >@@ -314,40 +303,35 @@ GetByIdStatus GetByIdStatus::computeForS > #endif // ENABLE(JIT) > > GetByIdStatus GetByIdStatus::computeFor( >- CodeBlock* profiledBlock, CodeBlock* dfgBlock, StubInfoMap& baselineMap, >- StubInfoMap& dfgMap, CodeOrigin codeOrigin, UniquedStringImpl* uid) >+ CodeBlock* profiledBlock, ICStatusMap& baselineMap, >+ ICStatusContextStack& icContextStack, CodeOrigin codeOrigin, UniquedStringImpl* uid) > { >-#if ENABLE(DFG_JIT) >- if (dfgBlock) { >- CallLinkStatus::ExitSiteData exitSiteData; >- { >- ConcurrentJSLocker locker(profiledBlock->m_lock); >- exitSiteData = CallLinkStatus::computeExitSiteData( >- profiledBlock, codeOrigin.bytecodeIndex); >- } >- >- GetByIdStatus result; >- { >- ConcurrentJSLocker locker(dfgBlock->m_lock); >- result = computeForStubInfoWithoutExitSiteFeedback( >- locker, dfgBlock, dfgMap.get(codeOrigin), uid, exitSiteData); >- } >- >- if (result.takesSlowPath()) >- return result; >+ CallLinkStatus::ExitSiteData callExitSiteData = >+ CallLinkStatus::computeExitSiteData(profiledBlock, codeOrigin.bytecodeIndex); >+ ExitFlag didExit = hasBadCacheExitSite(profiledBlock, codeOrigin.bytecodeIndex); > >- if (hasExitSite(profiledBlock, codeOrigin.bytecodeIndex)) >- return GetByIdStatus(TakesSlowPath, true); >+ for (ICStatusContext* context : icContextStack) { >+ ICStatus status = context->get(codeOrigin); > >- if (result.isSet()) >+ auto withExits = [&] (const GetByIdStatus& result) -> GetByIdStatus { >+ if (didExit.isSet(codeOrigin.exitingInlineKind())) >+ return result.slowVersion(); > return result; >- } >-#else >- UNUSED_PARAM(dfgBlock); >- UNUSED_PARAM(dfgMap); >-#endif >+ }; > >- return computeFor(profiledBlock, baselineMap, codeOrigin.bytecodeIndex, uid); >+ if (status.stubInfo) { >+ ConcurrentJSLocker locker(context->optimizedCodeBlock->m_lock); >+ GetByIdStatus result = computeForStubInfoWithoutExitSiteFeedback( >+ locker, context->optimizedCodeBlock, status.stubInfo, uid, callExitSiteData); >+ if (result.isSet()) >+ return withExits(result); >+ } >+ >+ if (status.getStatus) >+ return withExits(*status.getStatus); >+ } >+ >+ return computeFor(profiledBlock, baselineMap, codeOrigin.bytecodeIndex, uid, didExit, callExitSiteData); > } > > GetByIdStatus GetByIdStatus::computeFor(const StructureSet& set, UniquedStringImpl* uid) >@@ -414,6 +398,11 @@ bool GetByIdStatus::makesCalls() const > return false; > } > >+GetByIdStatus GetByIdStatus::slowVersion() const >+{ >+ return GetByIdStatus(makesCalls() ? MakesCalls : TakesSlowPath, wasSeenInJIT()); >+} >+ > void GetByIdStatus::filter(const StructureSet& set) > { > if (m_state != Simple) >@@ -423,6 +412,25 @@ void GetByIdStatus::filter(const Structu > m_state = NoInformation; > } > >+void GetByIdStatus::markIfCheap(SlotVisitor& visitor) >+{ >+ for (GetByIdVariant& variant : m_variants) >+ variant.markIfCheap(visitor); >+} >+ >+bool GetByIdStatus::finalize() >+{ >+ for (GetByIdVariant& variant : m_variants) { >+ if (!variant.finalize()) >+ return false; >+ } >+ if (m_moduleNamespaceObject && !Heap::isMarked(m_moduleNamespaceObject)) >+ return false; >+ if (m_moduleEnvironment && !Heap::isMarked(m_moduleEnvironment)) >+ return false; >+ return true; >+} >+ > void GetByIdStatus::dump(PrintStream& out) const > { > out.print("("); >Index: Source/JavaScriptCore/bytecode/GetByIdStatus.h >=================================================================== >--- Source/JavaScriptCore/bytecode/GetByIdStatus.h (revision 232441) >+++ Source/JavaScriptCore/bytecode/GetByIdStatus.h (working copy) >@@ -28,7 +28,9 @@ > #include "CallLinkStatus.h" > #include "CodeOrigin.h" > #include "ConcurrentJSLock.h" >+#include "ExitFlag.h" > #include "GetByIdVariant.h" >+#include "ICStatusMap.h" > #include "ScopeOffset.h" > > namespace JSC { >@@ -40,8 +42,6 @@ class JSModuleNamespaceObject; > class ModuleNamespaceAccessCase; > class StructureStubInfo; > >-typedef HashMap<CodeOrigin, StructureStubInfo*, CodeOriginApproximateHash> StubInfoMap; >- > class GetByIdStatus { > public: > enum State { >@@ -81,10 +81,10 @@ public: > m_variants.append(variant); > } > >- static GetByIdStatus computeFor(CodeBlock*, StubInfoMap&, unsigned bytecodeIndex, UniquedStringImpl* uid); >+ static GetByIdStatus computeFor(CodeBlock*, ICStatusMap&, unsigned bytecodeIndex, UniquedStringImpl* uid, ExitFlag, CallLinkStatus::ExitSiteData); > static GetByIdStatus computeFor(const StructureSet&, UniquedStringImpl* uid); > >- static GetByIdStatus computeFor(CodeBlock* baselineBlock, CodeBlock* dfgBlock, StubInfoMap& baselineMap, StubInfoMap& dfgMap, CodeOrigin, UniquedStringImpl* uid); >+ static GetByIdStatus computeFor(CodeBlock* baselineBlock, ICStatusMap& baselineMap, ICStatusContextStack& dfgContextStack, CodeOrigin, UniquedStringImpl* uid); > > #if ENABLE(DFG_JIT) > static GetByIdStatus computeForStubInfo(const ConcurrentJSLocker&, CodeBlock* baselineBlock, StructureStubInfo*, CodeOrigin, UniquedStringImpl* uid); >@@ -106,6 +106,8 @@ public: > bool takesSlowPath() const { return m_state == TakesSlowPath || m_state == MakesCalls || m_state == Custom || m_state == ModuleNamespace; } > bool makesCalls() const; > >+ GetByIdStatus slowVersion() const; >+ > bool wasSeenInJIT() const { return m_wasSeenInJIT; } > > // Attempts to reduce the set of variants to fit the given structure set. This may be approximate. >@@ -115,12 +117,12 @@ public: > JSModuleEnvironment* moduleEnvironment() const { return m_moduleEnvironment; } > ScopeOffset scopeOffset() const { return m_scopeOffset; } > >+ void markIfCheap(SlotVisitor&); >+ bool finalize(); // Return true if this gets to live. >+ > void dump(PrintStream&) const; > > private: >-#if ENABLE(DFG_JIT) >- static bool hasExitSite(CodeBlock*, unsigned bytecodeIndex); >-#endif > #if ENABLE(JIT) > GetByIdStatus(const ModuleNamespaceAccessCase&); > static GetByIdStatus computeForStubInfoWithoutExitSiteFeedback( >Index: Source/JavaScriptCore/bytecode/GetByIdVariant.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/GetByIdVariant.cpp (revision 232441) >+++ Source/JavaScriptCore/bytecode/GetByIdVariant.cpp (working copy) >@@ -135,6 +135,24 @@ bool GetByIdVariant::attemptToMerge(cons > return true; > } > >+void GetByIdVariant::markIfCheap(SlotVisitor& visitor) >+{ >+ m_structureSet.markIfCheap(visitor); >+} >+ >+bool GetByIdVariant::finalize() >+{ >+ if (!m_structureSet.isStillAlive()) >+ return false; >+ if (!m_conditionSet.areStillLive()) >+ return false; >+ if (m_callLinkStatus && !m_callLinkStatus->finalize()) >+ return false; >+ if (m_intrinsicFunction && !Heap::isMarked(m_intrinsicFunction)) >+ return false; >+ return true; >+} >+ > void GetByIdVariant::dump(PrintStream& out) const > { > dumpInContext(out, 0); >Index: Source/JavaScriptCore/bytecode/GetByIdVariant.h >=================================================================== >--- Source/JavaScriptCore/bytecode/GetByIdVariant.h (revision 232441) >+++ Source/JavaScriptCore/bytecode/GetByIdVariant.h (working copy) >@@ -73,6 +73,9 @@ public: > > bool attemptToMerge(const GetByIdVariant& other); > >+ void markIfCheap(SlotVisitor&); >+ bool finalize(); >+ > void dump(PrintStream&) const; > void dumpInContext(PrintStream&, DumpContext*) const; > >Index: Source/JavaScriptCore/bytecode/ICStatusMap.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/ICStatusMap.cpp (nonexistent) >+++ Source/JavaScriptCore/bytecode/ICStatusMap.cpp (working copy) >@@ -0,0 +1,51 @@ >+/* >+ * Copyright (C) 2018 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "ICStatusMap.h" >+ >+#include "InlineCallFrame.h" >+#include "TerminatedCodeOrigin.h" >+ >+namespace JSC { >+ >+ICStatus ICStatusContext::get(CodeOrigin codeOrigin) const >+{ >+ return map.get<TerminatedCodeOriginHashTranslator>( >+ TerminatedCodeOrigin(codeOrigin, inlineCallFrame)); >+} >+ >+bool ICStatusContext::isInlined(CodeOrigin codeOrigin) const >+{ >+ return codeOrigin.inlineCallFrame && codeOrigin.inlineCallFrame != inlineCallFrame; >+} >+ >+ExitingInlineKind ICStatusContext::inlineKind(CodeOrigin codeOrigin) const >+{ >+ return isInlined(codeOrigin) ? ExitFromInlined : ExitFromNotInlined; >+} >+ >+} // namespace JSC >+ >Index: Source/JavaScriptCore/bytecode/ICStatusMap.h >=================================================================== >--- Source/JavaScriptCore/bytecode/ICStatusMap.h (nonexistent) >+++ Source/JavaScriptCore/bytecode/ICStatusMap.h (working copy) >@@ -0,0 +1,68 @@ >+/* >+ * Copyright (C) 2018 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#include "CodeOrigin.h" >+#include "ExitingInlineKind.h" >+#include <wtf/HashMap.h> >+ >+namespace JSC { >+ >+class CallLinkInfo; >+class CallLinkStatus; >+class CodeBlock; >+class GetByIdStatus; >+class InByIdStatus; >+class PutByIdStatus; >+class StructureStubInfo; >+struct ByValInfo; >+ >+struct ICStatus { >+ StructureStubInfo* stubInfo { nullptr }; >+ CallLinkInfo* callLinkInfo { nullptr }; >+ ByValInfo* byValInfo { nullptr }; >+ CallLinkStatus* callStatus { nullptr }; >+ GetByIdStatus* getStatus { nullptr }; >+ InByIdStatus* inStatus { nullptr }; >+ PutByIdStatus* putStatus { nullptr }; >+}; >+ >+typedef HashMap<CodeOrigin, ICStatus, CodeOriginApproximateHash> ICStatusMap; >+ >+struct ICStatusContext { >+ ICStatus get(CodeOrigin) const; >+ bool isInlined(CodeOrigin) const; >+ ExitingInlineKind inlineKind(CodeOrigin) const; >+ >+ InlineCallFrame* inlineCallFrame { nullptr }; >+ CodeBlock* optimizedCodeBlock { nullptr }; >+ ICStatusMap map; >+}; >+ >+typedef Vector<ICStatusContext*, 8> ICStatusContextStack; >+ >+} // namespace JSC >+ >Index: Source/JavaScriptCore/bytecode/ICStatusUtils.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/ICStatusUtils.cpp (nonexistent) >+++ Source/JavaScriptCore/bytecode/ICStatusUtils.cpp (working copy) >@@ -0,0 +1,55 @@ >+/* >+ * Copyright (C) 2018 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "ICStatusUtils.h" >+ >+#include "CodeBlock.h" >+#include "ExitFlag.h" >+#include "UnlinkedCodeBlock.h" >+ >+namespace JSC { >+ >+ExitFlag hasBadCacheExitSite(CodeBlock* profiledBlock, unsigned bytecodeIndex) >+{ >+#if ENABLE(DFG_JIT) >+ UnlinkedCodeBlock* unlinkedCodeBlock = profiledBlock->unlinkedCodeBlock(); >+ ConcurrentJSLocker locker(unlinkedCodeBlock->m_lock); >+ auto exitFlag = [&] (ExitKind exitKind) -> ExitFlag { >+ auto withInlined = [&] (ExitingInlineKind inlineKind) -> ExitFlag { >+ return ExitFlag(unlinkedCodeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, exitKind, ExitFromAnything, inlineKind)), inlineKind); >+ }; >+ return withInlined(ExitFromNotInlined) | withInlined(ExitFromInlined); >+ }; >+ return exitFlag(BadCache) | exitFlag(BadConstantCache); >+#else >+ UNUSED_PARAM(profiledBlock); >+ UNUSED_PARAM(bytecodeIndex); >+ return ExitFlag(); >+#endif >+} >+ >+} // namespace JSC >+ >Index: Source/JavaScriptCore/bytecode/ICStatusUtils.h >=================================================================== >--- Source/JavaScriptCore/bytecode/ICStatusUtils.h (revision 232441) >+++ Source/JavaScriptCore/bytecode/ICStatusUtils.h (working copy) >@@ -25,6 +25,8 @@ > > #pragma once > >+#include "ExitFlag.h" >+ > namespace JSC { > > template<typename VariantVectorType, typename VariantType> >@@ -59,5 +61,7 @@ void filterICStatusVariants(VariantVecto > }); > } > >+ExitFlag hasBadCacheExitSite(CodeBlock* profiledBlock, unsigned bytecodeIndex); >+ > } // namespace JSC > >Index: Source/JavaScriptCore/bytecode/InByIdStatus.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/InByIdStatus.cpp (revision 232441) >+++ Source/JavaScriptCore/bytecode/InByIdStatus.cpp (working copy) >@@ -1,5 +1,6 @@ > /* > * Copyright (C) 2018 Yusuke Suzuki <utatane.tea@gmail.com>. >+ * Copyright (C) 2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -41,16 +42,16 @@ bool InByIdStatus::appendVariant(const I > return appendICStatusVariant(m_variants, variant); > } > >-InByIdStatus InByIdStatus::computeFor(CodeBlock* profiledBlock, StubInfoMap& map, unsigned bytecodeIndex, UniquedStringImpl* uid) >+InByIdStatus InByIdStatus::computeFor(CodeBlock* profiledBlock, ICStatusMap& map, unsigned bytecodeIndex, UniquedStringImpl* uid, ExitFlag didExit) > { > ConcurrentJSLocker locker(profiledBlock->m_lock); > > InByIdStatus result; > > #if ENABLE(DFG_JIT) >- result = computeForStubInfoWithoutExitSiteFeedback(locker, map.get(CodeOrigin(bytecodeIndex)), uid); >+ result = computeForStubInfoWithoutExitSiteFeedback(locker, map.get(CodeOrigin(bytecodeIndex)).stubInfo, uid); > >- if (!result.takesSlowPath() && hasExitSite(profiledBlock, bytecodeIndex)) >+ if (!result.takesSlowPath() && didExit) > return InByIdStatus(TakesSlowPath); > #else > UNUSED_PARAM(map); >@@ -61,56 +62,47 @@ InByIdStatus InByIdStatus::computeFor(Co > return result; > } > >-InByIdStatus InByIdStatus::computeFor( >- CodeBlock* profiledBlock, CodeBlock* dfgBlock, StubInfoMap& baselineMap, >- StubInfoMap& dfgMap, CodeOrigin codeOrigin, UniquedStringImpl* uid) >+InByIdStatus InByIdStatus::computeFor(CodeBlock* profiledBlock, ICStatusMap& map, unsigned bytecodeIndex, UniquedStringImpl* uid) > { >-#if ENABLE(DFG_JIT) >- if (dfgBlock) { >- CallLinkStatus::ExitSiteData exitSiteData; >- { >- ConcurrentJSLocker locker(profiledBlock->m_lock); >- exitSiteData = CallLinkStatus::computeExitSiteData( >- profiledBlock, codeOrigin.bytecodeIndex); >- } >- >- InByIdStatus result; >- { >- ConcurrentJSLocker locker(dfgBlock->m_lock); >- result = computeForStubInfoWithoutExitSiteFeedback(locker, dfgMap.get(codeOrigin), uid); >- } >+ return computeFor(profiledBlock, map, bytecodeIndex, uid, hasBadCacheExitSite(profiledBlock, bytecodeIndex)); >+} > >- if (result.takesSlowPath()) >+InByIdStatus InByIdStatus::computeFor( >+ CodeBlock* profiledBlock, ICStatusMap& baselineMap, >+ ICStatusContextStack& contextStack, CodeOrigin codeOrigin, UniquedStringImpl* uid) >+{ >+ ExitFlag didExit = hasBadCacheExitSite(profiledBlock, codeOrigin.bytecodeIndex); >+ >+ for (ICStatusContext* context : contextStack) { >+ ICStatus status = context->get(codeOrigin); >+ >+ auto withExits = [&] (const InByIdStatus& result) -> InByIdStatus { >+ if (didExit.isSet(codeOrigin.exitingInlineKind())) >+ return InByIdStatus(TakesSlowPath); > return result; >+ }; > >- if (hasExitSite(profiledBlock, codeOrigin.bytecodeIndex)) >- return InByIdStatus(TakesSlowPath); >- >- if (result.isSet()) >- return result; >+ if (status.stubInfo) { >+ ConcurrentJSLocker locker(context->optimizedCodeBlock->m_lock); >+ InByIdStatus result = >+ computeForStubInfoWithoutExitSiteFeedback(locker, status.stubInfo, uid); >+ if (result.isSet()) >+ return withExits(result); >+ } >+ >+ if (status.inStatus) >+ return withExits(*status.inStatus); > } >-#else >- UNUSED_PARAM(dfgBlock); >- UNUSED_PARAM(dfgMap); >-#endif >- >- return computeFor(profiledBlock, baselineMap, codeOrigin.bytecodeIndex, uid); >+ >+ return computeFor(profiledBlock, baselineMap, codeOrigin.bytecodeIndex, uid, didExit); > } > > #if ENABLE(DFG_JIT) >-bool InByIdStatus::hasExitSite(CodeBlock* profiledBlock, unsigned bytecodeIndex) >-{ >- UnlinkedCodeBlock* unlinkedCodeBlock = profiledBlock->unlinkedCodeBlock(); >- ConcurrentJSLocker locker(unlinkedCodeBlock->m_lock); >- return unlinkedCodeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCache)) >- || unlinkedCodeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadConstantCache)); >-} >- > InByIdStatus InByIdStatus::computeForStubInfo(const ConcurrentJSLocker& locker, CodeBlock* profiledBlock, StructureStubInfo* stubInfo, CodeOrigin codeOrigin, UniquedStringImpl* uid) > { > InByIdStatus result = InByIdStatus::computeForStubInfoWithoutExitSiteFeedback(locker, stubInfo, uid); > >- if (!result.takesSlowPath() && InByIdStatus::hasExitSite(profiledBlock, codeOrigin.bytecodeIndex)) >+ if (!result.takesSlowPath() && hasBadCacheExitSite(profiledBlock, codeOrigin.bytecodeIndex)) > return InByIdStatus(TakesSlowPath); > return result; > } >@@ -218,6 +210,21 @@ void InByIdStatus::filter(const Structur > m_state = NoInformation; > } > >+void InByIdStatus::markIfCheap(SlotVisitor& visitor) >+{ >+ for (InByIdVariant& variant : m_variants) >+ variant.markIfCheap(visitor); >+} >+ >+bool InByIdStatus::finalize() >+{ >+ for (InByIdVariant& variant : m_variants) { >+ if (!variant.finalize()) >+ return false; >+ } >+ return true; >+} >+ > void InByIdStatus::dump(PrintStream& out) const > { > out.print("("); >Index: Source/JavaScriptCore/bytecode/InByIdStatus.h >=================================================================== >--- Source/JavaScriptCore/bytecode/InByIdStatus.h (revision 232441) >+++ Source/JavaScriptCore/bytecode/InByIdStatus.h (working copy) >@@ -1,5 +1,6 @@ > /* > * Copyright (C) 2018 Yusuke Suzuki <utatane.tea@gmail.com>. >+ * Copyright (C) 2018 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 +29,7 @@ > #include "CallLinkStatus.h" > #include "CodeOrigin.h" > #include "ConcurrentJSLock.h" >+#include "ICStatusMap.h" > #include "InByIdVariant.h" > > namespace JSC { >@@ -36,8 +38,6 @@ class AccessCase; > class CodeBlock; > class StructureStubInfo; > >-typedef HashMap<CodeOrigin, StructureStubInfo*, CodeOriginApproximateHash> StubInfoMap; >- > class InByIdStatus { > public: > enum State { >@@ -59,8 +59,9 @@ public: > m_variants.append(variant); > } > >- static InByIdStatus computeFor(CodeBlock*, StubInfoMap&, unsigned bytecodeIndex, UniquedStringImpl* uid); >- static InByIdStatus computeFor(CodeBlock* baselineBlock, CodeBlock* dfgBlock, StubInfoMap& baselineMap, StubInfoMap& dfgMap, CodeOrigin, UniquedStringImpl* uid); >+ static InByIdStatus computeFor(CodeBlock*, ICStatusMap&, unsigned bytecodeIndex, UniquedStringImpl* uid); >+ static InByIdStatus computeFor(CodeBlock*, ICStatusMap&, unsigned bytecodeIndex, UniquedStringImpl* uid, ExitFlag); >+ static InByIdStatus computeFor(CodeBlock* baselineBlock, ICStatusMap& baselineMap, ICStatusContextStack& contextStack, CodeOrigin, UniquedStringImpl* uid); > > #if ENABLE(DFG_JIT) > static InByIdStatus computeForStubInfo(const ConcurrentJSLocker&, CodeBlock* baselineBlock, StructureStubInfo*, CodeOrigin, UniquedStringImpl* uid); >@@ -81,12 +82,14 @@ public: > > // Attempts to reduce the set of variants to fit the given structure set. This may be approximate. > void filter(const StructureSet&); >+ >+ void markIfCheap(SlotVisitor&); >+ bool finalize(); > > void dump(PrintStream&) const; > > private: > #if ENABLE(DFG_JIT) >- static bool hasExitSite(CodeBlock*, unsigned bytecodeIndex); > static InByIdStatus computeForStubInfoWithoutExitSiteFeedback(const ConcurrentJSLocker&, StructureStubInfo*, UniquedStringImpl* uid); > #endif > bool appendVariant(const InByIdVariant&); >Index: Source/JavaScriptCore/bytecode/InByIdVariant.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/InByIdVariant.cpp (revision 232441) >+++ Source/JavaScriptCore/bytecode/InByIdVariant.cpp (working copy) >@@ -1,5 +1,6 @@ > /* > * Copyright (C) 2018 Yusuke Suzuki <utatane.tea@gmail.com>. >+ * Copyright (C) 2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -63,6 +64,20 @@ bool InByIdVariant::attemptToMerge(const > return true; > } > >+void InByIdVariant::markIfCheap(SlotVisitor& visitor) >+{ >+ m_structureSet.markIfCheap(visitor); >+} >+ >+bool InByIdVariant::finalize() >+{ >+ if (!m_structureSet.isStillAlive()) >+ return false; >+ if (!m_conditionSet.areStillLive()) >+ return false; >+ return true; >+} >+ > void InByIdVariant::dump(PrintStream& out) const > { > dumpInContext(out, 0); >Index: Source/JavaScriptCore/bytecode/InByIdVariant.h >=================================================================== >--- Source/JavaScriptCore/bytecode/InByIdVariant.h (revision 232441) >+++ Source/JavaScriptCore/bytecode/InByIdVariant.h (working copy) >@@ -1,5 +1,6 @@ > /* > * Copyright (C) 2018 Yusuke Suzuki <utatane.tea@gmail.com>. >+ * Copyright (C) 2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -54,6 +55,9 @@ public: > bool isHit() const { return offset() != invalidOffset; } > > bool attemptToMerge(const InByIdVariant& other); >+ >+ void markIfCheap(SlotVisitor&); >+ bool finalize(); > > void dump(PrintStream&) const; > void dumpInContext(PrintStream&, DumpContext*) const; >Index: Source/JavaScriptCore/bytecode/InstanceOfStatus.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/InstanceOfStatus.cpp (revision 232441) >+++ Source/JavaScriptCore/bytecode/InstanceOfStatus.cpp (working copy) >@@ -27,6 +27,7 @@ > #include "InstanceOfStatus.h" > > #include "ICStatusUtils.h" >+#include "InstanceOfAccessCase.h" > #include "JSCInlines.h" > #include "PolymorphicAccess.h" > #include "StructureStubInfo.h" >@@ -39,13 +40,13 @@ void InstanceOfStatus::appendVariant(con > } > > InstanceOfStatus InstanceOfStatus::computeFor( >- CodeBlock* codeBlock, StubInfoMap& infoMap, unsigned bytecodeIndex) >+ CodeBlock* codeBlock, ICStatusMap& infoMap, unsigned bytecodeIndex) > { > ConcurrentJSLocker locker(codeBlock->m_lock); > > InstanceOfStatus result; > #if ENABLE(DFG_JIT) >- result = computeForStubInfo(locker, infoMap.get(CodeOrigin(bytecodeIndex))); >+ result = computeForStubInfo(locker, infoMap.get(CodeOrigin(bytecodeIndex)).stubInfo); > > if (!result.takesSlowPath()) { > UnlinkedCodeBlock* unlinkedCodeBlock = codeBlock->unlinkedCodeBlock(); >Index: Source/JavaScriptCore/bytecode/InstanceOfStatus.h >=================================================================== >--- Source/JavaScriptCore/bytecode/InstanceOfStatus.h (revision 232441) >+++ Source/JavaScriptCore/bytecode/InstanceOfStatus.h (working copy) >@@ -27,6 +27,7 @@ > > #include "CodeOrigin.h" > #include "ConcurrentJSLock.h" >+#include "ICStatusMap.h" > #include "InstanceOfVariant.h" > > namespace JSC { >@@ -35,8 +36,6 @@ class AccessCase; > class CodeBlock; > class StructureStubInfo; > >-typedef HashMap<CodeOrigin, StructureStubInfo*, CodeOriginApproximateHash> StubInfoMap; >- > class InstanceOfStatus { > public: > enum State { >@@ -61,7 +60,7 @@ public: > ASSERT(state == NoInformation || state == TakesSlowPath); > } > >- static InstanceOfStatus computeFor(CodeBlock*, StubInfoMap&, unsigned bytecodeIndex); >+ static InstanceOfStatus computeFor(CodeBlock*, ICStatusMap&, unsigned bytecodeIndex); > > #if ENABLE(DFG_JIT) > static InstanceOfStatus computeForStubInfo(const ConcurrentJSLocker&, StructureStubInfo*); >Index: Source/JavaScriptCore/bytecode/PutByIdStatus.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/PutByIdStatus.cpp (revision 232441) >+++ Source/JavaScriptCore/bytecode/PutByIdStatus.cpp (working copy) >@@ -29,6 +29,7 @@ > #include "CodeBlock.h" > #include "ComplexGetStatus.h" > #include "GetterSetterAccessCase.h" >+#include "ICStatusUtils.h" > #include "LLIntData.h" > #include "LowLevelInterpreter.h" > #include "JSCInlines.h" >@@ -55,12 +56,9 @@ bool PutByIdStatus::appendVariant(const > } > > #if ENABLE(DFG_JIT) >-bool PutByIdStatus::hasExitSite(CodeBlock* profiledBlock, unsigned bytecodeIndex) >+ExitFlag PutByIdStatus::hasExitSite(CodeBlock* profiledBlock, unsigned bytecodeIndex) > { >- UnlinkedCodeBlock* unlinkedCodeBlock = profiledBlock->unlinkedCodeBlock(); >- ConcurrentJSLocker locker(unlinkedCodeBlock->m_lock); >- return unlinkedCodeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCache)) >- || unlinkedCodeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadConstantCache)); >+ return hasBadCacheExitSite(profiledBlock, bytecodeIndex); > } > #endif > >@@ -110,7 +108,7 @@ PutByIdStatus PutByIdStatus::computeFrom > structure, newStructure, conditionSet, offset, newStructure->inferredTypeDescriptorFor(uid)); > } > >-PutByIdStatus PutByIdStatus::computeFor(CodeBlock* profiledBlock, StubInfoMap& map, unsigned bytecodeIndex, UniquedStringImpl* uid) >+PutByIdStatus PutByIdStatus::computeFor(CodeBlock* profiledBlock, ICStatusMap& map, unsigned bytecodeIndex, UniquedStringImpl* uid, ExitFlag didExit, CallLinkStatus::ExitSiteData callExitSiteData) > { > ConcurrentJSLocker locker(profiledBlock->m_lock); > >@@ -118,13 +116,12 @@ PutByIdStatus PutByIdStatus::computeFor( > UNUSED_PARAM(bytecodeIndex); > UNUSED_PARAM(uid); > #if ENABLE(DFG_JIT) >- if (hasExitSite(profiledBlock, bytecodeIndex)) >+ if (didExit) > return PutByIdStatus(TakesSlowPath); > >- StructureStubInfo* stubInfo = map.get(CodeOrigin(bytecodeIndex)); >+ StructureStubInfo* stubInfo = map.get(CodeOrigin(bytecodeIndex)).stubInfo; > PutByIdStatus result = computeForStubInfo( >- locker, profiledBlock, stubInfo, uid, >- CallLinkStatus::computeExitSiteData(profiledBlock, bytecodeIndex)); >+ locker, profiledBlock, stubInfo, uid, callExitSiteData); > if (!result) > return computeFromLLInt(profiledBlock, bytecodeIndex, uid); > >@@ -264,38 +261,34 @@ PutByIdStatus PutByIdStatus::computeForS > } > #endif > >-PutByIdStatus PutByIdStatus::computeFor(CodeBlock* baselineBlock, CodeBlock* dfgBlock, StubInfoMap& baselineMap, StubInfoMap& dfgMap, CodeOrigin codeOrigin, UniquedStringImpl* uid) >+PutByIdStatus PutByIdStatus::computeFor(CodeBlock* baselineBlock, ICStatusMap& baselineMap, ICStatusContextStack& contextStack, CodeOrigin codeOrigin, UniquedStringImpl* uid) > { >-#if ENABLE(DFG_JIT) >- if (dfgBlock) { >- if (hasExitSite(baselineBlock, codeOrigin.bytecodeIndex)) >- return PutByIdStatus(TakesSlowPath); >- CallLinkStatus::ExitSiteData exitSiteData; >- { >- ConcurrentJSLocker locker(baselineBlock->m_lock); >- exitSiteData = CallLinkStatus::computeExitSiteData( >- baselineBlock, codeOrigin.bytecodeIndex); >- } >- >- PutByIdStatus result; >- { >- ConcurrentJSLocker locker(dfgBlock->m_lock); >- result = computeForStubInfo( >- locker, dfgBlock, dfgMap.get(codeOrigin), uid, exitSiteData); >+ CallLinkStatus::ExitSiteData callExitSiteData = >+ CallLinkStatus::computeExitSiteData(baselineBlock, codeOrigin.bytecodeIndex); >+ ExitFlag didExit = hasExitSite(baselineBlock, codeOrigin.bytecodeIndex); >+ >+ for (ICStatusContext* context : contextStack) { >+ ICStatus status = context->get(codeOrigin); >+ >+ auto withExits = [&] (const PutByIdStatus& result) -> PutByIdStatus { >+ if (didExit.isSet(codeOrigin.exitingInlineKind())) >+ return result.slowVersion(); >+ return result; >+ }; >+ >+ if (status.stubInfo) { >+ ConcurrentJSLocker locker(context->optimizedCodeBlock->m_lock); >+ PutByIdStatus result = computeForStubInfo( >+ locker, context->optimizedCodeBlock, status.stubInfo, uid, callExitSiteData); >+ if (result.isSet()) >+ return withExits(result); > } > >- // We use TakesSlowPath in some cases where the stub was unset. That's weird and >- // it would be better not to do that. But it means that we have to defend >- // ourselves here. >- if (result.isSimple()) >- return result; >+ if (status.putStatus) >+ return withExits(*status.putStatus); > } >-#else >- UNUSED_PARAM(dfgBlock); >- UNUSED_PARAM(dfgMap); >-#endif > >- return computeFor(baselineBlock, baselineMap, codeOrigin.bytecodeIndex, uid); >+ return computeFor(baselineBlock, baselineMap, codeOrigin.bytecodeIndex, uid, didExit, callExitSiteData); > } > > PutByIdStatus PutByIdStatus::computeFor(JSGlobalObject* globalObject, const StructureSet& set, UniquedStringImpl* uid, bool isDirect) >@@ -398,6 +391,35 @@ bool PutByIdStatus::makesCalls() const > return false; > } > >+PutByIdStatus PutByIdStatus::slowVersion() const >+{ >+ return PutByIdStatus(makesCalls() ? MakesCalls : TakesSlowPath); >+} >+ >+void PutByIdStatus::markIfCheap(SlotVisitor& visitor) >+{ >+ for (PutByIdVariant& variant : m_variants) >+ variant.markIfCheap(visitor); >+} >+ >+bool PutByIdStatus::finalize() >+{ >+ for (PutByIdVariant& variant : m_variants) { >+ if (!variant.finalize()) >+ return false; >+ } >+ return true; >+} >+ >+void PutByIdStatus::filter(const StructureSet& set) >+{ >+ if (m_state != Simple) >+ return; >+ filterICStatusVariants(m_variants, set); >+ if (m_variants.isEmpty()) >+ m_state = NoInformation; >+} >+ > void PutByIdStatus::dump(PrintStream& out) const > { > switch (m_state) { >Index: Source/JavaScriptCore/bytecode/PutByIdStatus.h >=================================================================== >--- Source/JavaScriptCore/bytecode/PutByIdStatus.h (revision 232441) >+++ Source/JavaScriptCore/bytecode/PutByIdStatus.h (working copy) >@@ -26,6 +26,8 @@ > #pragma once > > #include "CallLinkStatus.h" >+#include "ExitFlag.h" >+#include "ICStatusMap.h" > #include "PutByIdVariant.h" > > namespace JSC { >@@ -69,10 +71,10 @@ public: > m_variants.append(variant); > } > >- static PutByIdStatus computeFor(CodeBlock*, StubInfoMap&, unsigned bytecodeIndex, UniquedStringImpl* uid); >+ static PutByIdStatus computeFor(CodeBlock*, ICStatusMap&, unsigned bytecodeIndex, UniquedStringImpl* uid, ExitFlag, CallLinkStatus::ExitSiteData); > static PutByIdStatus computeFor(JSGlobalObject*, const StructureSet&, UniquedStringImpl* uid, bool isDirect); > >- static PutByIdStatus computeFor(CodeBlock* baselineBlock, CodeBlock* dfgBlock, StubInfoMap& baselineMap, StubInfoMap& dfgMap, CodeOrigin, UniquedStringImpl* uid); >+ static PutByIdStatus computeFor(CodeBlock* baselineBlock, ICStatusMap& baselineMap, ICStatusContextStack& contextStack, CodeOrigin, UniquedStringImpl* uid); > > #if ENABLE(JIT) > static PutByIdStatus computeForStubInfo(const ConcurrentJSLocker&, CodeBlock* baselineBlock, StructureStubInfo*, CodeOrigin, UniquedStringImpl* uid); >@@ -85,17 +87,22 @@ public: > bool isSimple() const { return m_state == Simple; } > bool takesSlowPath() const { return m_state == TakesSlowPath || m_state == MakesCalls; } > bool makesCalls() const; >+ PutByIdStatus slowVersion() const; > > size_t numVariants() const { return m_variants.size(); } > const Vector<PutByIdVariant, 1>& variants() const { return m_variants; } > const PutByIdVariant& at(size_t index) const { return m_variants[index]; } > const PutByIdVariant& operator[](size_t index) const { return at(index); } > >+ void markIfCheap(SlotVisitor&); >+ bool finalize(); >+ void filter(const StructureSet&); >+ > void dump(PrintStream&) const; > > private: > #if ENABLE(DFG_JIT) >- static bool hasExitSite(CodeBlock*, unsigned bytecodeIndex); >+ static ExitFlag hasExitSite(CodeBlock*, unsigned bytecodeIndex); > #endif > #if ENABLE(JIT) > static PutByIdStatus computeForStubInfo( >Index: Source/JavaScriptCore/bytecode/PutByIdVariant.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/PutByIdVariant.cpp (revision 232441) >+++ Source/JavaScriptCore/bytecode/PutByIdVariant.cpp (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2014, 2015 Apple Inc. All rights reserved. >+ * Copyright (C) 2014-2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -206,6 +206,26 @@ bool PutByIdVariant::attemptToMergeTrans > return true; > } > >+void PutByIdVariant::markIfCheap(SlotVisitor& visitor) >+{ >+ m_oldStructure.markIfCheap(visitor); >+ if (m_newStructure) >+ m_newStructure->markIfCheap(visitor); >+} >+ >+bool PutByIdVariant::finalize() >+{ >+ if (!m_oldStructure.isStillAlive()) >+ return false; >+ if (m_newStructure && !Heap::isMarked(m_newStructure)) >+ return false; >+ if (!m_conditionSet.areStillLive()) >+ return false; >+ if (m_callLinkStatus && !m_callLinkStatus->finalize()) >+ return false; >+ return true; >+} >+ > void PutByIdVariant::dump(PrintStream& out) const > { > dumpInContext(out, 0); >Index: Source/JavaScriptCore/bytecode/PutByIdVariant.h >=================================================================== >--- Source/JavaScriptCore/bytecode/PutByIdVariant.h (revision 232441) >+++ Source/JavaScriptCore/bytecode/PutByIdVariant.h (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2014, 2015 Apple Inc. All rights reserved. >+ * Copyright (C) 2014-2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -73,17 +73,17 @@ public: > return m_oldStructure; > } > >- const StructureSet& structureSet() const >- { >- return structure(); >- } >- > const StructureSet& oldStructure() const > { > ASSERT(kind() == Transition || kind() == Replace || kind() == Setter); > return m_oldStructure; > } > >+ const StructureSet& structureSet() const >+ { >+ return oldStructure(); >+ } >+ > StructureSet& oldStructure() > { > ASSERT(kind() == Transition || kind() == Replace || kind() == Setter); >@@ -129,6 +129,9 @@ public: > > bool attemptToMerge(const PutByIdVariant& other); > >+ void markIfCheap(SlotVisitor&); >+ bool finalize(); >+ > void dump(PrintStream&) const; > void dumpInContext(PrintStream&, DumpContext*) const; > >@@ -137,7 +140,7 @@ private: > > Kind m_kind; > StructureSet m_oldStructure; >- Structure* m_newStructure; >+ Structure* m_newStructure { nullptr }; > ObjectPropertyConditionSet m_conditionSet; > PropertyOffset m_offset; > InferredType::Descriptor m_requiredType; >Index: Source/JavaScriptCore/bytecode/RecordedStatuses.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/RecordedStatuses.cpp (nonexistent) >+++ Source/JavaScriptCore/bytecode/RecordedStatuses.cpp (working copy) >@@ -0,0 +1,122 @@ >+/* >+ * Copyright (C) 2018 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "RecordedStatuses.h" >+ >+namespace JSC { >+ >+RecordedStatuses& RecordedStatuses::operator=(RecordedStatuses&& other) >+{ >+ calls = WTFMove(other.calls); >+ gets = WTFMove(other.gets); >+ puts = WTFMove(other.puts); >+ ins = WTFMove(other.ins); >+ shrinkToFit(); >+ return *this; >+} >+ >+RecordedStatuses::RecordedStatuses(RecordedStatuses&& other) >+{ >+ *this = WTFMove(other); >+} >+ >+CallLinkStatus* RecordedStatuses::addCallLinkStatus(const CodeOrigin& codeOrigin, const CallLinkStatus& status) >+{ >+ auto statusPtr = std::make_unique<CallLinkStatus>(status); >+ CallLinkStatus* result = statusPtr.get(); >+ calls.append(std::make_pair(codeOrigin, WTFMove(statusPtr))); >+ return result; >+} >+ >+GetByIdStatus* RecordedStatuses::addGetByIdStatus(const CodeOrigin& codeOrigin, const GetByIdStatus& status) >+{ >+ auto statusPtr = std::make_unique<GetByIdStatus>(status); >+ GetByIdStatus* result = statusPtr.get(); >+ gets.append(std::make_pair(codeOrigin, WTFMove(statusPtr))); >+ return result; >+} >+ >+PutByIdStatus* RecordedStatuses::addPutByIdStatus(const CodeOrigin& codeOrigin, const PutByIdStatus& status) >+{ >+ auto statusPtr = std::make_unique<PutByIdStatus>(status); >+ PutByIdStatus* result = statusPtr.get(); >+ puts.append(std::make_pair(codeOrigin, WTFMove(statusPtr))); >+ return result; >+} >+ >+InByIdStatus* RecordedStatuses::addInByIdStatus(const CodeOrigin& codeOrigin, const InByIdStatus& status) >+{ >+ auto statusPtr = std::make_unique<InByIdStatus>(status); >+ InByIdStatus* result = statusPtr.get(); >+ ins.append(std::make_pair(codeOrigin, WTFMove(statusPtr))); >+ return result; >+} >+ >+void RecordedStatuses::markIfCheap(SlotVisitor& slotVisitor) >+{ >+ for (auto& pair : gets) >+ pair.second->markIfCheap(slotVisitor); >+ for (auto& pair : puts) >+ pair.second->markIfCheap(slotVisitor); >+ for (auto& pair : ins) >+ pair.second->markIfCheap(slotVisitor); >+} >+ >+void RecordedStatuses::finalizeWithoutDeleting() >+{ >+ // This variant of finalize gets called from within graph safepoints -- so there may be DFG IR in >+ // some compiler thread that points to the statuses. That thread is stopped at a safepoint so >+ // it's OK to edit its data structure, but it's not OK to delete them. Hence we don't remove >+ // anything from the vector or delete the unique_ptrs. >+ >+ auto finalize = [] (auto& vector) { >+ for (auto& pair : vector) { >+ if (!pair.second->finalize()) >+ *pair.second = { }; >+ } >+ }; >+ forEachVector(finalize); >+} >+ >+void RecordedStatuses::finalize() >+{ >+ auto finalize = [] (auto& vector) { >+ vector.removeAllMatching( >+ [&] (auto& pair) -> bool { >+ return !*pair.second || !pair.second->finalize(); >+ }); >+ vector.shrinkToFit(); >+ }; >+ forEachVector(finalize); >+} >+ >+void RecordedStatuses::shrinkToFit() >+{ >+ forEachVector([] (auto& vector) { vector.shrinkToFit(); }); >+} >+ >+} // namespace JSC >+ >Index: Source/JavaScriptCore/bytecode/RecordedStatuses.h >=================================================================== >--- Source/JavaScriptCore/bytecode/RecordedStatuses.h (nonexistent) >+++ Source/JavaScriptCore/bytecode/RecordedStatuses.h (working copy) >@@ -0,0 +1,74 @@ >+/* >+ * Copyright (C) 2018 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#include "CallLinkStatus.h" >+#include "GetByIdStatus.h" >+#include "InByIdStatus.h" >+#include "PutByIdStatus.h" >+ >+namespace JSC { >+ >+struct RecordedStatuses { >+ RecordedStatuses() { } >+ >+ RecordedStatuses& operator=(const RecordedStatuses& other) = delete; >+ >+ RecordedStatuses& operator=(RecordedStatuses&& other); >+ >+ RecordedStatuses(const RecordedStatuses& other) = delete; >+ >+ RecordedStatuses(RecordedStatuses&& other); >+ >+ CallLinkStatus* addCallLinkStatus(const CodeOrigin&, const CallLinkStatus&); >+ GetByIdStatus* addGetByIdStatus(const CodeOrigin&, const GetByIdStatus&); >+ PutByIdStatus* addPutByIdStatus(const CodeOrigin&, const PutByIdStatus&); >+ InByIdStatus* addInByIdStatus(const CodeOrigin&, const InByIdStatus&); >+ >+ void markIfCheap(SlotVisitor& slotVisitor); >+ >+ void finalizeWithoutDeleting(); >+ void finalize(); >+ >+ void shrinkToFit(); >+ >+ template<typename Func> >+ void forEachVector(const Func& func) >+ { >+ func(calls); >+ func(gets); >+ func(puts); >+ func(ins); >+ } >+ >+ Vector<std::pair<CodeOrigin, std::unique_ptr<CallLinkStatus>>> calls; >+ Vector<std::pair<CodeOrigin, std::unique_ptr<GetByIdStatus>>> gets; >+ Vector<std::pair<CodeOrigin, std::unique_ptr<PutByIdStatus>>> puts; >+ Vector<std::pair<CodeOrigin, std::unique_ptr<InByIdStatus>>> ins; >+}; >+ >+} // namespace JSC >+ >Index: Source/JavaScriptCore/bytecode/StructureSet.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/StructureSet.cpp (revision 232441) >+++ Source/JavaScriptCore/bytecode/StructureSet.cpp (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2014, 2015 Apple Inc. All rights reserved. >+ * Copyright (C) 2014-2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -31,6 +31,21 @@ > > namespace JSC { > >+void StructureSet::markIfCheap(SlotVisitor& visitor) const >+{ >+ for (Structure* structure : *this) >+ structure->markIfCheap(visitor); >+} >+ >+bool StructureSet::isStillAlive() const >+{ >+ for (Structure* structure : *this) { >+ if (!Heap::isMarked(structure)) >+ return false; >+ } >+ return true; >+} >+ > void StructureSet::dumpInContext(PrintStream& out, DumpContext* context) const > { > CommaPrinter comma; >Index: Source/JavaScriptCore/bytecode/StructureSet.h >=================================================================== >--- Source/JavaScriptCore/bytecode/StructureSet.h (revision 232441) >+++ Source/JavaScriptCore/bytecode/StructureSet.h (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved. >+ * Copyright (C) 2011-2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -58,6 +58,9 @@ public: > { > return onlyEntry(); > } >+ >+ void markIfCheap(SlotVisitor&) const; >+ bool isStillAlive() const; > > void dumpInContext(PrintStream&, DumpContext*) const; > void dump(PrintStream&) const; >Index: Source/JavaScriptCore/bytecode/TerminatedCodeOrigin.h >=================================================================== >--- Source/JavaScriptCore/bytecode/TerminatedCodeOrigin.h (nonexistent) >+++ Source/JavaScriptCore/bytecode/TerminatedCodeOrigin.h (working copy) >@@ -0,0 +1,60 @@ >+/* >+ * Copyright (C) 2018 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#include "CodeOrigin.h" >+ >+namespace JSC { >+ >+struct InlineCallFrame; >+ >+struct TerminatedCodeOrigin { >+ TerminatedCodeOrigin() { } >+ >+ TerminatedCodeOrigin(const CodeOrigin& codeOrigin, InlineCallFrame* terminal) >+ : codeOrigin(codeOrigin) >+ , terminal(terminal) >+ { >+ } >+ >+ CodeOrigin codeOrigin; >+ InlineCallFrame* terminal { nullptr }; >+}; >+ >+struct TerminatedCodeOriginHashTranslator { >+ static unsigned hash(const TerminatedCodeOrigin& value) >+ { >+ return value.codeOrigin.approximateHash(value.terminal); >+ } >+ >+ static bool equal(const CodeOrigin& a, const TerminatedCodeOrigin& b) >+ { >+ return b.codeOrigin.isApproximatelyEqualTo(a, b.terminal); >+ } >+}; >+ >+} // namespace JSC >+ >Index: Source/JavaScriptCore/bytecode/Watchpoint.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/Watchpoint.cpp (revision 232441) >+++ Source/JavaScriptCore/bytecode/Watchpoint.cpp (working copy) >@@ -203,3 +203,23 @@ void DeferredWatchpointFire::takeWatchpo > > } // namespace JSC > >+namespace WTF { >+ >+void printInternal(PrintStream& out, JSC::WatchpointState state) >+{ >+ switch (state) { >+ case JSC::ClearWatchpoint: >+ out.print("ClearWatchpoint"); >+ return; >+ case JSC::IsWatched: >+ out.print("IsWatched"); >+ return; >+ case JSC::IsInvalidated: >+ out.print("IsInvalidated"); >+ return; >+ } >+ RELEASE_ASSERT_NOT_REACHED(); >+} >+ >+} // namespace WTF >+ >Index: Source/JavaScriptCore/bytecode/Watchpoint.h >=================================================================== >--- Source/JavaScriptCore/bytecode/Watchpoint.h (revision 232441) >+++ Source/JavaScriptCore/bytecode/Watchpoint.h (working copy) >@@ -448,3 +448,10 @@ private: > }; > > } // namespace JSC >+ >+namespace WTF { >+ >+void printInternal(PrintStream& out, JSC::WatchpointState); >+ >+} // namespace WTF >+ >Index: Source/JavaScriptCore/dfg/DFGAbstractInterpreter.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAbstractInterpreter.h (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGAbstractInterpreter.h (working copy) >@@ -212,6 +212,8 @@ public: > > PhiChildren* phiChildren() { return m_phiChildren.get(); } > >+ void filterICStatus(Node*); >+ > private: > void clobberWorld(); > void didFoldClobberWorld(); >Index: Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (working copy) >@@ -3509,6 +3509,10 @@ bool AbstractInterpreter<AbstractStateTy > case LoopHint: > case ZombieHint: > case ExitOK: >+ case FilterCallLinkStatus: >+ case FilterGetByIdStatus: >+ case FilterPutByIdStatus: >+ case FilterInByIdStatus: > break; > > case CheckTypeInfoFlags: { >@@ -3629,6 +3633,42 @@ bool AbstractInterpreter<AbstractStateTy > } > > template<typename AbstractStateType> >+void AbstractInterpreter<AbstractStateType>::filterICStatus(Node* node) >+{ >+ switch (node->op()) { >+ case FilterCallLinkStatus: >+ if (JSValue value = forNode(node->child1()).m_value) >+ node->callLinkStatus()->filter(m_vm, value); >+ break; >+ >+ case FilterGetByIdStatus: { >+ AbstractValue& value = forNode(node->child1()); >+ if (value.m_structure.isFinite()) >+ node->getByIdStatus()->filter(value.m_structure.toStructureSet()); >+ break; >+ } >+ >+ case FilterInByIdStatus: { >+ AbstractValue& value = forNode(node->child1()); >+ if (value.m_structure.isFinite()) >+ node->inByIdStatus()->filter(value.m_structure.toStructureSet()); >+ break; >+ } >+ >+ case FilterPutByIdStatus: { >+ AbstractValue& value = forNode(node->child1()); >+ if (value.m_structure.isFinite()) >+ node->putByIdStatus()->filter(value.m_structure.toStructureSet()); >+ break; >+ } >+ >+ default: >+ RELEASE_ASSERT_NOT_REACHED(); >+ break; >+ } >+} >+ >+template<typename AbstractStateType> > bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned indexInBlock) > { > return executeEffects(indexInBlock, m_state.block()->at(indexInBlock)); >Index: Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (working copy) >@@ -1080,9 +1080,8 @@ private: > // code block had gathered. > LazyOperandValueProfileParser m_lazyOperands; > >- CallLinkInfoMap m_callLinkInfos; >- StubInfoMap m_stubInfos; >- ByValInfoMap m_byValInfos; >+ ICStatusMap m_baselineMap; >+ ICStatusContext m_optimizedContext; > > // Pointers to the argument position trackers for this slice of code. > Vector<ArgumentPosition*> m_argumentPositions; >@@ -1100,10 +1099,7 @@ private: > InlineCallFrame::Kind, > BasicBlock* continuationBlock); > >- ~InlineStackEntry() >- { >- m_byteCodeParser->m_inlineStackTop = m_caller; >- } >+ ~InlineStackEntry(); > > VirtualRegister remapOperand(VirtualRegister operand) const > { >@@ -1118,6 +1114,8 @@ private: > > InlineStackEntry* m_inlineStackTop; > >+ ICStatusContextStack m_icContextStack; >+ > struct DelayedSetLocal { > CodeOrigin m_origin; > VirtualRegister m_operand; >@@ -1144,10 +1142,6 @@ private: > > Vector<DelayedSetLocal, 2> m_setLocalQueue; > >- CodeBlock* m_dfgCodeBlock; >- CallLinkStatus::ContextMap m_callContextMap; >- StubInfoMap m_dfgStubInfos; >- > Instruction* m_currentInstruction; > bool m_hasDebuggerEnabled; > }; >@@ -1212,7 +1206,7 @@ ByteCodeParser::Terminality ByteCodePars > > CallLinkStatus callLinkStatus = CallLinkStatus::computeFor( > m_inlineStackTop->m_profiledBlock, currentCodeOrigin(), >- m_inlineStackTop->m_callLinkInfos, m_callContextMap); >+ m_inlineStackTop->m_baselineMap, m_icContextStack); > > InlineCallFrame::Kind kind = InlineCallFrame::kindFor(callMode); > >@@ -1240,6 +1234,8 @@ ByteCodeParser::Terminality ByteCodePars > // If we have profiling information about this call, and it did not behave too polymorphically, > // we may be able to inline it, or in the case of recursive tail calls turn it into a jump. > if (callLinkStatus.canOptimize()) { >+ addToGraph(FilterCallLinkStatus, OpInfo(m_graph.m_plan.recordedStatuses.addCallLinkStatus(currentCodeOrigin(), callLinkStatus)), callTarget); >+ > VirtualRegister thisArgument = virtualRegisterForArgument(0, registerOffset); > auto optimizationResult = handleInlining(callTarget, result, callLinkStatus, registerOffset, thisArgument, > argumentCountIncludingThis, m_currentIndex + instructionSize, op, kind, prediction); >@@ -1277,12 +1273,14 @@ ByteCodeParser::Terminality ByteCodePars > > CallLinkStatus callLinkStatus = CallLinkStatus::computeFor( > m_inlineStackTop->m_profiledBlock, currentCodeOrigin(), >- m_inlineStackTop->m_callLinkInfos, m_callContextMap); >+ m_inlineStackTop->m_baselineMap, m_icContextStack); > refineStatically(callLinkStatus, callTarget); > > VERBOSE_LOG(" Varargs call link status at ", currentCodeOrigin(), ": ", callLinkStatus, "\n"); > > if (callLinkStatus.canOptimize()) { >+ addToGraph(FilterCallLinkStatus, OpInfo(m_graph.m_plan.recordedStatuses.addCallLinkStatus(currentCodeOrigin(), callLinkStatus)), callTarget); >+ > if (handleVarargsInlining(callTarget, result, > callLinkStatus, firstFreeReg, VirtualRegister(thisReg), VirtualRegister(arguments), > firstVarArgOffset, op, >@@ -3316,9 +3314,12 @@ bool ByteCodeParser::handleDOMJITGetter( > if (!check(variant.conditionSet())) > return false; > addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.structureSet())), thisNode); >- >+ > // We do not need to emit CheckCell thingy here. When the custom accessor is replaced to different one, Structure transition occurs. > addToGraph(CheckSubClass, OpInfo(domAttribute.classInfo), thisNode); >+ >+ bool wasSeenInJIT = true; >+ addToGraph(FilterGetByIdStatus, OpInfo(m_graph.m_plan.recordedStatuses.addGetByIdStatus(currentCodeOrigin(), GetByIdStatus(GetByIdStatus::Custom, wasSeenInJIT, variant))), thisNode); > > CallDOMGetterData* callDOMGetterData = m_graph.m_callDOMGetterData.add(); > callDOMGetterData->customAccessorGetter = variant.customAccessorGetter(); >@@ -3350,6 +3351,8 @@ bool ByteCodeParser::handleModuleNamespa > if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCell)) > return false; > addToGraph(CheckCell, OpInfo(m_graph.freeze(getById.moduleNamespaceObject())), Edge(base, CellUse)); >+ >+ addToGraph(FilterGetByIdStatus, OpInfo(m_graph.m_plan.recordedStatuses.addGetByIdStatus(currentCodeOrigin(), getById)), base); > > // Ideally we wouldn't have to do this Phantom. But: > // >@@ -4005,14 +4008,21 @@ void ByteCodeParser::handleGetById( > return; > } > >+ // FIXME: If we use the GetByIdStatus for anything then we should record it and insert a node >+ // after everything else (like the GetByOffset or whatever) that will filter the recorded >+ // GetByIdStatus. That means that the constant folder also needs to do the same! >+ > if (getByIdStatus.numVariants() > 1) { > if (getByIdStatus.makesCalls() || !isFTL(m_graph.m_plan.mode) >- || !Options::usePolymorphicAccessInlining()) { >+ || !Options::usePolymorphicAccessInlining() >+ || getByIdStatus.numVariants() > Options::maxPolymorphicAccessInliningListSize()) { > set(VirtualRegister(destinationOperand), > addToGraph(getById, OpInfo(identifierNumber), OpInfo(prediction), base)); > return; > } > >+ addToGraph(FilterGetByIdStatus, OpInfo(m_graph.m_plan.recordedStatuses.addGetByIdStatus(currentCodeOrigin(), getByIdStatus)), base); >+ > Vector<MultiGetByOffsetCase, 2> cases; > > // 1) Emit prototype structure checks for all chains. This could sort of maybe not be >@@ -4054,10 +4064,12 @@ void ByteCodeParser::handleGetById( > addToGraph(MultiGetByOffset, OpInfo(data), OpInfo(prediction), base)); > return; > } >+ >+ addToGraph(FilterGetByIdStatus, OpInfo(m_graph.m_plan.recordedStatuses.addGetByIdStatus(currentCodeOrigin(), getByIdStatus)), base); > > ASSERT(getByIdStatus.numVariants() == 1); > GetByIdVariant variant = getByIdStatus[0]; >- >+ > Node* loadedValue = load(prediction, base, identifierNumber, variant); > if (!loadedValue) { > set(VirtualRegister(destinationOperand), >@@ -4148,7 +4160,8 @@ void ByteCodeParser::handlePutById( > > if (putByIdStatus.numVariants() > 1) { > if (!isFTL(m_graph.m_plan.mode) || putByIdStatus.makesCalls() >- || !Options::usePolymorphicAccessInlining()) { >+ || !Options::usePolymorphicAccessInlining() >+ || putByIdStatus.numVariants() > Options::maxPolymorphicAccessInliningListSize()) { > emitPutById(base, identifierNumber, value, putByIdStatus, isDirect); > return; > } >@@ -4166,6 +4179,8 @@ void ByteCodeParser::handlePutById( > > if (UNLIKELY(m_graph.compilation())) > m_graph.compilation()->noticeInlinedPutById(); >+ >+ addToGraph(FilterPutByIdStatus, OpInfo(m_graph.m_plan.recordedStatuses.addPutByIdStatus(currentCodeOrigin(), putByIdStatus)), base); > > for (const PutByIdVariant& variant : putByIdStatus.variants()) { > m_graph.registerInferredType(variant.requiredType()); >@@ -4187,6 +4202,8 @@ void ByteCodeParser::handlePutById( > > switch (variant.kind()) { > case PutByIdVariant::Replace: { >+ addToGraph(FilterPutByIdStatus, OpInfo(m_graph.m_plan.recordedStatuses.addPutByIdStatus(currentCodeOrigin(), putByIdStatus)), base); >+ > store(base, identifierNumber, variant, value); > if (UNLIKELY(m_graph.compilation())) > m_graph.compilation()->noticeInlinedPutById(); >@@ -4194,6 +4211,8 @@ void ByteCodeParser::handlePutById( > } > > case PutByIdVariant::Transition: { >+ addToGraph(FilterPutByIdStatus, OpInfo(m_graph.m_plan.recordedStatuses.addPutByIdStatus(currentCodeOrigin(), putByIdStatus)), base); >+ > addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.oldStructure())), base); > if (!check(variant.conditionSet())) { > emitPutById(base, identifierNumber, value, putByIdStatus, isDirect); >@@ -4261,6 +4280,8 @@ void ByteCodeParser::handlePutById( > } > > case PutByIdVariant::Setter: { >+ addToGraph(FilterPutByIdStatus, OpInfo(m_graph.m_plan.recordedStatuses.addPutByIdStatus(currentCodeOrigin(), putByIdStatus)), base); >+ > Node* loadedValue = load(SpecCellOther, base, identifierNumber, variant); > if (!loadedValue) { > emitPutById(base, identifierNumber, value, putByIdStatus, isDirect); >@@ -4497,6 +4518,7 @@ void ByteCodeParser::parseBlock(unsigned > > m_graph.freeze(rareData); > m_graph.watchpoints().addLazily(rareData->allocationProfileWatchpointSet()); >+ > // The callee is still live up to this point. > addToGraph(Phantom, callee); > Node* object = addToGraph(NewObject, OpInfo(m_graph.registerStructure(structure))); >@@ -4792,7 +4814,7 @@ void ByteCodeParser::parseBlock(unsigned > auto& bytecode = *reinterpret_cast<OpInstanceof*>(currentInstruction); > > InstanceOfStatus status = InstanceOfStatus::computeFor( >- m_inlineStackTop->m_profiledBlock, m_inlineStackTop->m_stubInfos, >+ m_inlineStackTop->m_profiledBlock, m_inlineStackTop->m_baselineMap, > m_currentIndex); > > Node* value = get(VirtualRegister(bytecode.value())); >@@ -5031,7 +5053,7 @@ void ByteCodeParser::parseBlock(unsigned > unsigned identifierNumber = 0; > { > ConcurrentJSLocker locker(m_inlineStackTop->m_profiledBlock->m_lock); >- ByValInfo* byValInfo = m_inlineStackTop->m_byValInfos.get(CodeOrigin(currentCodeOrigin().bytecodeIndex)); >+ ByValInfo* byValInfo = m_inlineStackTop->m_baselineMap.get(CodeOrigin(currentCodeOrigin().bytecodeIndex)).byValInfo; > // FIXME: When the bytecode is not compiled in the baseline JIT, byValInfo becomes null. > // At that time, there is no information. > if (byValInfo >@@ -5100,7 +5122,7 @@ void ByteCodeParser::parseBlock(unsigned > PutByIdStatus putByIdStatus; > { > ConcurrentJSLocker locker(m_inlineStackTop->m_profiledBlock->m_lock); >- ByValInfo* byValInfo = m_inlineStackTop->m_byValInfos.get(CodeOrigin(currentCodeOrigin().bytecodeIndex)); >+ ByValInfo* byValInfo = m_inlineStackTop->m_baselineMap.get(CodeOrigin(currentCodeOrigin().bytecodeIndex)).byValInfo; > // FIXME: When the bytecode is not compiled in the baseline JIT, byValInfo becomes null. > // At that time, there is no information. > if (byValInfo >@@ -5206,8 +5228,8 @@ void ByteCodeParser::parseBlock(unsigned > > UniquedStringImpl* uid = m_graph.identifiers()[identifierNumber]; > GetByIdStatus getByIdStatus = GetByIdStatus::computeFor( >- m_inlineStackTop->m_profiledBlock, m_dfgCodeBlock, >- m_inlineStackTop->m_stubInfos, m_dfgStubInfos, >+ m_inlineStackTop->m_profiledBlock, >+ m_inlineStackTop->m_baselineMap, m_icContextStack, > currentCodeOrigin(), uid); > > AccessType type = AccessType::Get; >@@ -5250,8 +5272,8 @@ void ByteCodeParser::parseBlock(unsigned > bool direct = currentInstruction[8].u.putByIdFlags & PutByIdIsDirect; > > PutByIdStatus putByIdStatus = PutByIdStatus::computeFor( >- m_inlineStackTop->m_profiledBlock, m_dfgCodeBlock, >- m_inlineStackTop->m_stubInfos, m_dfgStubInfos, >+ m_inlineStackTop->m_profiledBlock, >+ m_inlineStackTop->m_baselineMap, m_icContextStack, > currentCodeOrigin(), m_graph.identifiers()[identifierNumber]); > > handlePutById(base, identifierNumber, value, putByIdStatus, direct); >@@ -6433,8 +6455,8 @@ void ByteCodeParser::parseBlock(unsigned > UniquedStringImpl* uid = m_graph.identifiers()[identifierNumber]; > > InByIdStatus status = InByIdStatus::computeFor( >- m_inlineStackTop->m_profiledBlock, m_dfgCodeBlock, >- m_inlineStackTop->m_stubInfos, m_dfgStubInfos, >+ m_inlineStackTop->m_profiledBlock, >+ m_inlineStackTop->m_baselineMap, m_icContextStack, > currentCodeOrigin(), uid); > > if (status.isSimple()) { >@@ -6455,6 +6477,8 @@ void ByteCodeParser::parseBlock(unsigned > } > > if (allOK) { >+ addToGraph(FilterInByIdStatus, OpInfo(m_graph.m_plan.recordedStatuses.addInByIdStatus(currentCodeOrigin(), status)), base); >+ > Node* match = addToGraph(MatchStructure, OpInfo(data), base); > set(VirtualRegister(currentInstruction[1].u.operand), match); > NEXT_OPCODE(op_in_by_id); >@@ -6639,12 +6663,19 @@ ByteCodeParser::InlineStackEntry::Inline > // We do this while holding the lock because we want to encourage StructureStubInfo's > // to be potentially added to operations and because the profiled block could be in the > // middle of LLInt->JIT tier-up in which case we would be adding the info's right now. >- if (m_profiledBlock->hasBaselineJITProfiling()) { >- m_profiledBlock->getStubInfoMap(locker, m_stubInfos); >- m_profiledBlock->getCallLinkInfoMap(locker, m_callLinkInfos); >- m_profiledBlock->getByValInfoMap(locker, m_byValInfos); >+ if (m_profiledBlock->hasBaselineJITProfiling()) >+ m_profiledBlock->getICStatusMap(locker, m_baselineMap); >+ } >+ >+ if (Options::usePolyvariantDevirtualization()) { >+ CodeBlock* optimizedBlock = m_profiledBlock->replacement(); >+ m_optimizedContext.optimizedCodeBlock = optimizedBlock; >+ if (optimizedBlock) { >+ ConcurrentJSLocker locker(optimizedBlock->m_lock); >+ optimizedBlock->getICStatusMap(locker, m_optimizedContext.map); > } > } >+ byteCodeParser->m_icContextStack.append(&m_optimizedContext); > > int argumentCountIncludingThisWithFixup = std::max<int>(argumentCountIncludingThis, codeBlock->numParameters()); > >@@ -6654,6 +6685,7 @@ ByteCodeParser::InlineStackEntry::Inline > ASSERT(inlineCallFrameStart.isValid()); > > m_inlineCallFrame = byteCodeParser->m_graph.m_plan.inlineCallFrames->add(); >+ m_optimizedContext.inlineCallFrame = m_inlineCallFrame; > > // The owner is the machine code block, and we already have a barrier on that when the > // plan finishes. >@@ -6709,6 +6741,13 @@ ByteCodeParser::InlineStackEntry::Inline > byteCodeParser->m_inlineStackTop = this; > } > >+ByteCodeParser::InlineStackEntry::~InlineStackEntry() >+{ >+ m_byteCodeParser->m_inlineStackTop = m_caller; >+ RELEASE_ASSERT(m_byteCodeParser->m_icContextStack.last() == &m_optimizedContext); >+ m_byteCodeParser->m_icContextStack.removeLast(); >+} >+ > void ByteCodeParser::parseCodeBlock() > { > clearCaches(); >@@ -6805,15 +6844,6 @@ void ByteCodeParser::parse() > > VERBOSE_LOG("Parsing ", *m_codeBlock, "\n"); > >- m_dfgCodeBlock = m_graph.m_plan.profiledDFGCodeBlock; >- if (isFTL(m_graph.m_plan.mode) && m_dfgCodeBlock >- && Options::usePolyvariantDevirtualization()) { >- if (Options::usePolyvariantCallInlining()) >- CallLinkStatus::computeDFGStatuses(m_dfgCodeBlock, m_callContextMap); >- if (Options::usePolyvariantByIdInlining()) >- m_dfgCodeBlock->getStubInfoMap(m_dfgStubInfos); >- } >- > InlineStackEntry inlineStackEntry( > this, m_codeBlock, m_profiledBlock, 0, VirtualRegister(), VirtualRegister(), > m_codeBlock->numParameters(), InlineCallFrame::Call, nullptr); >Index: Source/JavaScriptCore/dfg/DFGClobberize.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGClobberize.h (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGClobberize.h (working copy) >@@ -446,6 +446,10 @@ void clobberize(Graph& graph, Node* node > case ProfileControlFlow: > case PutHint: > case InitializeEntrypointArguments: >+ case FilterCallLinkStatus: >+ case FilterGetByIdStatus: >+ case FilterPutByIdStatus: >+ case FilterInByIdStatus: > write(SideState); > return; > >Index: Source/JavaScriptCore/dfg/DFGClobbersExitState.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGClobbersExitState.cpp (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGClobbersExitState.cpp (working copy) >@@ -75,6 +75,10 @@ bool clobbersExitState(Graph& graph, Nod > case FencedStoreBarrier: > case AllocatePropertyStorage: > case ReallocatePropertyStorage: >+ case FilterCallLinkStatus: >+ case FilterGetByIdStatus: >+ case FilterPutByIdStatus: >+ case FilterInByIdStatus: > // These do clobber memory, but nothing that is observable. It may be nice to separate the > // heaps into those that are observable and those that aren't, but we don't do that right now. > // FIXME: https://bugs.webkit.org/show_bug.cgi?id=148440 >Index: Source/JavaScriptCore/dfg/DFGCommonData.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGCommonData.h (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGCommonData.h (working copy) >@@ -35,6 +35,7 @@ > #include "InlineCallFrameSet.h" > #include "JSCast.h" > #include "ProfilerCompilation.h" >+#include "RecordedStatuses.h" > #include <wtf/Bag.h> > #include <wtf/Noncopyable.h> > >@@ -125,6 +126,7 @@ public: > Bag<CodeBlockJettisoningWatchpoint> watchpoints; > Bag<AdaptiveStructureWatchpoint> adaptiveStructureWatchpoints; > Bag<AdaptiveInferredPropertyValueWatchpoint> adaptiveInferredPropertyValueWatchpoints; >+ RecordedStatuses recordedStatuses; > Vector<JumpReplacement> jumpReplacements; > > ScratchBuffer* catchOSREntryBuffer; >Index: Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp (working copy) >@@ -557,7 +557,15 @@ private: > } > } > >+ auto addFilterStatus = [&] () { >+ m_insertionSet.insertNode( >+ indexInBlock, SpecNone, FilterGetByIdStatus, node->origin, >+ OpInfo(m_graph.m_plan.recordedStatuses.addGetByIdStatus(node->origin.semantic, status)), >+ Edge(child)); >+ }; >+ > if (status.numVariants() == 1) { >+ addFilterStatus(); > emitGetByOffset(indexInBlock, node, baseValue, status[0], identifierNumber); > changed = true; > break; >@@ -566,6 +574,7 @@ private: > if (!isFTL(m_graph.m_plan.mode)) > break; > >+ addFilterStatus(); > MultiGetByOffsetData* data = m_graph.m_multiGetByOffsetData.add(); > for (const GetByIdVariant& variant : status.variants()) { > data->cases.append( >@@ -639,6 +648,11 @@ private: > if (!allGood) > break; > >+ m_insertionSet.insertNode( >+ indexInBlock, SpecNone, FilterPutByIdStatus, node->origin, >+ OpInfo(m_graph.m_plan.recordedStatuses.addPutByIdStatus(node->origin.semantic, status)), >+ Edge(child)); >+ > if (status.numVariants() == 1) { > emitPutByOffset(indexInBlock, node, baseValue, status[0], identifierNumber); > break; >Index: Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h (working copy) >@@ -46,7 +46,10 @@ struct SetPointerAdaptor { > { > return set->add(common.watchpoints.add(codeBlock)); > } >- static bool hasBeenInvalidated(T set) { return set->hasBeenInvalidated(); } >+ static bool hasBeenInvalidated(T set) >+ { >+ return set->hasBeenInvalidated(); >+ } > static void dumpInContext(PrintStream& out, T set, DumpContext*) > { > out.print(RawPointer(set)); >Index: Source/JavaScriptCore/dfg/DFGDoesGC.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGDoesGC.cpp (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGDoesGC.cpp (working copy) >@@ -313,6 +313,10 @@ bool doesGC(Graph& graph, Node* node) > case AtomicsXor: > case AtomicsIsLockFree: > case MatchStructure: >+ case FilterCallLinkStatus: >+ case FilterGetByIdStatus: >+ case FilterPutByIdStatus: >+ case FilterInByIdStatus: > return false; > > case PushWithScope: >Index: Source/JavaScriptCore/dfg/DFGFixupPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (working copy) >@@ -2173,6 +2173,10 @@ private: > case GetGlobalThis: > case ExtractValueFromWeakMapGet: > case CPUIntrinsic: >+ case FilterCallLinkStatus: >+ case FilterGetByIdStatus: >+ case FilterPutByIdStatus: >+ case FilterInByIdStatus: > break; > #else > default: >Index: Source/JavaScriptCore/dfg/DFGGraph.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGGraph.cpp (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGGraph.cpp (working copy) >@@ -356,6 +356,14 @@ void Graph::dump(PrintStream& out, const > out.print(comma, "ignoreLastIndexIsWritable = ", node->ignoreLastIndexIsWritable()); > if (node->isConstant()) > out.print(comma, pointerDumpInContext(node->constant(), context)); >+ if (node->hasCallLinkStatus()) >+ out.print(comma, *node->callLinkStatus()); >+ if (node->hasGetByIdStatus()) >+ out.print(comma, *node->getByIdStatus()); >+ if (node->hasInByIdStatus()) >+ out.print(comma, *node->inByIdStatus()); >+ if (node->hasPutByIdStatus()) >+ out.print(comma, *node->putByIdStatus()); > if (node->isJump()) > out.print(comma, "T:", *node->targetBlock()); > if (node->isBranch()) >Index: Source/JavaScriptCore/dfg/DFGMayExit.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGMayExit.cpp (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGMayExit.cpp (working copy) >@@ -101,6 +101,10 @@ ExitMode mayExitImpl(Graph& graph, Node* > case PutClosureVar: > case RecordRegExpCachedResult: > case NukeStructureAndSetButterfly: >+ case FilterCallLinkStatus: >+ case FilterGetByIdStatus: >+ case FilterPutByIdStatus: >+ case FilterInByIdStatus: > break; > > case StrCat: >Index: Source/JavaScriptCore/dfg/DFGNode.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGNode.h (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGNode.h (working copy) >@@ -2769,6 +2769,50 @@ public: > ASSERT(op() == ThrowStaticError); > return m_opInfo.as<uint32_t>(); > } >+ >+ bool hasCallLinkStatus() >+ { >+ return op() == FilterCallLinkStatus; >+ } >+ >+ CallLinkStatus* callLinkStatus() >+ { >+ ASSERT(hasCallLinkStatus()); >+ return m_opInfo.as<CallLinkStatus*>(); >+ } >+ >+ bool hasGetByIdStatus() >+ { >+ return op() == FilterGetByIdStatus; >+ } >+ >+ GetByIdStatus* getByIdStatus() >+ { >+ ASSERT(hasGetByIdStatus()); >+ return m_opInfo.as<GetByIdStatus*>(); >+ } >+ >+ bool hasInByIdStatus() >+ { >+ return op() == FilterInByIdStatus; >+ } >+ >+ InByIdStatus* inByIdStatus() >+ { >+ ASSERT(hasInByIdStatus()); >+ return m_opInfo.as<InByIdStatus*>(); >+ } >+ >+ bool hasPutByIdStatus() >+ { >+ return op() == FilterPutByIdStatus; >+ } >+ >+ PutByIdStatus* putByIdStatus() >+ { >+ ASSERT(hasPutByIdStatus()); >+ return m_opInfo.as<PutByIdStatus*>(); >+ } > > void dumpChildren(PrintStream& out) > { >Index: Source/JavaScriptCore/dfg/DFGNodeType.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGNodeType.h (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGNodeType.h (working copy) >@@ -397,11 +397,8 @@ namespace JSC { namespace DFG { > macro(GetArgument, NodeResultJS) \ > \ > macro(NewFunction, NodeResultJS) \ >- \ > macro(NewGeneratorFunction, NodeResultJS) \ >- \ > macro(NewAsyncGeneratorFunction, NodeResultJS) \ >- \ > macro(NewAsyncFunction, NodeResultJS) \ > \ > /* Block terminals. */\ >@@ -478,6 +475,12 @@ namespace JSC { namespace DFG { > \ > /* Used for $vm performance debugging */ \ > macro(CPUIntrinsic, NodeResultJS | NodeMustGenerate) \ >+ \ >+ /* Used to provide feedback to the IC profiler. */ \ >+ macro(FilterCallLinkStatus, NodeMustGenerate) \ >+ macro(FilterGetByIdStatus, NodeMustGenerate) \ >+ macro(FilterInByIdStatus, NodeMustGenerate) \ >+ macro(FilterPutByIdStatus, NodeMustGenerate) \ > > > // This enum generates a monotonically increasing id for all Node types, >Index: Source/JavaScriptCore/dfg/DFGOSRExitBase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGOSRExitBase.cpp (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGOSRExitBase.cpp (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2013, 2016 Apple Inc. All rights reserved. >+ * Copyright (C) 2013-2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -42,11 +42,17 @@ void OSRExitBase::considerAddingAsFreque > baselineCodeBlockForOriginAndBaselineCodeBlock( > m_codeOriginForExitProfile, profiledCodeBlock); > if (sourceProfiledCodeBlock) { >+ ExitingInlineKind inlineKind; >+ if (m_codeOriginForExitProfile.inlineCallFrame) >+ inlineKind = ExitFromInlined; >+ else >+ inlineKind = ExitFromNotInlined; >+ > FrequentExitSite site; > if (m_wasHoisted) >- site = FrequentExitSite(HoistingFailed, jitType); >+ site = FrequentExitSite(HoistingFailed, jitType, inlineKind); > else >- site = FrequentExitSite(m_codeOriginForExitProfile.bytecodeIndex, m_kind, jitType); >+ site = FrequentExitSite(m_codeOriginForExitProfile.bytecodeIndex, m_kind, jitType, inlineKind); > ExitProfile::add(sourceProfiledCodeBlock, site); > } > } >Index: Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp (working copy) >@@ -756,6 +756,7 @@ private: > } > > promoteLocalHeap(); >+ removeICStatusFilters(); > > if (Options::validateGraphAtEachPhase()) > DFG::validate(m_graph, DumpGraph, graphBeforeSinking); >@@ -1088,6 +1089,12 @@ private: > case PutHint: > // Handled by OSR availability analysis > break; >+ >+ case FilterCallLinkStatus: >+ case FilterGetByIdStatus: >+ case FilterPutByIdStatus: >+ case FilterInByIdStatus: >+ break; > > default: > m_graph.doToChildren( >@@ -2331,6 +2338,25 @@ private: > > RELEASE_ASSERT_NOT_REACHED(); > } >+ >+ void removeICStatusFilters() >+ { >+ for (BasicBlock* block : m_graph.blocksInNaturalOrder()) { >+ for (Node* node : *block) { >+ switch (node->op()) { >+ case FilterCallLinkStatus: >+ case FilterGetByIdStatus: >+ case FilterPutByIdStatus: >+ case FilterInByIdStatus: >+ if (node->child1()->isPhantomAllocation()) >+ node->removeWithoutChecks(); >+ break; >+ default: >+ break; >+ } >+ } >+ } >+ } > > // This is a great way of asking value->isStillValid() without having to worry about getting > // different answers. It turns out that this analysis works OK regardless of what this >Index: Source/JavaScriptCore/dfg/DFGPlan.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGPlan.cpp (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGPlan.cpp (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2013-2017 Apple Inc. All rights reserved. >+ * Copyright (C) 2013-2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -555,6 +555,7 @@ void Plan::reallyAdd(CommonData* commonD > identifiers.reallyAdd(*vm, commonData); > weakReferences.reallyAdd(*vm, commonData); > transitions.reallyAdd(*vm, commonData); >+ commonData->recordedStatuses = WTFMove(recordedStatuses); > } > > void Plan::notifyCompiling() >@@ -633,6 +634,8 @@ void Plan::checkLivenessAndVisitChildren > cleanMustHandleValuesIfNecessary(); > for (unsigned i = mustHandleValues.size(); i--;) > visitor.appendUnbarriered(mustHandleValues[i]); >+ >+ recordedStatuses.markIfCheap(visitor); > > visitor.appendUnbarriered(codeBlock); > visitor.appendUnbarriered(codeBlock->alternative()); >@@ -649,6 +652,11 @@ void Plan::checkLivenessAndVisitChildren > transitions.visitChildren(visitor); > } > >+void Plan::finalizeInGC() >+{ >+ recordedStatuses.finalizeWithoutDeleting(); >+} >+ > bool Plan::isKnownToBeLiveDuringGC() > { > if (stage == Cancelled) >Index: Source/JavaScriptCore/dfg/DFGPlan.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGPlan.h (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGPlan.h (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2013-2017 Apple Inc. All rights reserved. >+ * Copyright (C) 2013-2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -36,6 +36,7 @@ > #include "DeferredCompilationCallback.h" > #include "Operands.h" > #include "ProfilerCompilation.h" >+#include "RecordedStatuses.h" > #include <wtf/HashMap.h> > #include <wtf/ThreadSafeRefCounted.h> > >@@ -72,6 +73,7 @@ struct Plan : public ThreadSafeRefCounte > void iterateCodeBlocksForGC(const Func&); > void checkLivenessAndVisitChildren(SlotVisitor&); > bool isKnownToBeLiveDuringGC(); >+ void finalizeInGC(); > void cancel(); > > bool canTierUpAndOSREnter() const { return !tierUpAndOSREnterBytecodes.isEmpty(); } >@@ -104,6 +106,7 @@ struct Plan : public ThreadSafeRefCounte > DesiredIdentifiers identifiers; > DesiredWeakReferences weakReferences; > DesiredTransitions transitions; >+ RecordedStatuses recordedStatuses; > > bool willTryToTierUp { false }; > >Index: Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (working copy) >@@ -1213,6 +1213,10 @@ private: > case InitializeEntrypointArguments: > case WeakSetAdd: > case WeakMapSet: >+ case FilterCallLinkStatus: >+ case FilterGetByIdStatus: >+ case FilterPutByIdStatus: >+ case FilterInByIdStatus: > break; > > // This gets ignored because it only pretends to produce a value. >Index: Source/JavaScriptCore/dfg/DFGSafeToExecute.h >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSafeToExecute.h (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGSafeToExecute.h (working copy) >@@ -479,6 +479,14 @@ bool safeToExecute(AbstractStateType& st > // already force these things to be ordered precisely. I'm just not confident enough in my > // effect based memory model to rely solely on that right now. > return false; >+ >+ case FilterCallLinkStatus: >+ case FilterGetByIdStatus: >+ case FilterPutByIdStatus: >+ case FilterInByIdStatus: >+ // We don't want these to be moved anywhere other than where we put them, since we want them >+ // to capture "profiling" at the point in control flow here the user put them. >+ return false; > > case GetByVal: > case GetIndexedPropertyStorage: >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (working copy) >@@ -4037,6 +4037,14 @@ void SpeculativeJIT::compile(Node* node) > case CheckStructureOrEmpty: > DFG_CRASH(m_jit.graph(), node, "CheckStructureOrEmpty only used in 64-bit DFG"); > break; >+ >+ case FilterCallLinkStatus: >+ case FilterGetByIdStatus: >+ case FilterPutByIdStatus: >+ case FilterInByIdStatus: >+ m_interpreter.filterICStatus(node); >+ noResult(node); >+ break; > > case LastNodeType: > case Phi: >Index: Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (working copy) >@@ -4630,6 +4630,14 @@ void SpeculativeJIT::compile(Node* node) > break; > } > >+ case FilterCallLinkStatus: >+ case FilterGetByIdStatus: >+ case FilterPutByIdStatus: >+ case FilterInByIdStatus: >+ m_interpreter.filterICStatus(node); >+ noResult(node); >+ break; >+ > #else // ENABLE(FTL_JIT) > case CheckTierUpInLoop: > case CheckTierUpAtReturn: >Index: Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGStrengthReductionPhase.cpp (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2013-2016 Apple Inc. All rights reserved. >+ * Copyright (C) 2013-2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -898,10 +898,14 @@ private: > case TailCall: { > ExecutableBase* executable = nullptr; > Edge callee = m_graph.varArgChild(m_node, 0); >- if (JSFunction* function = callee->dynamicCastConstant<JSFunction*>(vm())) >+ CallVariant callVariant; >+ if (JSFunction* function = callee->dynamicCastConstant<JSFunction*>(vm())) { > executable = function->executable(); >- else if (callee->isFunctionAllocation()) >+ callVariant = CallVariant(function); >+ } else if (callee->isFunctionAllocation()) { > executable = callee->castOperand<FunctionExecutable*>(); >+ callVariant = CallVariant(executable); >+ } > > if (!executable) > break; >@@ -919,6 +923,8 @@ private: > } > } > >+ m_graph.m_plan.recordedStatuses.addCallLinkStatus(m_node->origin.semantic, CallLinkStatus(callVariant)); >+ > m_node->convertToDirectCall(m_graph.freeze(executable)); > m_changed = true; > break; >Index: Source/JavaScriptCore/dfg/DFGWorklist.cpp >=================================================================== >--- Source/JavaScriptCore/dfg/DFGWorklist.cpp (revision 232441) >+++ Source/JavaScriptCore/dfg/DFGWorklist.cpp (working copy) >@@ -393,8 +393,10 @@ void Worklist::removeDeadPlans(VM& vm) > Plan* plan = iter->value.get(); > if (plan->vm != &vm) > continue; >- if (plan->isKnownToBeLiveDuringGC()) >+ if (plan->isKnownToBeLiveDuringGC()) { >+ plan->finalizeInGC(); > continue; >+ } > RELEASE_ASSERT(plan->stage != Plan::Cancelled); // Should not be cancelled, yet. > ASSERT(!deadPlanKeys.contains(plan->key())); > deadPlanKeys.add(plan->key()); >Index: Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h >=================================================================== >--- Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h (revision 232441) >+++ Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h (working copy) >@@ -56,6 +56,8 @@ namespace JSC { namespace FTL { > macro(DirectArguments_minCapacity, DirectArguments::offsetOfMinCapacity()) \ > macro(DirectArguments_mappedArguments, DirectArguments::offsetOfMappedArguments()) \ > macro(DirectArguments_modifiedArgumentsDescriptor, DirectArguments::offsetOfModifiedArgumentsDescriptor()) \ >+ macro(FunctionRareData_allocator, FunctionRareData::offsetOfObjectAllocationProfile() + ObjectAllocationProfile::offsetOfAllocator()) \ >+ macro(FunctionRareData_structure, FunctionRareData::offsetOfObjectAllocationProfile() + ObjectAllocationProfile::offsetOfStructure()) \ > macro(GetterSetter_getter, GetterSetter::offsetOfGetter()) \ > macro(GetterSetter_setter, GetterSetter::offsetOfSetter()) \ > macro(JSArrayBufferView_length, JSArrayBufferView::offsetOfLength()) \ >@@ -112,10 +114,10 @@ namespace JSC { namespace FTL { > macro(StringImpl_length, StringImpl::lengthMemoryOffset()) \ > macro(Structure_classInfo, Structure::classInfoOffset()) \ > macro(Structure_globalObject, Structure::globalObjectOffset()) \ >+ macro(Structure_indexingModeIncludingHistory, Structure::indexingModeIncludingHistoryOffset()) \ >+ macro(Structure_inlineCapacity, Structure::inlineCapacityOffset()) \ > macro(Structure_prototype, Structure::prototypeOffset()) \ > macro(Structure_structureID, Structure::structureIDOffset()) \ >- macro(Structure_inlineCapacity, Structure::inlineCapacityOffset()) \ >- macro(Structure_indexingModeIncludingHistory, Structure::indexingModeIncludingHistoryOffset()) \ > macro(HashMapImpl_capacity, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfCapacity()) \ > macro(HashMapImpl_buffer, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfBuffer()) \ > macro(HashMapImpl_head, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfHead()) \ >Index: Source/JavaScriptCore/ftl/FTLCapabilities.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLCapabilities.cpp (revision 232441) >+++ Source/JavaScriptCore/ftl/FTLCapabilities.cpp (working copy) >@@ -352,6 +352,11 @@ inline CapabilityLevel canCompile(Node* > case PutByValDirect: > case PutByValWithThis: > case MatchStructure: >+ case CreateThis: >+ case FilterCallLinkStatus: >+ case FilterGetByIdStatus: >+ case FilterPutByIdStatus: >+ case FilterInByIdStatus: > // These are OK. > break; > >@@ -363,7 +368,6 @@ inline CapabilityLevel canCompile(Node* > break; > > case IdentityWithProfile: >- case CreateThis: > case CheckTierUpInLoop: > case CheckTierUpAndOSREnter: > case CheckTierUpAtReturn: >Index: Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp >=================================================================== >--- Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (revision 232441) >+++ Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (working copy) >@@ -850,6 +850,9 @@ private: > case NewArrayWithSpread: > compileNewArrayWithSpread(); > break; >+ case CreateThis: >+ compileCreateThis(); >+ break; > case Spread: > compileSpread(); > break; >@@ -1292,6 +1295,12 @@ private: > case CallDOMGetter: > compileCallDOMGetter(); > break; >+ case FilterCallLinkStatus: >+ case FilterGetByIdStatus: >+ case FilterPutByIdStatus: >+ case FilterInByIdStatus: >+ compileFilterICStatus(); >+ break; > > case PhantomLocal: > case LoopHint: >@@ -5670,6 +5679,40 @@ private: > > setJSValue(result); > } >+ >+ void compileCreateThis() >+ { >+ LValue callee = lowCell(m_node->child1()); >+ >+ LBasicBlock isFunctionBlock = m_out.newBlock(); >+ LBasicBlock hasRareData = m_out.newBlock(); >+ LBasicBlock slowPath = m_out.newBlock(); >+ LBasicBlock continuation = m_out.newBlock(); >+ >+ m_out.branch(isFunction(callee, provenType(m_node->child1())), usually(isFunctionBlock), rarely(slowPath)); >+ >+ LBasicBlock lastNext = m_out.appendTo(isFunctionBlock, hasRareData); >+ LValue rareData = m_out.loadPtr(callee, m_heaps.JSFunction_rareData); >+ m_out.branch(m_out.isZero64(rareData), rarely(slowPath), usually(hasRareData)); >+ >+ m_out.appendTo(hasRareData, slowPath); >+ LValue allocator = m_out.loadPtr(rareData, m_heaps.FunctionRareData_allocator); >+ LValue structure = m_out.loadPtr(rareData, m_heaps.FunctionRareData_structure); >+ LValue butterfly = m_out.constIntPtr(0); >+ ValueFromBlock fastResult = m_out.anchor(allocateObject(allocator, structure, butterfly, slowPath)); >+ m_out.jump(continuation); >+ >+ m_out.appendTo(slowPath, continuation); >+ ValueFromBlock slowResult = m_out.anchor(vmCall( >+ Int64, m_out.operation(operationCreateThis), m_callFrame, callee, m_out.constInt32(m_node->inlineCapacity()))); >+ m_out.jump(continuation); >+ >+ m_out.appendTo(continuation, lastNext); >+ LValue result = m_out.phi(Int64, fastResult, slowResult); >+ >+ mutatorFence(); >+ setJSValue(result); >+ } > > void compileSpread() > { >@@ -12136,6 +12179,11 @@ private: > setJSValue(patchpoint); > } > >+ void compileFilterICStatus() >+ { >+ m_interpreter.filterICStatus(m_node); >+ } >+ > void emitSwitchForMultiByOffset(LValue base, bool structuresChecked, Vector<SwitchCase, 2>& cases, LBasicBlock exit) > { > if (cases.isEmpty()) { >Index: Source/JavaScriptCore/jit/PolymorphicCallStubRoutine.cpp >=================================================================== >--- Source/JavaScriptCore/jit/PolymorphicCallStubRoutine.cpp (revision 232441) >+++ Source/JavaScriptCore/jit/PolymorphicCallStubRoutine.cpp (working copy) >@@ -96,10 +96,22 @@ CallVariantList PolymorphicCallStubRouti > return result; > } > >+bool PolymorphicCallStubRoutine::hasEdges() const >+{ >+ // The FTL does not count edges in its poly call stub routines. If the FTL went poly call, then >+ // it's not meaningful to keep profiling - we can just leave it at that. Remember, the FTL would >+ // have had full edge profiling from the DFG, and based on this information, it would have >+ // decided to go poly. >+ // >+ // There probably are very-difficult-to-imagine corner cases where the FTL not doing edge >+ // profiling is bad for polyvariant inlining. But polyvariant inlining is profitable sometimes >+ // while not having to increment counts is profitable always. So, we let the FTL run faster and >+ // not keep counts. >+ return !!m_fastCounts; >+} >+ > CallEdgeList PolymorphicCallStubRoutine::edges() const > { >- // We wouldn't have these if this was an FTL stub routine. We shouldn't be asking for profiling >- // from the FTL. > RELEASE_ASSERT(m_fastCounts); > > CallEdgeList result; >Index: Source/JavaScriptCore/jit/PolymorphicCallStubRoutine.h >=================================================================== >--- Source/JavaScriptCore/jit/PolymorphicCallStubRoutine.h (revision 232441) >+++ Source/JavaScriptCore/jit/PolymorphicCallStubRoutine.h (working copy) >@@ -90,6 +90,7 @@ public: > virtual ~PolymorphicCallStubRoutine(); > > CallVariantList variants() const; >+ bool hasEdges() const; > CallEdgeList edges() const; > > void clearCallNodesFor(CallLinkInfo*); >Index: Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp >=================================================================== >--- Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp (revision 232441) >+++ Source/JavaScriptCore/profiler/ProfilerBytecodeSequence.cpp (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2012-2017 Apple Inc. All rights reserved. >+ * Copyright (C) 2012-2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -49,12 +49,12 @@ BytecodeSequence::BytecodeSequence(CodeB > m_header.append(out.toCString()); > } > >- StubInfoMap stubInfos; >- codeBlock->getStubInfoMap(stubInfos); >+ ICStatusMap statusMap; >+ codeBlock->getICStatusMap(statusMap); > > for (unsigned bytecodeIndex = 0; bytecodeIndex < codeBlock->instructions().size();) { > out.reset(); >- codeBlock->dumpBytecode(out, bytecodeIndex, stubInfos); >+ codeBlock->dumpBytecode(out, bytecodeIndex, statusMap); > OpcodeID opcodeID = Interpreter::getOpcodeID(codeBlock->instructions()[bytecodeIndex].u.opcode); > m_sequence.append(Bytecode(bytecodeIndex, opcodeID, out.toCString())); > bytecodeIndex += opcodeLength(opcodeID); >Index: Source/JavaScriptCore/runtime/FunctionRareData.cpp >=================================================================== >--- Source/JavaScriptCore/runtime/FunctionRareData.cpp (revision 232441) >+++ Source/JavaScriptCore/runtime/FunctionRareData.cpp (working copy) >@@ -82,6 +82,9 @@ FunctionRareData::~FunctionRareData() > > void FunctionRareData::initializeObjectAllocationProfile(VM& vm, JSGlobalObject* globalObject, JSObject* prototype, size_t inlineCapacity, JSFunction* constructor) > { >+ if (m_objectAllocationProfileWatchpoint.isStillValid()) >+ m_objectAllocationProfileWatchpoint.startWatching(); >+ > m_objectAllocationProfile.initializeProfile(vm, globalObject, this, prototype, inlineCapacity, constructor, this); > } > >Index: Source/JavaScriptCore/runtime/Options.h >=================================================================== >--- Source/JavaScriptCore/runtime/Options.h (revision 232441) >+++ Source/JavaScriptCore/runtime/Options.h (working copy) >@@ -275,6 +275,7 @@ constexpr bool enableWebAssemblyStreamin > v(unsigned, maxAccessVariantListSize, 8, Normal, nullptr) \ > v(bool, usePolyvariantDevirtualization, true, Normal, nullptr) \ > v(bool, usePolymorphicAccessInlining, true, Normal, nullptr) \ >+ v(unsigned, maxPolymorphicAccessInliningListSize, 8, Normal, nullptr) \ > v(bool, usePolymorphicCallInlining, true, Normal, nullptr) \ > v(bool, usePolymorphicCallInliningForNonStubStatus, false, Normal, nullptr) \ > v(unsigned, maxPolymorphicCallVariantListSize, 15, Normal, nullptr) \ >@@ -322,9 +323,6 @@ constexpr bool enableWebAssemblyStreamin > \ > v(unsigned, maximumVarargsForInlining, 100, Normal, nullptr) \ > \ >- v(bool, usePolyvariantCallInlining, true, Normal, nullptr) \ >- v(bool, usePolyvariantByIdInlining, true, Normal, nullptr) \ >- \ > v(bool, useMaximalFlushInsertionPhase, false, Normal, "Setting to true allows the DFG's MaximalFlushInsertionPhase to run.") \ > \ > v(unsigned, maximumBinaryStringSwitchCaseLength, 50, Normal, nullptr) \
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:
ysuzuki
:
review+
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 164904
:
295471
|
295518
|
295582
|
341446
|
341462
|
341542
|
341545
|
341604
|
341611
|
341614
|
341693
|
341703
|
341728
|
341779
|
341807
|
341811
|
341817
|
341825
|
341848
|
341849
|
341850
|
341851
|
341861
|
341924
|
342117
|
342182
|
342188
|
342200
|
343463