Changeset 281615 in webkit
- Timestamp:
- Aug 26, 2021 12:39:01 AM (11 months ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 54 edited
- 4 moved
-
ChangeLog (modified) (1 diff)
-
JavaScriptCore.xcodeproj/project.pbxproj (modified) (4 diffs)
-
Sources.txt (modified) (1 diff)
-
bytecode/AccessCase.cpp (modified) (23 diffs)
-
bytecode/AccessCase.h (modified) (7 diffs)
-
bytecode/ArrayProfile.h (modified) (1 diff)
-
bytecode/GetterSetterAccessCase.cpp (modified) (1 diff)
-
bytecode/ICStatusMap.h (modified) (2 diffs)
-
bytecode/InlineAccess.cpp (modified) (1 diff)
-
bytecode/PolymorphicAccess.cpp (modified) (4 diffs)
-
bytecode/PutByStatus.cpp (moved) (moved from trunk/Source/JavaScriptCore/bytecode/PutByIdStatus.cpp) (32 diffs)
-
bytecode/PutByStatus.h (moved) (moved from trunk/Source/JavaScriptCore/bytecode/PutByIdStatus.h) (6 diffs)
-
bytecode/PutByVariant.cpp (moved) (moved from trunk/Source/JavaScriptCore/bytecode/PutByIdVariant.cpp) (16 diffs)
-
bytecode/PutByVariant.h (moved) (moved from trunk/Source/JavaScriptCore/bytecode/PutByIdVariant.h) (5 diffs)
-
bytecode/RecordedStatuses.cpp (modified) (2 diffs)
-
bytecode/RecordedStatuses.h (modified) (3 diffs)
-
bytecode/StructureStubInfo.cpp (modified) (1 diff)
-
bytecode/StructureStubInfo.h (modified) (2 diffs)
-
dfg/DFGAbstractInterpreterInlines.h (modified) (10 diffs)
-
dfg/DFGArgumentsEliminationPhase.cpp (modified) (2 diffs)
-
dfg/DFGByteCodeParser.cpp (modified) (23 diffs)
-
dfg/DFGClobberize.h (modified) (1 diff)
-
dfg/DFGClobbersExitState.cpp (modified) (1 diff)
-
dfg/DFGConstantFoldingPhase.cpp (modified) (10 diffs)
-
dfg/DFGDoesGC.cpp (modified) (1 diff)
-
dfg/DFGFixupPhase.cpp (modified) (2 diffs)
-
dfg/DFGGraph.cpp (modified) (1 diff)
-
dfg/DFGGraph.h (modified) (1 diff)
-
dfg/DFGJITCompiler.cpp (modified) (1 diff)
-
dfg/DFGJITCompiler.h (modified) (2 diffs)
-
dfg/DFGMayExit.cpp (modified) (1 diff)
-
dfg/DFGNode.h (modified) (3 diffs)
-
dfg/DFGNodeType.h (modified) (1 diff)
-
dfg/DFGOSRExitCompilerCommon.cpp (modified) (1 diff)
-
dfg/DFGObjectAllocationSinkingPhase.cpp (modified) (4 diffs)
-
dfg/DFGPredictionPropagationPhase.cpp (modified) (1 diff)
-
dfg/DFGSafeToExecute.h (modified) (1 diff)
-
dfg/DFGSpeculativeJIT32_64.cpp (modified) (2 diffs)
-
dfg/DFGSpeculativeJIT64.cpp (modified) (2 diffs)
-
dfg/DFGStoreBarrierInsertionPhase.cpp (modified) (1 diff)
-
dfg/DFGValidate.cpp (modified) (1 diff)
-
dfg/DFGVarargsForwardingPhase.cpp (modified) (2 diffs)
-
ftl/FTLCapabilities.cpp (modified) (1 diff)
-
ftl/FTLLowerDFGToB3.cpp (modified) (6 diffs)
-
generator/DSL.rb (modified) (1 diff)
-
jit/ICStats.h (modified) (1 diff)
-
jit/JIT.cpp (modified) (3 diffs)
-
jit/JIT.h (modified) (5 diffs)
-
jit/JITInlineCacheGenerator.cpp (modified) (2 diffs)
-
jit/JITInlineCacheGenerator.h (modified) (2 diffs)
-
jit/JITInlines.h (modified) (2 diffs)
-
jit/JITOperations.cpp (modified) (15 diffs)
-
jit/JITOperations.h (modified) (1 diff)
-
jit/JITPropertyAccess.cpp (modified) (12 diffs)
-
jit/JITPropertyAccess32_64.cpp (modified) (4 diffs)
-
jit/Repatch.cpp (modified) (8 diffs)
-
jit/Repatch.h (modified) (3 diffs)
-
llint/LowLevelInterpreter.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r281607 r281615 1 2021-08-25 Yusuke Suzuki <ysuzuki@apple.com> 2 3 [JSC] Polymorphic PutByVal 4 https://bugs.webkit.org/show_bug.cgi?id=229229 5 6 Reviewed by Saam Barati. 7 8 This patch changes PutByVal IC to modern style. This polymorphic PutByVal can handle multiple array types and multiple identifiers. 9 Also, this removes adhoc IC code in Baseline so that it paves the way to unlinked Baseline JIT by cleaning up IC. 10 11 Several interesting points of the design. 12 13 1. We need to pass ArrayProfile* via GPRReg to IC since we need to profile mayStoreToHole, which is still important to avoid the slow path. 14 2. Transition / Replace IC need to record propertyRegs if it exists not to clobber these registers. This is important in DFG / FTL since 15 IC should not clobber these registers unless it is flushed. It also makes Baseline code smaller since we do not reload them in the slow path call. 16 3. Added a path folding String/Symbol when emitting PutByVal in DFG / FTL. This edge-case is found via a microbenchmark. Let's consider the case: one 17 put_by_val site has one identifier "foo", but it has so many different Structures. Previously, we emit JITPutByIdGenerator adhocly, and still we 18 cache this "foo" identifier in cachedId. In DFG / FTL, while we cannot make it PutByOffset, we can emit PutById since we know that identifier is 19 always "foo". But after this patch's change, such a site becomes slow-path. And then this identifier information is missed, and we were emitting 20 PutByVal for that. For now, we attempt to fold to one identifier in DFGByteCodeParser so that we can still attempt to make it PutById, which 21 can be PutByOffset in constant folding phase. We would like to handle this one identifier slow-path case in PutByStatus / GetByStatus in the future 22 patch. 23 4. Now, DFG OSR exit does not query to ByValInfo for setter calls since JITPutByValGenerator use StructureStubInfo in Baseline. 24 25 Results of Microbenchmarks look good. 26 27 ToT Patched 28 29 put-by-val-direct-large-index 94.6265+-0.9076 93.4550+-0.7121 might be 1.0125x faster 30 inlined-put-by-val-with-string-transition 31 23.7131+-0.3282 ^ 22.7679+-0.1137 ^ definitely 1.0415x faster 32 put-by-val-with-string-slightly-polymorphic 33 1.9852+-0.0284 1.9580+-0.0224 might be 1.0139x faster 34 get-and-put-by-val-double-index-dont-fall-off-a-cliff 35 185.4762+-0.5737 ? 185.6325+-0.5819 ? 36 polymorphic-put-by-val-with-string 30.9903+-0.1207 30.8097+-0.1285 37 put-by-val-machine-int 1.8803+-0.0384 1.8707+-0.0440 38 fold-put-by-val-with-symbol-to-multi-put-by-offset 39 4.8463+-0.1148 4.7839+-0.0547 might be 1.0130x faster 40 put-by-val-with-string-replace-and-transition 41 8.8730+-1.5934 ^ 6.2276+-0.0585 ^ definitely 1.4248x faster 42 fold-put-by-val-with-string-to-multi-put-by-offset 43 4.8183+-0.0841 ? 4.8233+-0.0892 ? 44 put-by-val-direct 0.2845+-0.0091 ? 0.2901+-0.0088 ? might be 1.0196x slower 45 put-by-val-with-symbol-replace-and-transition 46 6.3527+-0.0686 ? 6.3933+-0.0961 ? 47 put-by-val-with-symbol 9.3556+-3.1421 7.1509+-0.1019 might be 1.3083x faster 48 put-by-val-with-symbol-slightly-polymorphic 49 2.0052+-0.0309 1.9781+-0.0397 might be 1.0137x faster 50 put-by-val-negative-array-index 14.9572+-0.1221 ^ 14.5636+-0.1044 ^ definitely 1.0270x faster 51 put-by-val-with-string 11.6345+-4.3048 ^ 7.0919+-0.0918 ^ definitely 1.6405x faster 52 put-by-val-large-index-blank-indexing-type 53 3.1425+-0.1165 3.1236+-0.0378 54 inlined-put-by-val-with-symbol-transition 55 23.4932+-0.3186 ^ 22.8469+-0.0873 ^ definitely 1.0283x faster 56 polymorphic-put-by-val-with-symbol 36.6046+-1.6519 ^ 30.8597+-0.1474 ^ definitely 1.1862x faster 57 58 Speedometer2 showed roughly 0.2-0.3% progression. 59 60 ---------------------------------------------------------------------------------------------------------------------------------- 61 | subtest | ms | ms | b / a | pValue (significance using False Discovery Rate) | 62 ---------------------------------------------------------------------------------------------------------------------------------- 63 | Elm-TodoMVC |121.916667 |121.958333 |1.000342 | 0.876802 | 64 | VueJS-TodoMVC |26.263333 |26.006667 |0.990227 | 0.263868 | 65 | EmberJS-TodoMVC |127.080000 |127.866667 |1.006190 | 0.011497 (significant) | 66 | BackboneJS-TodoMVC |48.920000 |49.318333 |1.008143 | 0.003395 (significant) | 67 | Preact-TodoMVC |19.828333 |19.828333 |1.000000 | 1.000000 | 68 | AngularJS-TodoMVC |134.011667 |132.080000 |0.985586 | 0.000000 (significant) | 69 | Vanilla-ES2015-TodoMVC |63.726667 |63.838333 |1.001752 | 0.408404 | 70 | Inferno-TodoMVC |65.153333 |63.753333 |0.978512 | 0.000000 (significant) | 71 | Flight-TodoMVC |78.133333 |78.780000 |1.008276 | 0.097794 | 72 | Angular2-TypeScript-TodoMVC |40.415000 |40.100000 |0.992206 | 0.287630 | 73 | VanillaJS-TodoMVC |51.931667 |52.500000 |1.010944 | 0.004149 (significant) | 74 | jQuery-TodoMVC |226.056667 |225.073333 |0.995650 | 0.007796 (significant) | 75 | EmberJS-Debug-TodoMVC |341.210000 |340.978333 |0.999321 | 0.623386 | 76 | React-TodoMVC |87.198333 |86.893333 |0.996502 | 0.042189 | 77 | React-Redux-TodoMVC |146.506667 |145.958333 |0.996257 | 0.018801 (significant) | 78 | Vanilla-ES2015-Babel-Webpack-TodoMVC |61.450000 |61.870000 |1.006835 | 0.000049 (significant) | 79 ---------------------------------------------------------------------------------------------------------------------------------- 80 a mean = 254.85111 81 b mean = 255.25735 82 pValue = 0.1856561656 83 (Bigger means are better.) 84 1.002 times better 85 Results ARE NOT significant 86 87 * JavaScriptCore.xcodeproj/project.pbxproj: 88 * Sources.txt: 89 * bytecode/AccessCase.cpp: 90 (JSC::AccessCase::create): 91 (JSC::AccessCase::guardedByStructureCheckSkippingConstantIdentifierCheck const): 92 (JSC::AccessCase::requiresIdentifierNameMatch const): 93 (JSC::AccessCase::requiresInt32PropertyCheck const): 94 (JSC::AccessCase::needsScratchFPR const): 95 (JSC::AccessCase::forEachDependentCell const): 96 (JSC::AccessCase::doesCalls const): 97 (JSC::AccessCase::canReplace const): 98 (JSC::AccessCase::generateWithGuard): 99 (JSC::AccessCase::generateImpl): 100 (JSC::AccessCase::toTypedArrayType): 101 (JSC::AccessCase::canBeShared): 102 * bytecode/AccessCase.h: 103 (JSC::SharedJITStubSet::Hash::Key::Key): 104 (JSC::SharedJITStubSet::Hash::Key::operator==): 105 (JSC::SharedJITStubSet::Searcher::Translator::equal): 106 * bytecode/ArrayProfile.h: 107 (JSC::ArrayProfile::offsetOfMayStoreToHole): 108 (JSC::ArrayProfile::offsetOfLastSeenStructureID): 109 * bytecode/GetterSetterAccessCase.cpp: 110 (JSC::GetterSetterAccessCase::emitDOMJITGetter): 111 * bytecode/ICStatusMap.h: 112 * bytecode/InlineAccess.cpp: 113 (JSC::getScratchRegister): 114 * bytecode/PolymorphicAccess.cpp: 115 (JSC::PolymorphicAccess::regenerate): 116 (WTF::printInternal): 117 * bytecode/PutByStatus.cpp: Renamed from Source/JavaScriptCore/bytecode/PutByIdStatus.cpp. 118 (JSC::PutByStatus::appendVariant): 119 (JSC::PutByStatus::shrinkToFit): 120 (JSC::PutByStatus::computeFromLLInt): 121 (JSC::PutByStatus::PutByStatus): 122 (JSC::PutByStatus::computeFor): 123 (JSC::PutByStatus::computeForStubInfo): 124 (JSC::PutByStatus::makesCalls const): 125 (JSC::PutByStatus::slowVersion const): 126 (JSC::PutByStatus::singleIdentifier const): 127 (JSC::PutByStatus::visitAggregateImpl): 128 (JSC::PutByStatus::markIfCheap): 129 (JSC::PutByStatus::finalize): 130 (JSC::PutByStatus::merge): 131 (JSC::PutByStatus::filter): 132 (JSC::PutByStatus::dump const): 133 * bytecode/PutByStatus.h: Renamed from Source/JavaScriptCore/bytecode/PutByIdStatus.h. 134 * bytecode/PutByVariant.cpp: Renamed from Source/JavaScriptCore/bytecode/PutByIdVariant.cpp. 135 (JSC::PutByVariant::PutByVariant): 136 (JSC::PutByVariant::operator=): 137 (JSC::PutByVariant::replace): 138 (JSC::PutByVariant::transition): 139 (JSC::PutByVariant::setter): 140 (JSC::PutByVariant::oldStructureForTransition const): 141 (JSC::PutByVariant::fixTransitionToReplaceIfNecessary): 142 (JSC::PutByVariant::writesStructures const): 143 (JSC::PutByVariant::reallocatesStorage const): 144 (JSC::PutByVariant::makesCalls const): 145 (JSC::PutByVariant::attemptToMerge): 146 (JSC::PutByVariant::attemptToMergeTransitionWithReplace): 147 (JSC::PutByVariant::visitAggregateImpl): 148 (JSC::PutByVariant::markIfCheap): 149 (JSC::PutByVariant::finalize): 150 (JSC::PutByVariant::dump const): 151 (JSC::PutByVariant::dumpInContext const): 152 * bytecode/PutByVariant.h: Renamed from Source/JavaScriptCore/bytecode/PutByIdVariant.h. 153 (JSC::PutByVariant::PutByVariant): 154 (JSC::PutByVariant::identifier const): 155 (JSC::PutByVariant::overlaps): 156 * bytecode/RecordedStatuses.cpp: 157 (JSC::RecordedStatuses::addPutByStatus): 158 (JSC::RecordedStatuses::visitAggregateImpl): 159 (JSC::RecordedStatuses::addPutByIdStatus): Deleted. 160 * bytecode/RecordedStatuses.h: 161 * bytecode/StructureStubInfo.cpp: 162 (JSC::StructureStubInfo::reset): 163 * bytecode/StructureStubInfo.h: 164 * dfg/DFGAbstractInterpreterInlines.h: 165 (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): 166 (JSC::DFG::AbstractInterpreter<AbstractStateType>::filterICStatus): 167 * dfg/DFGArgumentsEliminationPhase.cpp: 168 * dfg/DFGByteCodeParser.cpp: 169 (JSC::DFG::ByteCodeParser::load): 170 (JSC::DFG::ByteCodeParser::store): 171 (JSC::DFG::ByteCodeParser::emitPutById): 172 (JSC::DFG::ByteCodeParser::handlePutById): 173 (JSC::DFG::ByteCodeParser::handlePutPrivateNameById): 174 (JSC::DFG::ByteCodeParser::parseBlock): 175 (JSC::DFG::ByteCodeParser::handlePutByVal): 176 * dfg/DFGClobberize.h: 177 (JSC::DFG::clobberize): 178 * dfg/DFGClobbersExitState.cpp: 179 (JSC::DFG::clobbersExitState): 180 * dfg/DFGConstantFoldingPhase.cpp: 181 (JSC::DFG::ConstantFoldingPhase::foldConstants): 182 (JSC::DFG::ConstantFoldingPhase::emitPutByOffset): 183 (JSC::DFG::ConstantFoldingPhase::tryFoldAsPutByOffset): 184 * dfg/DFGDoesGC.cpp: 185 (JSC::DFG::doesGC): 186 * dfg/DFGFixupPhase.cpp: 187 (JSC::DFG::FixupPhase::fixupNode): 188 * dfg/DFGGraph.cpp: 189 (JSC::DFG::Graph::dump): 190 * dfg/DFGGraph.h: 191 * dfg/DFGJITCompiler.cpp: 192 (JSC::DFG::JITCompiler::link): 193 * dfg/DFGJITCompiler.h: 194 (JSC::DFG::JITCompiler::addPutByVal): 195 * dfg/DFGMayExit.cpp: 196 * dfg/DFGNode.h: 197 (JSC::DFG::Node::hasPutByStatus): 198 (JSC::DFG::Node::putByStatus): 199 (JSC::DFG::Node::hasPutByIdStatus): Deleted. 200 (JSC::DFG::Node::putByIdStatus): Deleted. 201 * dfg/DFGNodeType.h: 202 * dfg/DFGOSRExitCompilerCommon.cpp: 203 (JSC::DFG::callerReturnPC): 204 * dfg/DFGObjectAllocationSinkingPhase.cpp: 205 * dfg/DFGPredictionPropagationPhase.cpp: 206 * dfg/DFGSafeToExecute.h: 207 (JSC::DFG::safeToExecute): 208 * dfg/DFGSpeculativeJIT32_64.cpp: 209 (JSC::DFG::SpeculativeJIT::compile): 210 * dfg/DFGSpeculativeJIT64.cpp: 211 (JSC::DFG::SpeculativeJIT::compile): 212 * dfg/DFGStoreBarrierInsertionPhase.cpp: 213 * dfg/DFGValidate.cpp: 214 * dfg/DFGVarargsForwardingPhase.cpp: 215 * ftl/FTLCapabilities.cpp: 216 (JSC::FTL::canCompile): 217 * ftl/FTLLowerDFGToB3.cpp: 218 (JSC::FTL::DFG::LowerDFGToB3::compileNode): 219 (JSC::FTL::DFG::LowerDFGToB3::compilePutByVal): 220 (JSC::FTL::DFG::LowerDFGToB3::compileMultiPutByOffset): 221 * generator/DSL.rb: 222 * jit/ICStats.h: 223 * jit/JIT.cpp: 224 (JSC::JIT::privateCompileSlowCases): 225 (JSC::JIT::link): 226 * jit/JIT.h: 227 * jit/JITInlineCacheGenerator.cpp: 228 (JSC::JITPutByIdGenerator::JITPutByIdGenerator): 229 (JSC::JITPutByValGenerator::JITPutByValGenerator): 230 (JSC::JITPutByValGenerator::generateFastPath): 231 (JSC::JITPutByValGenerator::finalize): 232 * jit/JITInlineCacheGenerator.h: 233 * jit/JITInlines.h: 234 (JSC::JIT::emitArrayProfilingSiteWithCell): 235 (JSC::JIT::chooseArrayMode): Deleted. 236 * jit/JITOperations.cpp: 237 (JSC::JSC_DEFINE_JIT_OPERATION): 238 (JSC::putByVal): 239 (JSC::directPutByVal): 240 (JSC::putByValOptimize): 241 (JSC::directPutByValOptimize): 242 (JSC::tryPutByValOptimize): Deleted. 243 (JSC::tryDirectPutByValOptimize): Deleted. 244 * jit/JITOperations.h: 245 * jit/JITPropertyAccess.cpp: 246 (JSC::JIT::emit_op_put_by_val): 247 (JSC::JIT::emitSlow_op_put_by_val): 248 (JSC::JIT::slow_op_put_by_val_prepareCallGenerator): 249 (JSC::JIT::emitSlow_op_put_private_name): 250 (JSC::JIT::slow_op_put_private_name_prepareCallGenerator): 251 (JSC::JIT::emitGenericContiguousPutByVal): Deleted. 252 (JSC::JIT::emitArrayStoragePutByVal): Deleted. 253 (JSC::JIT::privateCompilePutByVal): Deleted. 254 (JSC::JIT::privateCompilePutByValWithCachedId): Deleted. 255 (JSC::JIT::emitIntTypedArrayPutByVal): Deleted. 256 (JSC::JIT::emitFloatTypedArrayPutByVal): Deleted. 257 * jit/JITPropertyAccess32_64.cpp: 258 (JSC::JIT::emit_op_put_by_val): 259 (JSC::JIT::emitSlow_op_put_by_val): 260 (JSC::JIT::emitGenericContiguousPutByVal): Deleted. 261 (JSC::JIT::emitArrayStoragePutByVal): Deleted. 262 * jit/Repatch.cpp: 263 (JSC::appropriateGenericPutByFunction): 264 (JSC::appropriateOptimizingPutByFunction): 265 (JSC::tryCachePutBy): 266 (JSC::repatchPutBy): 267 (JSC::tryCacheArrayPutByVal): 268 (JSC::repatchArrayPutByVal): 269 (JSC::tryCacheInBy): 270 (JSC::resetPutBy): 271 (JSC::appropriateGenericPutByIdFunction): Deleted. 272 (JSC::appropriateOptimizingPutByIdFunction): Deleted. 273 (JSC::tryCachePutByID): Deleted. 274 (JSC::repatchPutByID): Deleted. 275 (JSC::resetPutByID): Deleted. 276 * jit/Repatch.h: 277 * llint/LowLevelInterpreter.h: 278 1 279 2021-08-25 Yusuke Suzuki <ysuzuki@apple.com> 2 280 -
trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r281325 r281615 465 465 0F93329E14CA7DC50085F3C6 /* CallLinkStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93329414CA7DC10085F3C6 /* CallLinkStatus.h */; settings = {ATTRIBUTES = (Private, ); }; }; 466 466 0F9332A014CA7DCD0085F3C6 /* GetByStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93329614CA7DC10085F3C6 /* GetByStatus.h */; settings = {ATTRIBUTES = (Private, ); }; }; 467 0F9332A414CA7DD90085F3C6 /* PutBy IdStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93329A14CA7DC10085F3C6 /* PutByIdStatus.h */; settings = {ATTRIBUTES = (Private, ); }; };467 0F9332A414CA7DD90085F3C6 /* PutByStatus.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93329A14CA7DC10085F3C6 /* PutByStatus.h */; settings = {ATTRIBUTES = (Private, ); }; }; 468 468 0F9332A514CA7DDD0085F3C6 /* StructureSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93329B14CA7DC10085F3C6 /* StructureSet.h */; settings = {ATTRIBUTES = (Private, ); }; }; 469 0F93B4AA18B92C4D00178A3F /* PutBy IdVariant.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93B4A818B92C4D00178A3F /* PutByIdVariant.h */; settings = {ATTRIBUTES = (Private, ); }; };469 0F93B4AA18B92C4D00178A3F /* PutByVariant.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F93B4A818B92C4D00178A3F /* PutByVariant.h */; settings = {ATTRIBUTES = (Private, ); }; }; 470 470 0F952AA11DF7860900E06FBD /* VisitRaceKey.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F952AA01DF7860700E06FBD /* VisitRaceKey.h */; settings = {ATTRIBUTES = (Private, ); }; }; 471 471 0F952ABD1B487A7700C367C5 /* TrackedReferences.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F952ABB1B487A7700C367C5 /* TrackedReferences.h */; settings = {ATTRIBUTES = (Private, ); }; }; … … 2867 2867 0F93329514CA7DC10085F3C6 /* GetByStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetByStatus.cpp; sourceTree = "<group>"; }; 2868 2868 0F93329614CA7DC10085F3C6 /* GetByStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetByStatus.h; sourceTree = "<group>"; }; 2869 0F93329914CA7DC10085F3C6 /* PutBy IdStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PutByIdStatus.cpp; sourceTree = "<group>"; };2870 0F93329A14CA7DC10085F3C6 /* PutBy IdStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PutByIdStatus.h; sourceTree = "<group>"; };2869 0F93329914CA7DC10085F3C6 /* PutByStatus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PutByStatus.cpp; sourceTree = "<group>"; }; 2870 0F93329A14CA7DC10085F3C6 /* PutByStatus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PutByStatus.h; sourceTree = "<group>"; }; 2871 2871 0F93329B14CA7DC10085F3C6 /* StructureSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructureSet.h; sourceTree = "<group>"; }; 2872 0F93B4A718B92C4D00178A3F /* PutBy IdVariant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PutByIdVariant.cpp; sourceTree = "<group>"; };2873 0F93B4A818B92C4D00178A3F /* PutBy IdVariant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PutByIdVariant.h; sourceTree = "<group>"; };2872 0F93B4A718B92C4D00178A3F /* PutByVariant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PutByVariant.cpp; sourceTree = "<group>"; }; 2873 0F93B4A818B92C4D00178A3F /* PutByVariant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PutByVariant.h; sourceTree = "<group>"; }; 2874 2874 0F952A9F1DF7860700E06FBD /* VisitRaceKey.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VisitRaceKey.cpp; sourceTree = "<group>"; }; 2875 2875 0F952AA01DF7860700E06FBD /* VisitRaceKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VisitRaceKey.h; sourceTree = "<group>"; }; … … 8696 8696 0F15CD201BA5F9860031FFD3 /* PutByIdFlags.cpp */, 8697 8697 0F15CD211BA5F9860031FFD3 /* PutByIdFlags.h */, 8698 0F93329914CA7DC10085F3C6 /* PutBy IdStatus.cpp */,8699 0F93329A14CA7DC10085F3C6 /* PutBy IdStatus.h */,8700 0F93B4A718B92C4D00178A3F /* PutBy IdVariant.cpp */,8701 0F93B4A818B92C4D00178A3F /* PutBy IdVariant.h */,8698 0F93329914CA7DC10085F3C6 /* PutByStatus.cpp */, 8699 0F93329A14CA7DC10085F3C6 /* PutByStatus.h */, 8700 0F93B4A718B92C4D00178A3F /* PutByVariant.cpp */, 8701 0F93B4A818B92C4D00178A3F /* PutByVariant.h */, 8702 8702 0F9FC8C114E1B5FB00D52AE0 /* PutKind.h */, 8703 8703 0F44A7AD20BF685F0022B171 /* RecordedStatuses.cpp */, … … 10507 10507 0F5780A218FE1E98001E72D9 /* PureNaN.h in Headers */, 10508 10508 0F15CD231BA5F9860031FFD3 /* PutByIdFlags.h in Headers */, 10509 0F9332A414CA7DD90085F3C6 /* PutBy IdStatus.h in Headers */,10510 0F93B4AA18B92C4D00178A3F /* PutBy IdVariant.h in Headers */,10509 0F9332A414CA7DD90085F3C6 /* PutByStatus.h in Headers */, 10510 0F93B4AA18B92C4D00178A3F /* PutByVariant.h in Headers */, 10511 10511 0F0CD4C215F1A6070032F1C0 /* PutDirectIndexMode.h in Headers */, 10512 10512 0F9FC8C514E1B60400D52AE0 /* PutKind.h in Headers */, -
trunk/Source/JavaScriptCore/Sources.txt
r280493 r281615 270 270 bytecode/ProxyableAccessCase.cpp 271 271 bytecode/PutByIdFlags.cpp 272 bytecode/PutBy IdStatus.cpp273 bytecode/PutBy IdVariant.cpp272 bytecode/PutByStatus.cpp 273 bytecode/PutByVariant.cpp 274 274 bytecode/RecordedStatuses.cpp 275 275 bytecode/ReduceWhitespace.cpp -
trunk/Source/JavaScriptCore/bytecode/AccessCase.cpp
r280460 r281615 100 100 case IndexedTypedArrayFloat64Load: 101 101 case IndexedStringLoad: 102 case IndexedInt32Store: 103 case IndexedDoubleStore: 104 case IndexedContiguousStore: 105 case IndexedArrayStorageStore: 106 case IndexedTypedArrayInt8Store: 107 case IndexedTypedArrayUint8Store: 108 case IndexedTypedArrayUint8ClampedStore: 109 case IndexedTypedArrayInt16Store: 110 case IndexedTypedArrayUint16Store: 111 case IndexedTypedArrayInt32Store: 112 case IndexedTypedArrayUint32Store: 113 case IndexedTypedArrayFloat32Store: 114 case IndexedTypedArrayFloat64Store: 102 115 RELEASE_ASSERT(!prototypeAccessChain); 103 116 break; … … 273 286 case IndexedTypedArrayFloat64Load: 274 287 case IndexedStringLoad: 288 case IndexedInt32Store: 289 case IndexedDoubleStore: 290 case IndexedContiguousStore: 291 case IndexedArrayStorageStore: 292 case IndexedTypedArrayInt8Store: 293 case IndexedTypedArrayUint8Store: 294 case IndexedTypedArrayUint8ClampedStore: 295 case IndexedTypedArrayInt16Store: 296 case IndexedTypedArrayUint16Store: 297 case IndexedTypedArrayInt32Store: 298 case IndexedTypedArrayUint32Store: 299 case IndexedTypedArrayFloat32Store: 300 case IndexedTypedArrayFloat64Store: 275 301 return false; 276 302 default: … … 327 353 case IndexedTypedArrayFloat64Load: 328 354 case IndexedStringLoad: 355 case IndexedInt32Store: 356 case IndexedDoubleStore: 357 case IndexedContiguousStore: 358 case IndexedArrayStorageStore: 359 case IndexedTypedArrayInt8Store: 360 case IndexedTypedArrayUint8Store: 361 case IndexedTypedArrayUint8ClampedStore: 362 case IndexedTypedArrayInt16Store: 363 case IndexedTypedArrayUint16Store: 364 case IndexedTypedArrayInt32Store: 365 case IndexedTypedArrayUint32Store: 366 case IndexedTypedArrayFloat32Store: 367 case IndexedTypedArrayFloat64Store: 329 368 return false; 330 369 } … … 379 418 case IndexedTypedArrayFloat64Load: 380 419 case IndexedStringLoad: 420 case IndexedInt32Store: 421 case IndexedDoubleStore: 422 case IndexedContiguousStore: 423 case IndexedArrayStorageStore: 424 case IndexedTypedArrayInt8Store: 425 case IndexedTypedArrayUint8Store: 426 case IndexedTypedArrayUint8ClampedStore: 427 case IndexedTypedArrayInt16Store: 428 case IndexedTypedArrayUint16Store: 429 case IndexedTypedArrayInt32Store: 430 case IndexedTypedArrayUint32Store: 431 case IndexedTypedArrayFloat32Store: 432 case IndexedTypedArrayFloat64Store: 381 433 return true; 382 434 } … … 426 478 case IndexedTypedArrayInt32Load: 427 479 case IndexedStringLoad: 480 case IndexedInt32Store: 481 case IndexedContiguousStore: 482 case IndexedArrayStorageStore: 483 case IndexedTypedArrayInt8Store: 484 case IndexedTypedArrayUint8Store: 485 case IndexedTypedArrayUint8ClampedStore: 486 case IndexedTypedArrayInt16Store: 487 case IndexedTypedArrayUint16Store: 488 case IndexedTypedArrayInt32Store: 428 489 return false; 429 490 case IndexedDoubleLoad: … … 431 492 case IndexedTypedArrayFloat64Load: 432 493 case IndexedTypedArrayUint32Load: 494 case IndexedDoubleStore: 495 case IndexedTypedArrayUint32Store: 496 case IndexedTypedArrayFloat32Store: 497 case IndexedTypedArrayFloat64Store: 433 498 return true; 434 499 } … … 516 581 case IndexedTypedArrayFloat64Load: 517 582 case IndexedStringLoad: 583 case IndexedInt32Store: 584 case IndexedDoubleStore: 585 case IndexedContiguousStore: 586 case IndexedArrayStorageStore: 587 case IndexedTypedArrayInt8Store: 588 case IndexedTypedArrayUint8Store: 589 case IndexedTypedArrayUint8ClampedStore: 590 case IndexedTypedArrayInt16Store: 591 case IndexedTypedArrayUint16Store: 592 case IndexedTypedArrayInt32Store: 593 case IndexedTypedArrayUint32Store: 594 case IndexedTypedArrayFloat32Store: 595 case IndexedTypedArrayFloat64Store: 518 596 break; 519 597 } … … 570 648 case IndexedTypedArrayFloat64Load: 571 649 case IndexedStringLoad: 650 case IndexedInt32Store: 651 case IndexedDoubleStore: 652 case IndexedContiguousStore: 653 case IndexedArrayStorageStore: 654 case IndexedTypedArrayInt8Store: 655 case IndexedTypedArrayUint8Store: 656 case IndexedTypedArrayUint8ClampedStore: 657 case IndexedTypedArrayInt16Store: 658 case IndexedTypedArrayUint16Store: 659 case IndexedTypedArrayInt32Store: 660 case IndexedTypedArrayUint32Store: 661 case IndexedTypedArrayFloat32Store: 662 case IndexedTypedArrayFloat64Store: 572 663 doesCalls = false; 573 664 break; … … 651 742 case IndexedTypedArrayFloat64Load: 652 743 case IndexedStringLoad: 744 case IndexedInt32Store: 745 case IndexedDoubleStore: 746 case IndexedContiguousStore: 747 case IndexedArrayStorageStore: 748 case IndexedTypedArrayInt8Store: 749 case IndexedTypedArrayUint8Store: 750 case IndexedTypedArrayUint8ClampedStore: 751 case IndexedTypedArrayInt16Store: 752 case IndexedTypedArrayUint16Store: 753 case IndexedTypedArrayInt32Store: 754 case IndexedTypedArrayUint32Store: 755 case IndexedTypedArrayFloat32Store: 756 case IndexedTypedArrayFloat64Store: 653 757 return other.type() == type(); 654 758 … … 962 1066 if (stubInfo.m_stubInfoGPR != InvalidGPRReg) 963 1067 allocator.lock(stubInfo.m_stubInfoGPR); 1068 ASSERT(stubInfo.m_arrayProfileGPR == InvalidGPRReg); 964 1069 allocator.lock(scratchGPR); 965 1070 … … 1061 1166 if (stubInfo.m_stubInfoGPR != InvalidGPRReg) 1062 1167 allocator.lock(stubInfo.m_stubInfoGPR); 1168 ASSERT(stubInfo.m_arrayProfileGPR == InvalidGPRReg); 1063 1169 allocator.lock(scratchGPR); 1064 1170 GPRReg scratch2GPR = allocator.allocateScratchGPR(); … … 1146 1252 if (stubInfo.m_stubInfoGPR != InvalidGPRReg) 1147 1253 allocator.lock(stubInfo.m_stubInfoGPR); 1254 ASSERT(stubInfo.m_arrayProfileGPR == InvalidGPRReg); 1148 1255 allocator.lock(scratchGPR); 1149 1256 GPRReg scratch2GPR = allocator.allocateScratchGPR(); … … 1200 1307 jit.and32(CCallHelpers::TrustedImm32(IndexingShapeMask), scratchGPR); 1201 1308 1202 CCallHelpers::Jump isOutOfBounds;1203 CCallHelpers::Jump isEmpty;1204 1205 1309 ScratchRegisterAllocator allocator(stubInfo.usedRegisters); 1206 1310 allocator.lock(stubInfo.baseRegs()); … … 1209 1313 if (stubInfo.m_stubInfoGPR != InvalidGPRReg) 1210 1314 allocator.lock(stubInfo.m_stubInfoGPR); 1315 ASSERT(stubInfo.m_arrayProfileGPR == InvalidGPRReg); 1211 1316 allocator.lock(scratchGPR); 1212 1317 GPRReg scratch2GPR = allocator.allocateScratchGPR(); … … 1228 1333 1229 1334 jit.loadPtr(CCallHelpers::Address(baseGPR, JSObject::butterflyOffset()), scratchGPR); 1230 isOutOfBounds = jit.branch32(CCallHelpers::AboveOrEqual, propertyGPR, CCallHelpers::Address(scratchGPR, ArrayStorage::vectorLengthOffset()));1335 failAndIgnore.append(jit.branch32(CCallHelpers::AboveOrEqual, propertyGPR, CCallHelpers::Address(scratchGPR, ArrayStorage::vectorLengthOffset()))); 1231 1336 1232 1337 jit.zeroExtend32ToWord(propertyGPR, scratch2GPR); 1233 1338 #if USE(JSVALUE64) 1234 1339 jit.loadValue(CCallHelpers::BaseIndex(scratchGPR, scratch2GPR, CCallHelpers::TimesEight, ArrayStorage::vectorOffset()), JSValueRegs(scratchGPR)); 1235 isEmpty = jit.branchIfEmpty(scratchGPR);1340 failAndIgnore.append(jit.branchIfEmpty(scratchGPR)); 1236 1341 jit.move(scratchGPR, valueRegs.payloadGPR()); 1237 1342 #else 1238 1343 jit.loadValue(CCallHelpers::BaseIndex(scratchGPR, scratch2GPR, CCallHelpers::TimesEight, ArrayStorage::vectorOffset()), JSValueRegs(scratch3GPR, scratchGPR)); 1239 isEmpty = jit.branchIfEmpty(scratch3GPR);1344 failAndIgnore.append(jit.branchIfEmpty(scratch3GPR)); 1240 1345 jit.move(scratchGPR, valueRegs.payloadGPR()); 1241 1346 jit.move(scratch3GPR, valueRegs.tagGPR()); … … 1263 1368 1264 1369 jit.loadPtr(CCallHelpers::Address(baseGPR, JSObject::butterflyOffset()), scratchGPR); 1265 isOutOfBounds = jit.branch32(CCallHelpers::AboveOrEqual, propertyGPR, CCallHelpers::Address(scratchGPR, Butterfly::offsetOfPublicLength()));1370 failAndIgnore.append(jit.branch32(CCallHelpers::AboveOrEqual, propertyGPR, CCallHelpers::Address(scratchGPR, Butterfly::offsetOfPublicLength()))); 1266 1371 jit.zeroExtend32ToWord(propertyGPR, scratch2GPR); 1267 1372 if (m_type == IndexedDoubleLoad) { 1268 1373 RELEASE_ASSERT(state.scratchFPR != InvalidFPRReg); 1269 1374 jit.loadDouble(CCallHelpers::BaseIndex(scratchGPR, scratch2GPR, CCallHelpers::TimesEight), state.scratchFPR); 1270 isEmpty = jit.branchIfNaN(state.scratchFPR);1375 failAndIgnore.append(jit.branchIfNaN(state.scratchFPR)); 1271 1376 jit.boxDouble(state.scratchFPR, valueRegs); 1272 1377 } else { 1273 1378 #if USE(JSVALUE64) 1274 1379 jit.loadValue(CCallHelpers::BaseIndex(scratchGPR, scratch2GPR, CCallHelpers::TimesEight), JSValueRegs(scratchGPR)); 1275 isEmpty = jit.branchIfEmpty(scratchGPR);1380 failAndIgnore.append(jit.branchIfEmpty(scratchGPR)); 1276 1381 jit.move(scratchGPR, valueRegs.payloadGPR()); 1277 1382 #else 1278 1383 jit.loadValue(CCallHelpers::BaseIndex(scratchGPR, scratch2GPR, CCallHelpers::TimesEight), JSValueRegs(scratch3GPR, scratchGPR)); 1279 isEmpty = jit.branchIfEmpty(scratch3GPR);1384 failAndIgnore.append(jit.branchIfEmpty(scratch3GPR)); 1280 1385 jit.move(scratchGPR, valueRegs.payloadGPR()); 1281 1386 jit.move(scratch3GPR, valueRegs.tagGPR()); … … 1287 1392 state.succeed(); 1288 1393 1289 if (allocator.didReuseRegisters()) { 1290 isOutOfBounds.link(&jit); 1291 isEmpty.link(&jit); 1394 if (allocator.didReuseRegisters() && !failAndIgnore.empty()) { 1395 failAndIgnore.link(&jit); 1292 1396 allocator.restoreReusedRegistersByPopping(jit, preservedState); 1293 1397 state.failAndIgnore.append(jit.jump()); 1294 } else { 1295 state.failAndIgnore.append(isOutOfBounds); 1296 state.failAndIgnore.append(isEmpty); 1297 } 1298 1398 } else 1399 state.failAndIgnore.append(failAndIgnore); 1299 1400 return; 1300 1401 } 1301 1402 1302 case InstanceOfHit: 1303 case InstanceOfMiss: 1304 emitDefaultGuard(); 1305 1306 fallThrough.append( 1307 jit.branchPtr( 1308 CCallHelpers::NotEqual, state.u.prototypeGPR, 1309 CCallHelpers::TrustedImmPtr(as<InstanceOfAccessCase>().prototype()))); 1310 break; 1311 1312 case InstanceOfGeneric: { 1403 case IndexedInt32Store: 1404 case IndexedDoubleStore: 1405 case IndexedContiguousStore: 1406 case IndexedArrayStorageStore: { 1313 1407 ASSERT(!viaProxy()); 1314 GPRReg prototypeGPR = state.u.prototypeGPR; 1315 // Legend: value = `base instanceof prototypeGPR`. 1316 1317 GPRReg valueGPR = valueRegs.payloadGPR(); 1318 1408 GPRReg propertyGPR = state.u.propertyGPR; 1409 1410 // int32 check done in polymorphic access. 1411 jit.load8(CCallHelpers::Address(baseGPR, JSCell::indexingTypeAndMiscOffset()), scratchGPR); 1412 fallThrough.append(jit.branchTest32(CCallHelpers::NonZero, scratchGPR, CCallHelpers::TrustedImm32(CopyOnWrite))); 1413 jit.and32(CCallHelpers::TrustedImm32(IndexingShapeMask), scratchGPR); 1414 1415 CCallHelpers::JumpList isOutOfBounds; 1416 1319 1417 ScratchRegisterAllocator allocator(stubInfo.usedRegisters); 1320 1418 allocator.lock(stubInfo.baseRegs()); … … 1323 1421 if (stubInfo.m_stubInfoGPR != InvalidGPRReg) 1324 1422 allocator.lock(stubInfo.m_stubInfoGPR); 1423 if (stubInfo.m_arrayProfileGPR != InvalidGPRReg) 1424 allocator.lock(stubInfo.m_arrayProfileGPR); 1425 allocator.lock(scratchGPR); 1426 GPRReg scratch2GPR = allocator.allocateScratchGPR(); 1427 ScratchRegisterAllocator::PreservedState preservedState; 1428 1429 CCallHelpers::JumpList failAndIgnore; 1430 CCallHelpers::JumpList failAndRepatch; 1431 auto preserveReusedRegisters = [&] { 1432 preservedState = allocator.preserveReusedRegistersByPushing(jit, ScratchRegisterAllocator::ExtraStackSpace::NoExtraSpace); 1433 }; 1434 1435 CCallHelpers::Label storeResult; 1436 if (m_type == IndexedArrayStorageStore) { 1437 fallThrough.append(jit.branch32(CCallHelpers::NotEqual, scratchGPR, CCallHelpers::TrustedImm32(ArrayStorageShape))); 1438 1439 preserveReusedRegisters(); 1440 1441 jit.loadPtr(CCallHelpers::Address(baseGPR, JSObject::butterflyOffset()), scratchGPR); 1442 failAndIgnore.append(jit.branch32(CCallHelpers::AboveOrEqual, propertyGPR, CCallHelpers::Address(scratchGPR, ArrayStorage::vectorLengthOffset()))); 1443 1444 jit.zeroExtend32ToWord(propertyGPR, scratch2GPR); 1445 1446 #if USE(JSVALUE64) 1447 isOutOfBounds.append(jit.branchTest64(CCallHelpers::Zero, CCallHelpers::BaseIndex(scratchGPR, scratch2GPR, CCallHelpers::TimesEight, ArrayStorage::vectorOffset()))); 1448 #else 1449 isOutOfBounds.append(jit.branch32(CCallHelpers::Equal, CCallHelpers::BaseIndex(scratchGPR, scratch2GPR, CCallHelpers::TimesEight, ArrayStorage::vectorOffset() + JSValue::offsetOfTag()), CCallHelpers::TrustedImm32(JSValue::EmptyValueTag))); 1450 #endif 1451 1452 storeResult = jit.label(); 1453 jit.storeValue(valueRegs, CCallHelpers::BaseIndex(scratchGPR, scratch2GPR, CCallHelpers::TimesEight, ArrayStorage::vectorOffset())); 1454 } else { 1455 IndexingType expectedShape; 1456 switch (m_type) { 1457 case IndexedInt32Store: 1458 expectedShape = Int32Shape; 1459 break; 1460 case IndexedDoubleStore: 1461 expectedShape = DoubleShape; 1462 break; 1463 case IndexedContiguousStore: 1464 expectedShape = ContiguousShape; 1465 break; 1466 default: 1467 RELEASE_ASSERT_NOT_REACHED(); 1468 break; 1469 } 1470 1471 fallThrough.append(jit.branch32(CCallHelpers::NotEqual, scratchGPR, CCallHelpers::TrustedImm32(expectedShape))); 1472 1473 preserveReusedRegisters(); 1474 1475 jit.loadPtr(CCallHelpers::Address(baseGPR, JSObject::butterflyOffset()), scratchGPR); 1476 isOutOfBounds.append(jit.branch32(CCallHelpers::AboveOrEqual, propertyGPR, CCallHelpers::Address(scratchGPR, Butterfly::offsetOfPublicLength()))); 1477 storeResult = jit.label(); 1478 switch (m_type) { 1479 case IndexedDoubleStore: { 1480 RELEASE_ASSERT(state.scratchFPR != InvalidFPRReg); 1481 auto notInt = jit.branchIfNotInt32(valueRegs); 1482 jit.convertInt32ToDouble(valueRegs.payloadGPR(), state.scratchFPR); 1483 auto ready = jit.jump(); 1484 notInt.link(&jit); 1485 #if USE(JSVALUE64) 1486 jit.unboxDoubleWithoutAssertions(valueRegs.payloadGPR(), scratch2GPR, state.scratchFPR); 1487 failAndRepatch.append(jit.branchIfNaN(state.scratchFPR)); 1488 #else 1489 failAndRepatch.append(jit.branch32(CCallHelpers::Above, valueRegs.tagGPR(), CCallHelpers::TrustedImm32(JSValue::LowestTag))); 1490 jit.unboxDouble(valueRegs, state.scratchFPR); 1491 #endif 1492 ready.link(&jit); 1493 1494 jit.zeroExtend32ToWord(propertyGPR, scratch2GPR); 1495 jit.storeDouble(state.scratchFPR, CCallHelpers::BaseIndex(scratchGPR, scratch2GPR, CCallHelpers::TimesEight)); 1496 break; 1497 } 1498 case IndexedInt32Store: 1499 jit.zeroExtend32ToWord(propertyGPR, scratch2GPR); 1500 failAndRepatch.append(jit.branchIfNotInt32(valueRegs)); 1501 jit.storeValue(valueRegs, CCallHelpers::BaseIndex(scratchGPR, scratch2GPR, CCallHelpers::TimesEight)); 1502 break; 1503 case IndexedContiguousStore: 1504 jit.zeroExtend32ToWord(propertyGPR, scratch2GPR); 1505 jit.storeValue(valueRegs, CCallHelpers::BaseIndex(scratchGPR, scratch2GPR, CCallHelpers::TimesEight)); 1506 // WriteBarrier must be emitted in the embedder side. 1507 break; 1508 default: 1509 RELEASE_ASSERT_NOT_REACHED(); 1510 break; 1511 } 1512 } 1513 1514 allocator.restoreReusedRegistersByPopping(jit, preservedState); 1515 state.succeed(); 1516 1517 if (m_type == IndexedArrayStorageStore) { 1518 isOutOfBounds.link(&jit); 1519 if (stubInfo.m_arrayProfileGPR != InvalidGPRReg) 1520 jit.store8(CCallHelpers::TrustedImm32(1), CCallHelpers::Address(stubInfo.m_arrayProfileGPR, ArrayProfile::offsetOfMayStoreToHole())); 1521 jit.add32(CCallHelpers::TrustedImm32(1), CCallHelpers::Address(scratchGPR, ArrayStorage::numValuesInVectorOffset())); 1522 jit.branch32(CCallHelpers::Below, scratch2GPR, CCallHelpers::Address(scratchGPR, ArrayStorage::lengthOffset())).linkTo(storeResult, &jit); 1523 1524 jit.add32(CCallHelpers::TrustedImm32(1), scratch2GPR); 1525 jit.store32(scratch2GPR, CCallHelpers::Address(scratchGPR, ArrayStorage::lengthOffset())); 1526 jit.sub32(CCallHelpers::TrustedImm32(1), scratch2GPR); 1527 jit.jump().linkTo(storeResult, &jit); 1528 } else { 1529 isOutOfBounds.link(&jit); 1530 failAndIgnore.append(jit.branch32(CCallHelpers::AboveOrEqual, propertyGPR, CCallHelpers::Address(scratchGPR, Butterfly::offsetOfVectorLength()))); 1531 if (stubInfo.m_arrayProfileGPR != InvalidGPRReg) 1532 jit.store8(CCallHelpers::TrustedImm32(1), CCallHelpers::Address(stubInfo.m_arrayProfileGPR, ArrayProfile::offsetOfMayStoreToHole())); 1533 jit.add32(CCallHelpers::TrustedImm32(1), propertyGPR, scratch2GPR); 1534 jit.store32(scratch2GPR, CCallHelpers::Address(scratchGPR, Butterfly::offsetOfPublicLength())); 1535 jit.jump().linkTo(storeResult, &jit); 1536 1537 } 1538 1539 if (allocator.didReuseRegisters()) { 1540 if (!failAndIgnore.empty()) { 1541 failAndIgnore.link(&jit); 1542 allocator.restoreReusedRegistersByPopping(jit, preservedState); 1543 state.failAndIgnore.append(jit.jump()); 1544 } 1545 if (!failAndRepatch.empty()) { 1546 failAndRepatch.link(&jit); 1547 allocator.restoreReusedRegistersByPopping(jit, preservedState); 1548 state.failAndRepatch.append(jit.jump()); 1549 } 1550 } else { 1551 state.failAndIgnore.append(failAndIgnore); 1552 state.failAndRepatch.append(failAndRepatch); 1553 } 1554 return; 1555 } 1556 1557 case IndexedTypedArrayInt8Store: 1558 case IndexedTypedArrayUint8Store: 1559 case IndexedTypedArrayUint8ClampedStore: 1560 case IndexedTypedArrayInt16Store: 1561 case IndexedTypedArrayUint16Store: 1562 case IndexedTypedArrayInt32Store: 1563 case IndexedTypedArrayUint32Store: 1564 case IndexedTypedArrayFloat32Store: 1565 case IndexedTypedArrayFloat64Store: { 1566 ASSERT(!viaProxy()); 1567 // This code is written such that the result could alias with the base or the property. 1568 1569 TypedArrayType type = toTypedArrayType(m_type); 1570 1571 GPRReg propertyGPR = state.u.propertyGPR; 1572 1573 jit.load8(CCallHelpers::Address(baseGPR, JSCell::typeInfoTypeOffset()), scratchGPR); 1574 fallThrough.append(jit.branch32(CCallHelpers::NotEqual, scratchGPR, CCallHelpers::TrustedImm32(typeForTypedArrayType(type)))); 1575 1576 if (isInt(type)) 1577 state.failAndRepatch.append(jit.branchIfNotInt32(valueRegs)); 1578 else { 1579 ASSERT(isFloat(type)); 1580 RELEASE_ASSERT(state.scratchFPR != InvalidFPRReg); 1581 auto doubleCase = jit.branchIfNotInt32(valueRegs); 1582 jit.convertInt32ToDouble(valueRegs.payloadGPR(), state.scratchFPR); 1583 auto ready = jit.jump(); 1584 doubleCase.link(&jit); 1585 #if USE(JSVALUE64) 1586 state.failAndRepatch.append(jit.branchIfNotNumber(valueRegs.payloadGPR())); 1587 jit.unboxDoubleWithoutAssertions(valueRegs.payloadGPR(), scratchGPR, state.scratchFPR); 1588 #else 1589 state.failAndRepatch.append(jit.branch32(CCallHelpers::Above, valueRegs.tagGPR(), CCallHelpers::TrustedImm32(JSValue::LowestTag))); 1590 jit.unboxDouble(valueRegs, state.scratchFPR); 1591 #endif 1592 ready.link(&jit); 1593 } 1594 1595 jit.load32(CCallHelpers::Address(baseGPR, JSArrayBufferView::offsetOfLength()), scratchGPR); 1596 // OutOfBounds bit of ArrayProfile will be set in the operation function. 1597 state.failAndRepatch.append(jit.branch32(CCallHelpers::AboveOrEqual, propertyGPR, scratchGPR)); 1598 1599 ScratchRegisterAllocator allocator(stubInfo.usedRegisters); 1600 allocator.lock(stubInfo.baseRegs()); 1601 allocator.lock(valueRegs); 1602 allocator.lock(stubInfo.propertyRegs()); 1603 if (stubInfo.m_stubInfoGPR != InvalidGPRReg) 1604 allocator.lock(stubInfo.m_stubInfoGPR); 1605 if (stubInfo.m_arrayProfileGPR != InvalidGPRReg) 1606 allocator.lock(stubInfo.m_arrayProfileGPR); 1607 allocator.lock(scratchGPR); 1608 GPRReg scratch2GPR = allocator.allocateScratchGPR(); 1609 GPRReg scratch3GPR = InvalidGPRReg; 1610 if (isClamped(type)) 1611 scratch3GPR = allocator.allocateScratchGPR(); 1612 1613 ScratchRegisterAllocator::PreservedState preservedState = allocator.preserveReusedRegistersByPushing( 1614 jit, ScratchRegisterAllocator::ExtraStackSpace::NoExtraSpace); 1615 1616 jit.loadPtr(CCallHelpers::Address(baseGPR, JSArrayBufferView::offsetOfVector()), scratch2GPR); 1617 jit.cageConditionallyAndUntag(Gigacage::Primitive, scratch2GPR, scratchGPR, scratchGPR, false); 1618 1619 jit.signExtend32ToPtr(propertyGPR, scratchGPR); 1620 if (isInt(type)) { 1621 if (isClamped(type)) { 1622 ASSERT(elementSize(type) == 1); 1623 ASSERT(!JSC::isSigned(type)); 1624 jit.move(valueRegs.payloadGPR(), scratch3GPR); 1625 auto inBounds = jit.branch32(CCallHelpers::BelowOrEqual, scratch3GPR, CCallHelpers::TrustedImm32(0xff)); 1626 auto tooBig = jit.branch32(CCallHelpers::GreaterThan, scratch3GPR, CCallHelpers::TrustedImm32(0xff)); 1627 jit.xor32(scratch3GPR, scratch3GPR); 1628 auto clamped = jit.jump(); 1629 tooBig.link(&jit); 1630 jit.move(CCallHelpers::TrustedImm32(0xff), scratch3GPR); 1631 clamped.link(&jit); 1632 inBounds.link(&jit); 1633 jit.store8(scratch3GPR, CCallHelpers::BaseIndex(scratch2GPR, scratchGPR, CCallHelpers::TimesOne)); 1634 } else { 1635 switch (elementSize(type)) { 1636 case 1: 1637 jit.store8(valueRegs.payloadGPR(), CCallHelpers::BaseIndex(scratch2GPR, scratchGPR, CCallHelpers::TimesOne)); 1638 break; 1639 case 2: 1640 jit.store16(valueRegs.payloadGPR(), CCallHelpers::BaseIndex(scratch2GPR, scratchGPR, CCallHelpers::TimesTwo)); 1641 break; 1642 case 4: 1643 jit.store32(valueRegs.payloadGPR(), CCallHelpers::BaseIndex(scratch2GPR, scratchGPR, CCallHelpers::TimesFour)); 1644 break; 1645 default: 1646 CRASH(); 1647 } 1648 } 1649 } else { 1650 ASSERT(isFloat(type)); 1651 RELEASE_ASSERT(state.scratchFPR != InvalidFPRReg); 1652 switch (elementSize(type)) { 1653 case 4: 1654 jit.convertDoubleToFloat(state.scratchFPR, state.scratchFPR); 1655 jit.storeFloat(state.scratchFPR, CCallHelpers::BaseIndex(scratch2GPR, scratchGPR, CCallHelpers::TimesFour)); 1656 break; 1657 case 8: { 1658 jit.storeDouble(state.scratchFPR, CCallHelpers::BaseIndex(scratch2GPR, scratchGPR, CCallHelpers::TimesEight)); 1659 break; 1660 } 1661 default: 1662 CRASH(); 1663 } 1664 } 1665 1666 allocator.restoreReusedRegistersByPopping(jit, preservedState); 1667 state.succeed(); 1668 return; 1669 } 1670 1671 case InstanceOfHit: 1672 case InstanceOfMiss: 1673 emitDefaultGuard(); 1674 1675 fallThrough.append( 1676 jit.branchPtr( 1677 CCallHelpers::NotEqual, state.u.prototypeGPR, 1678 CCallHelpers::TrustedImmPtr(as<InstanceOfAccessCase>().prototype()))); 1679 break; 1680 1681 case InstanceOfGeneric: { 1682 ASSERT(!viaProxy()); 1683 GPRReg prototypeGPR = state.u.prototypeGPR; 1684 // Legend: value = `base instanceof prototypeGPR`. 1685 1686 GPRReg valueGPR = valueRegs.payloadGPR(); 1687 1688 ScratchRegisterAllocator allocator(stubInfo.usedRegisters); 1689 allocator.lock(stubInfo.baseRegs()); 1690 allocator.lock(valueRegs); 1691 allocator.lock(stubInfo.propertyRegs()); 1692 if (stubInfo.m_stubInfoGPR != InvalidGPRReg) 1693 allocator.lock(stubInfo.m_stubInfoGPR); 1694 ASSERT(stubInfo.m_arrayProfileGPR == InvalidGPRReg); 1325 1695 allocator.lock(scratchGPR); 1326 1696 … … 1895 2265 allocator.lock(stubInfo.baseRegs()); 1896 2266 allocator.lock(valueRegs); 2267 if (stubInfo.propertyRegs()) 2268 allocator.lock(stubInfo.propertyRegs()); 1897 2269 if (stubInfo.m_stubInfoGPR != InvalidGPRReg) 1898 2270 allocator.lock(stubInfo.m_stubInfoGPR); 2271 if (stubInfo.m_arrayProfileGPR != InvalidGPRReg) 2272 allocator.lock(stubInfo.m_arrayProfileGPR); 1899 2273 allocator.lock(scratchGPR); 1900 2274 … … 2059 2433 if (stubInfo.m_stubInfoGPR != InvalidGPRReg) 2060 2434 allocator.lock(stubInfo.m_stubInfoGPR); 2435 ASSERT(stubInfo.m_arrayProfileGPR == InvalidGPRReg); 2061 2436 allocator.lock(scratchGPR); 2062 2437 ASSERT(structure()->transitionWatchpointSetHasBeenInvalidated()); … … 2184 2559 case IndexedStringLoad: 2185 2560 case CheckPrivateBrand: 2561 case IndexedInt32Store: 2562 case IndexedDoubleStore: 2563 case IndexedContiguousStore: 2564 case IndexedArrayStorageStore: 2565 case IndexedTypedArrayInt8Store: 2566 case IndexedTypedArrayUint8Store: 2567 case IndexedTypedArrayUint8ClampedStore: 2568 case IndexedTypedArrayInt16Store: 2569 case IndexedTypedArrayUint16Store: 2570 case IndexedTypedArrayInt32Store: 2571 case IndexedTypedArrayUint32Store: 2572 case IndexedTypedArrayFloat32Store: 2573 case IndexedTypedArrayFloat64Store: 2186 2574 // These need to be handled by generateWithGuard(), since the guard is part of the 2187 2575 // algorithm. We can be sure that nobody will call generate() directly for these since they … … 2197 2585 switch (accessType) { 2198 2586 case IndexedTypedArrayInt8Load: 2587 case IndexedTypedArrayInt8Store: 2199 2588 return TypeInt8; 2200 2589 case IndexedTypedArrayUint8Load: 2590 case IndexedTypedArrayUint8Store: 2201 2591 return TypeUint8; 2202 2592 case IndexedTypedArrayUint8ClampedLoad: 2593 case IndexedTypedArrayUint8ClampedStore: 2203 2594 return TypeUint8Clamped; 2204 2595 case IndexedTypedArrayInt16Load: 2596 case IndexedTypedArrayInt16Store: 2205 2597 return TypeInt16; 2206 2598 case IndexedTypedArrayUint16Load: 2599 case IndexedTypedArrayUint16Store: 2207 2600 return TypeUint16; 2208 2601 case IndexedTypedArrayInt32Load: 2602 case IndexedTypedArrayInt32Store: 2209 2603 return TypeInt32; 2210 2604 case IndexedTypedArrayUint32Load: 2605 case IndexedTypedArrayUint32Store: 2211 2606 return TypeUint32; 2212 2607 case IndexedTypedArrayFloat32Load: 2608 case IndexedTypedArrayFloat32Store: 2213 2609 return TypeFloat32; 2214 2610 case IndexedTypedArrayFloat64Load: 2611 case IndexedTypedArrayFloat64Store: 2215 2612 return TypeFloat64; 2216 2613 default: … … 2285 2682 case IndexedTypedArrayFloat32Load: 2286 2683 case IndexedTypedArrayFloat64Load: 2684 case IndexedInt32Store: 2685 case IndexedDoubleStore: 2686 case IndexedContiguousStore: 2687 case IndexedArrayStorageStore: 2688 case IndexedTypedArrayInt8Store: 2689 case IndexedTypedArrayUint8Store: 2690 case IndexedTypedArrayUint8ClampedStore: 2691 case IndexedTypedArrayInt16Store: 2692 case IndexedTypedArrayUint16Store: 2693 case IndexedTypedArrayInt32Store: 2694 case IndexedTypedArrayUint32Store: 2695 case IndexedTypedArrayFloat32Store: 2696 case IndexedTypedArrayFloat64Store: 2287 2697 case IndexedStringLoad: 2288 2698 case InstanceOfGeneric: -
trunk/Source/JavaScriptCore/bytecode/AccessCase.h
r279813 r281615 129 129 IndexedTypedArrayFloat32Load, 130 130 IndexedTypedArrayFloat64Load, 131 IndexedStringLoad 131 IndexedStringLoad, 132 IndexedInt32Store, 133 IndexedDoubleStore, 134 IndexedContiguousStore, 135 IndexedArrayStorageStore, 136 IndexedTypedArrayInt8Store, 137 IndexedTypedArrayUint8Store, 138 IndexedTypedArrayUint8ClampedStore, 139 IndexedTypedArrayInt16Store, 140 IndexedTypedArrayUint16Store, 141 IndexedTypedArrayInt32Store, 142 IndexedTypedArrayUint32Store, 143 IndexedTypedArrayFloat32Store, 144 IndexedTypedArrayFloat64Store, 132 145 }; 133 146 … … 354 367 Key() = default; 355 368 356 Key(GPRReg baseGPR, GPRReg valueGPR, GPRReg extraGPR, GPRReg stubInfoGPR, RegisterSet usedRegisters, PolymorphicAccessJITStubRoutine* wrapped)369 Key(GPRReg baseGPR, GPRReg valueGPR, GPRReg extraGPR, GPRReg stubInfoGPR, GPRReg arrayProfileGPR, RegisterSet usedRegisters, PolymorphicAccessJITStubRoutine* wrapped) 357 370 : m_wrapped(wrapped) 358 371 , m_baseGPR(baseGPR) … … 360 373 , m_extraGPR(extraGPR) 361 374 , m_stubInfoGPR(stubInfoGPR) 375 , m_arrayProfileGPR(arrayProfileGPR) 362 376 , m_usedRegisters(usedRegisters) 363 377 { } … … 376 390 && a.m_extraGPR == b.m_extraGPR 377 391 && a.m_stubInfoGPR == b.m_stubInfoGPR 392 && a.m_arrayProfileGPR == b.m_arrayProfileGPR 378 393 && a.m_usedRegisters == b.m_usedRegisters; 379 394 } … … 384 399 GPRReg m_extraGPR; 385 400 GPRReg m_stubInfoGPR; 401 GPRReg m_arrayProfileGPR; 386 402 RegisterSet m_usedRegisters; 387 403 }; … … 417 433 && a.m_extraGPR == b.m_extraGPR 418 434 && a.m_stubInfoGPR == b.m_stubInfoGPR 435 && a.m_arrayProfileGPR == b.m_arrayProfileGPR 419 436 && a.m_usedRegisters == b.m_usedRegisters) { 420 437 // FIXME: The ordering of cases does not matter for sharing capabilities. … … 446 463 GPRReg m_extraGPR; 447 464 GPRReg m_stubInfoGPR; 465 GPRReg m_arrayProfileGPR; 448 466 RegisterSet m_usedRegisters; 449 467 const FixedVector<RefPtr<AccessCase>>& m_cases; -
trunk/Source/JavaScriptCore/bytecode/ArrayProfile.h
r272170 r281615 209 209 bool* addressOfMayStoreToHole() { return &m_mayStoreToHole; } 210 210 211 static ptrdiff_t offsetOfMayStoreToHole() { return OBJECT_OFFSETOF(ArrayProfile, m_mayStoreToHole); } 212 static ptrdiff_t offsetOfLastSeenStructureID() { return OBJECT_OFFSETOF(ArrayProfile, m_lastSeenStructureID); } 213 211 214 void setOutOfBounds() { m_outOfBounds = true; } 212 215 bool* addressOfOutOfBounds() { return &m_outOfBounds; } -
trunk/Source/JavaScriptCore/bytecode/GetterSetterAccessCase.cpp
r278656 r281615 142 142 if (stubInfo.m_stubInfoGPR != InvalidGPRReg) 143 143 allocator.lock(stubInfo.m_stubInfoGPR); 144 ASSERT(stubInfo.m_arrayProfileGPR == InvalidGPRReg); 144 145 allocator.lock(scratchGPR); 145 146 -
trunk/Source/JavaScriptCore/bytecode/ICStatusMap.h
r278445 r281615 37 37 class GetByStatus; 38 38 class InByStatus; 39 class PutBy IdStatus;39 class PutByStatus; 40 40 class DeleteByStatus; 41 41 class StructureStubInfo; … … 49 49 GetByStatus* getStatus { nullptr }; 50 50 InByStatus* inStatus { nullptr }; 51 PutBy IdStatus* putStatus { nullptr };51 PutByStatus* putStatus { nullptr }; 52 52 DeleteByStatus* deleteStatus { nullptr }; 53 53 }; -
trunk/Source/JavaScriptCore/bytecode/InlineAccess.cpp
r278656 r281615 217 217 allocator.lock(stubInfo.valueTagGPR); 218 218 #endif 219 if (stubInfo.propertyRegs()) 220 allocator.lock(stubInfo.propertyRegs()); 219 221 if (stubInfo.m_stubInfoGPR != InvalidGPRReg) 220 222 allocator.lock(stubInfo.m_stubInfoGPR); 223 if (stubInfo.m_arrayProfileGPR != InvalidGPRReg) 224 allocator.lock(stubInfo.m_arrayProfileGPR); 221 225 GPRReg scratch = allocator.allocateScratchGPR(); 222 226 if (allocator.didReuseRegisters()) -
trunk/Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp
r279813 r281615 495 495 if (stubInfo.m_stubInfoGPR != InvalidGPRReg) 496 496 allocator.lock(stubInfo.m_stubInfoGPR); 497 if (stubInfo.m_arrayProfileGPR != InvalidGPRReg) 498 allocator.lock(stubInfo.m_arrayProfileGPR); 497 499 498 500 state.scratchGPR = allocator.allocateScratchGPR(); … … 811 813 stubInfo.regs.thisGPR, 812 814 stubInfo.m_stubInfoGPR, 815 stubInfo.m_arrayProfileGPR, 813 816 stubInfo.usedRegisters, 814 817 keys, … … 847 850 if (codeBlock->useDataIC()) { 848 851 if (canBeShared) 849 vm.m_sharedJITStubs->add(SharedJITStubSet::Hash::Key(stubInfo.baseGPR, stubInfo.valueGPR, stubInfo.regs.thisGPR, stubInfo.m_stubInfoGPR, stubInfo. usedRegisters, stub.get()));852 vm.m_sharedJITStubs->add(SharedJITStubSet::Hash::Key(stubInfo.baseGPR, stubInfo.valueGPR, stubInfo.regs.thisGPR, stubInfo.m_stubInfoGPR, stubInfo.m_arrayProfileGPR, stubInfo.usedRegisters, stub.get())); 850 853 } 851 854 … … 1023 1026 out.print("IndexedStringLoad"); 1024 1027 return; 1028 case AccessCase::IndexedInt32Store: 1029 out.print("IndexedInt32Store"); 1030 return; 1031 case AccessCase::IndexedDoubleStore: 1032 out.print("IndexedDoubleStore"); 1033 return; 1034 case AccessCase::IndexedContiguousStore: 1035 out.print("IndexedContiguousStore"); 1036 return; 1037 case AccessCase::IndexedArrayStorageStore: 1038 out.print("IndexedArrayStorageStore"); 1039 return; 1040 case AccessCase::IndexedTypedArrayInt8Store: 1041 out.print("IndexedTypedArrayInt8Store"); 1042 return; 1043 case AccessCase::IndexedTypedArrayUint8Store: 1044 out.print("IndexedTypedArrayUint8Store"); 1045 return; 1046 case AccessCase::IndexedTypedArrayUint8ClampedStore: 1047 out.print("IndexedTypedArrayUint8ClampedStore"); 1048 return; 1049 case AccessCase::IndexedTypedArrayInt16Store: 1050 out.print("IndexedTypedArrayInt16Store"); 1051 return; 1052 case AccessCase::IndexedTypedArrayUint16Store: 1053 out.print("IndexedTypedArrayUint16Store"); 1054 return; 1055 case AccessCase::IndexedTypedArrayInt32Store: 1056 out.print("IndexedTypedArrayInt32Store"); 1057 return; 1058 case AccessCase::IndexedTypedArrayUint32Store: 1059 out.print("IndexedTypedArrayUint32Store"); 1060 return; 1061 case AccessCase::IndexedTypedArrayFloat32Store: 1062 out.print("IndexedTypedArrayFloat32Store"); 1063 return; 1064 case AccessCase::IndexedTypedArrayFloat64Store: 1065 out.print("IndexedTypedArrayFloat64Store"); 1066 return; 1025 1067 } 1026 1068 -
trunk/Source/JavaScriptCore/bytecode/PutByStatus.cpp
r281614 r281615 25 25 26 26 #include "config.h" 27 #include "PutBy IdStatus.h"27 #include "PutByStatus.h" 28 28 29 29 #include "BytecodeStructs.h" … … 39 39 namespace JSC { 40 40 41 bool PutBy IdStatus::appendVariant(const PutByIdVariant& variant)41 bool PutByStatus::appendVariant(const PutByVariant& variant) 42 42 { 43 43 return appendICStatusVariant(m_variants, variant); 44 44 } 45 45 46 void PutBy IdStatus::shrinkToFit()46 void PutByStatus::shrinkToFit() 47 47 { 48 48 m_variants.shrinkToFit(); 49 49 } 50 50 51 PutBy IdStatus PutByIdStatus::computeFromLLInt(CodeBlock* profiledBlock, BytecodeIndex bytecodeIndex, UniquedStringImpl* uid)51 PutByStatus PutByStatus::computeFromLLInt(CodeBlock* profiledBlock, BytecodeIndex bytecodeIndex) 52 52 { 53 53 VM& vm = profiledBlock->vm(); … … 55 55 auto instruction = profiledBlock->instructions().at(bytecodeIndex.offset()); 56 56 57 // We are not yet using `computeFromLLInt` in any place for `put_private_name`. 58 // We can add support for it if this is required in future changes, since we have 59 // IC implemented for this operation on LLInt. 60 ASSERT(!instruction->is<OpPutPrivateName>()); 57 switch (instruction->opcodeID()) { 58 case op_put_by_id: 59 break; 60 case op_put_by_val: 61 case op_put_by_val_direct: 62 return PutByStatus(NoInformation); 63 case op_put_private_name: 64 // We do no have a code retrieving LLInt information for `op_put_private_name`. 65 // We can add support for it if this is required in future changes, since we have 66 // IC implemented for this operation on LLInt. 67 return PutByStatus(NoInformation); 68 default: { 69 RELEASE_ASSERT_NOT_REACHED(); 70 break; 71 } 72 } 61 73 62 74 auto bytecode = instruction->as<OpPutById>(); 63 75 auto& metadata = bytecode.metadata(profiledBlock); 76 const Identifier* identifier = &(profiledBlock->identifier(bytecode.m_property)); 77 UniquedStringImpl* uid = identifier->impl(); 64 78 65 79 StructureID structureID = metadata.m_oldStructureID; 66 80 if (!structureID) 67 return PutBy IdStatus(NoInformation);81 return PutByStatus(NoInformation); 68 82 69 83 Structure* structure = vm.heap.structureIDTable().get(structureID); … … 73 87 PropertyOffset offset = structure->getConcurrently(uid); 74 88 if (!isValidOffset(offset)) 75 return PutBy IdStatus(NoInformation);76 77 return PutBy IdVariant::replace(structure, offset);89 return PutByStatus(NoInformation); 90 91 return PutByVariant::replace(nullptr, structure, offset); 78 92 } 79 93 … … 84 98 PropertyOffset offset = newStructure->getConcurrently(uid); 85 99 if (!isValidOffset(offset)) 86 return PutBy IdStatus(NoInformation);100 return PutByStatus(NoInformation); 87 101 88 102 ObjectPropertyConditionSet conditionSet; … … 92 106 vm, profiledBlock->globalObject(), structure, uid); 93 107 if (!conditionSet.isValid()) 94 return PutByIdStatus(NoInformation); 95 } 96 97 return PutByIdVariant::transition( 98 structure, newStructure, conditionSet, offset); 108 return PutByStatus(NoInformation); 109 } 110 111 return PutByVariant::transition(nullptr, structure, newStructure, conditionSet, offset); 99 112 } 100 113 101 114 #if ENABLE(JIT) 102 PutByIdStatus PutByIdStatus::computeFor(CodeBlock* profiledBlock, ICStatusMap& map, BytecodeIndex bytecodeIndex, UniquedStringImpl* uid, ExitFlag didExit, CallLinkStatus::ExitSiteData callExitSiteData) 115 PutByStatus::PutByStatus(StubInfoSummary summary, StructureStubInfo& stubInfo) 116 { 117 switch (summary) { 118 case StubInfoSummary::NoInformation: 119 m_state = NoInformation; 120 return; 121 case StubInfoSummary::Simple: 122 case StubInfoSummary::MakesCalls: 123 RELEASE_ASSERT_NOT_REACHED(); 124 return; 125 case StubInfoSummary::TakesSlowPath: 126 m_state = stubInfo.tookSlowPath ? ObservedTakesSlowPath : LikelyTakesSlowPath; 127 return; 128 case StubInfoSummary::TakesSlowPathAndMakesCalls: 129 m_state = stubInfo.tookSlowPath ? ObservedSlowPathAndMakesCalls : MakesCalls; 130 return; 131 } 132 RELEASE_ASSERT_NOT_REACHED(); 133 } 134 135 PutByStatus PutByStatus::computeFor(CodeBlock* profiledBlock, ICStatusMap& map, BytecodeIndex bytecodeIndex, ExitFlag didExit, CallLinkStatus::ExitSiteData callExitSiteData) 103 136 { 104 137 ConcurrentJSLocker locker(profiledBlock->m_lock); … … 106 139 UNUSED_PARAM(profiledBlock); 107 140 UNUSED_PARAM(bytecodeIndex); 108 UNUSED_PARAM(uid);109 141 #if ENABLE(DFG_JIT) 110 142 if (didExit) 111 return PutBy IdStatus(TakesSlowPath);143 return PutByStatus(LikelyTakesSlowPath); 112 144 113 145 StructureStubInfo* stubInfo = map.get(CodeOrigin(bytecodeIndex)).stubInfo; 114 PutBy IdStatus result = computeForStubInfo(115 locker, profiledBlock, stubInfo, uid,callExitSiteData);146 PutByStatus result = computeForStubInfo( 147 locker, profiledBlock, stubInfo, callExitSiteData); 116 148 if (!result) 117 return computeFromLLInt(profiledBlock, bytecodeIndex , uid);149 return computeFromLLInt(profiledBlock, bytecodeIndex); 118 150 119 151 return result; … … 122 154 UNUSED_PARAM(didExit); 123 155 UNUSED_PARAM(callExitSiteData); 124 return PutBy IdStatus(NoInformation);156 return PutByStatus(NoInformation); 125 157 #endif // ENABLE(JIT) 126 158 } 127 159 128 PutBy IdStatus PutByIdStatus::computeForStubInfo(const ConcurrentJSLocker& locker, CodeBlock* baselineBlock, StructureStubInfo* stubInfo, CodeOrigin codeOrigin, UniquedStringImpl* uid)160 PutByStatus PutByStatus::computeForStubInfo(const ConcurrentJSLocker& locker, CodeBlock* baselineBlock, StructureStubInfo* stubInfo, CodeOrigin codeOrigin) 129 161 { 130 162 return computeForStubInfo( 131 locker, baselineBlock, stubInfo, uid,163 locker, baselineBlock, stubInfo, 132 164 CallLinkStatus::computeExitSiteData(baselineBlock, codeOrigin.bytecodeIndex())); 133 165 } 134 166 135 PutByIdStatus PutByIdStatus::computeForStubInfo( 136 const ConcurrentJSLocker& locker, CodeBlock* profiledBlock, StructureStubInfo* stubInfo, 137 UniquedStringImpl* uid, CallLinkStatus::ExitSiteData callExitSiteData) 167 PutByStatus PutByStatus::computeForStubInfo(const ConcurrentJSLocker& locker, CodeBlock* profiledBlock, StructureStubInfo* stubInfo, CallLinkStatus::ExitSiteData callExitSiteData) 138 168 { 139 169 StubInfoSummary summary = StructureStubInfo::summary(profiledBlock->vm(), stubInfo); 140 170 if (!isInlineable(summary)) 141 return PutBy IdStatus(summary);171 return PutByStatus(summary, *stubInfo); 142 172 143 173 switch (stubInfo->cacheType()) { 144 174 case CacheType::Unset: 145 175 // This means that we attempted to cache but failed for some reason. 146 return PutBy IdStatus(JSC::slowVersion(summary));176 return PutByStatus(JSC::slowVersion(summary), *stubInfo); 147 177 148 178 case CacheType::PutByIdReplace: { 179 CacheableIdentifier identifier = stubInfo->identifier(); 180 UniquedStringImpl* uid = identifier.uid(); 181 RELEASE_ASSERT(uid); 149 182 PropertyOffset offset = 150 183 stubInfo->m_inlineAccessBaseStructure->getConcurrently(uid); 151 if (isValidOffset(offset)) { 152 return PutByIdVariant::replace( 153 stubInfo->m_inlineAccessBaseStructure.get(), offset); 154 } 155 return PutByIdStatus(JSC::slowVersion(summary)); 184 if (isValidOffset(offset)) 185 return PutByVariant::replace(WTFMove(identifier), stubInfo->m_inlineAccessBaseStructure.get(), offset); 186 return PutByStatus(JSC::slowVersion(summary), *stubInfo); 156 187 } 157 188 … … 159 190 PolymorphicAccess* list = stubInfo->u.stub; 160 191 161 PutBy IdStatus result;192 PutByStatus result; 162 193 result.m_state = Simple; 163 194 … … 165 196 const AccessCase& access = list->at(i); 166 197 if (access.viaProxy()) 167 return PutBy IdStatus(JSC::slowVersion(summary));198 return PutByStatus(JSC::slowVersion(summary), *stubInfo); 168 199 if (access.usesPolyProto()) 169 return PutByIdStatus(JSC::slowVersion(summary)); 170 171 PutByIdVariant variant; 200 return PutByStatus(JSC::slowVersion(summary), *stubInfo); 172 201 173 202 switch (access.type()) { 174 203 case AccessCase::Replace: { 175 204 Structure* structure = access.structure(); 176 PropertyOffset offset = structure->getConcurrently( uid);205 PropertyOffset offset = structure->getConcurrently(access.uid()); 177 206 if (!isValidOffset(offset)) 178 return PutByIdStatus(JSC::slowVersion(summary)); 179 variant = PutByIdVariant::replace( 180 structure, offset); 207 return PutByStatus(JSC::slowVersion(summary), *stubInfo); 208 auto variant = PutByVariant::replace(access.identifier(), structure, offset); 209 if (!result.appendVariant(variant)) 210 return PutByStatus(JSC::slowVersion(summary), *stubInfo); 181 211 break; 182 212 } 183 213 184 214 case AccessCase::Transition: { 185 PropertyOffset offset = 186 access.newStructure()->getConcurrently(uid); 215 PropertyOffset offset = access.newStructure()->getConcurrently(access.uid()); 187 216 if (!isValidOffset(offset)) 188 return PutBy IdStatus(JSC::slowVersion(summary));217 return PutByStatus(JSC::slowVersion(summary), *stubInfo); 189 218 ObjectPropertyConditionSet conditionSet = access.conditionSet(); 190 219 if (!conditionSet.structuresEnsureValidity()) 191 return PutByIdStatus(JSC::slowVersion(summary)); 192 variant = PutByIdVariant::transition( 193 access.structure(), access.newStructure(), conditionSet, offset); 220 return PutByStatus(JSC::slowVersion(summary), *stubInfo); 221 auto variant = PutByVariant::transition(access.identifier(), access.structure(), access.newStructure(), conditionSet, offset); 222 if (!result.appendVariant(variant)) 223 return PutByStatus(JSC::slowVersion(summary), *stubInfo); 194 224 break; 195 225 } … … 198 228 Structure* structure = access.structure(); 199 229 200 ComplexGetStatus complexGetStatus = ComplexGetStatus::computeFor( 201 structure, access.conditionSet(), uid); 230 ComplexGetStatus complexGetStatus = ComplexGetStatus::computeFor(structure, access.conditionSet(), access.uid()); 202 231 203 232 switch (complexGetStatus.kind()) { … … 206 235 207 236 case ComplexGetStatus::TakesSlowPath: 208 return PutBy IdStatus(JSC::slowVersion(summary));237 return PutByStatus(JSC::slowVersion(summary), *stubInfo); 209 238 210 239 case ComplexGetStatus::Inlineable: { … … 216 245 } 217 246 218 variant = PutByIdVariant::setter( 219 structure, complexGetStatus.offset(), complexGetStatus.conditionSet(), 220 WTFMove(callLinkStatus)); 221 } } 247 auto variant = PutByVariant::setter(access.identifier(), structure, complexGetStatus.offset(), complexGetStatus.conditionSet(), WTFMove(callLinkStatus)); 248 if (!result.appendVariant(variant)) 249 return PutByStatus(JSC::slowVersion(summary), *stubInfo); 250 } 251 } 222 252 break; 223 253 } … … 225 255 case AccessCase::CustomValueSetter: 226 256 case AccessCase::CustomAccessorSetter: 227 return PutBy IdStatus(MakesCalls);257 return PutByStatus(MakesCalls); 228 258 229 259 default: 230 return PutByIdStatus(JSC::slowVersion(summary)); 231 } 232 233 if (!result.appendVariant(variant)) 234 return PutByIdStatus(JSC::slowVersion(summary)); 260 return PutByStatus(JSC::slowVersion(summary), *stubInfo); 261 } 235 262 } 236 263 … … 240 267 241 268 default: 242 return PutBy IdStatus(JSC::slowVersion(summary));243 } 244 } 245 246 PutBy IdStatus PutByIdStatus::computeFor(CodeBlock* baselineBlock, ICStatusMap& baselineMap, ICStatusContextStack& contextStack, CodeOrigin codeOrigin, UniquedStringImpl* uid)269 return PutByStatus(JSC::slowVersion(summary), *stubInfo); 270 } 271 } 272 273 PutByStatus PutByStatus::computeFor(CodeBlock* baselineBlock, ICStatusMap& baselineMap, ICStatusContextStack& contextStack, CodeOrigin codeOrigin) 247 274 { 248 275 BytecodeIndex bytecodeIndex = codeOrigin.bytecodeIndex(); … … 253 280 ICStatus status = context->get(codeOrigin); 254 281 255 auto bless = [&] (const PutBy IdStatus& result) -> PutByIdStatus {282 auto bless = [&] (const PutByStatus& result) -> PutByStatus { 256 283 if (!context->isInlined(codeOrigin)) { 257 PutBy IdStatus baselineResult = computeFor(258 baselineBlock, baselineMap, bytecodeIndex, uid,didExit,284 PutByStatus baselineResult = computeFor( 285 baselineBlock, baselineMap, bytecodeIndex, didExit, 259 286 callExitSiteData); 260 287 baselineResult.merge(result); … … 267 294 268 295 if (status.stubInfo) { 269 PutBy IdStatus result;296 PutByStatus result; 270 297 { 271 298 ConcurrentJSLocker locker(context->optimizedCodeBlock->m_lock); 272 299 result = computeForStubInfo( 273 locker, context->optimizedCodeBlock, status.stubInfo, uid,callExitSiteData);300 locker, context->optimizedCodeBlock, status.stubInfo, callExitSiteData); 274 301 } 275 302 if (result.isSet()) … … 281 308 } 282 309 283 return computeFor(baselineBlock, baselineMap, bytecodeIndex, uid, didExit, callExitSiteData); 284 } 285 286 PutByIdStatus PutByIdStatus::computeFor(JSGlobalObject* globalObject, const StructureSet& set, UniquedStringImpl* uid, bool isDirect, PrivateFieldPutKind privateFieldPutKind) 287 { 310 return computeFor(baselineBlock, baselineMap, bytecodeIndex, didExit, callExitSiteData); 311 } 312 313 PutByStatus PutByStatus::computeFor(JSGlobalObject* globalObject, const StructureSet& set, CacheableIdentifier identifier, bool isDirect, PrivateFieldPutKind privateFieldPutKind) 314 { 315 UniquedStringImpl* uid = identifier.uid(); 288 316 if (parseIndex(*uid)) 289 return PutBy IdStatus(TakesSlowPath);317 return PutByStatus(LikelyTakesSlowPath); 290 318 291 319 if (set.isEmpty()) 292 return PutBy IdStatus();320 return PutByStatus(); 293 321 294 322 VM& vm = globalObject->vm(); 295 PutBy IdStatus result;323 PutByStatus result; 296 324 result.m_state = Simple; 297 325 for (unsigned i = 0; i < set.size(); ++i) { … … 299 327 300 328 if (structure->typeInfo().overridesGetOwnPropertySlot() && structure->typeInfo().type() != GlobalObjectType) 301 return PutBy IdStatus(TakesSlowPath);329 return PutByStatus(LikelyTakesSlowPath); 302 330 303 331 if (!structure->propertyAccessesAreCacheable()) 304 return PutBy IdStatus(TakesSlowPath);332 return PutByStatus(LikelyTakesSlowPath); 305 333 306 334 unsigned attributes; … … 311 339 // slow path to throw exception. 312 340 if (privateFieldPutKind.isDefine()) 313 return PutBy IdStatus(TakesSlowPath);341 return PutByStatus(LikelyTakesSlowPath); 314 342 315 343 if (attributes & PropertyAttribute::CustomAccessorOrValue) 316 return PutBy IdStatus(MakesCalls);344 return PutByStatus(MakesCalls); 317 345 318 346 if (attributes & (PropertyAttribute::Accessor | PropertyAttribute::ReadOnly)) 319 return PutBy IdStatus(TakesSlowPath);347 return PutByStatus(LikelyTakesSlowPath); 320 348 321 349 WatchpointSet* replaceSet = structure->propertyReplacementWatchpointSet(offset); … … 326 354 // JIT thread, so even if we wanted to do this, we'd need to have a lazy thingy. 327 355 // So, better leave this alone and take slow path. 328 return PutByIdStatus(TakesSlowPath); 329 } 330 331 PutByIdVariant variant = 332 PutByIdVariant::replace(structure, offset); 356 return PutByStatus(LikelyTakesSlowPath); 357 } 358 359 PutByVariant variant = PutByVariant::replace(identifier, structure, offset); 333 360 if (!result.appendVariant(variant)) 334 return PutBy IdStatus(TakesSlowPath);361 return PutByStatus(LikelyTakesSlowPath); 335 362 continue; 336 363 } … … 341 368 // slow path to throw excpetion if it ever gets executed. 342 369 if (privateFieldPutKind.isSet()) 343 return PutBy IdStatus(TakesSlowPath);370 return PutByStatus(LikelyTakesSlowPath); 344 371 345 372 // Our hypothesis is that we're doing a transition. Before we prove that this is really … … 348 375 // Don't cache put transitions on dictionaries. 349 376 if (structure->isDictionary()) 350 return PutBy IdStatus(TakesSlowPath);377 return PutByStatus(LikelyTakesSlowPath); 351 378 352 379 // If the structure corresponds to something that isn't an object, then give up, since 353 380 // we don't want to be adding properties to strings. 354 381 if (!structure->typeInfo().isObject()) 355 return PutBy IdStatus(TakesSlowPath);382 return PutByStatus(LikelyTakesSlowPath); 356 383 357 384 ObjectPropertyConditionSet conditionSet; … … 361 388 vm, globalObject, structure, uid); 362 389 if (!conditionSet.isValid()) 363 return PutBy IdStatus(TakesSlowPath);390 return PutByStatus(LikelyTakesSlowPath); 364 391 } 365 392 … … 368 395 Structure::addPropertyTransitionToExistingStructureConcurrently(structure, uid, 0, offset); 369 396 if (!transition) 370 return PutBy IdStatus(TakesSlowPath);397 return PutByStatus(LikelyTakesSlowPath); 371 398 ASSERT(isValidOffset(offset)); 372 399 373 bool didAppend = result.appendVariant( 374 PutByIdVariant::transition( 375 structure, transition, conditionSet, offset)); 400 bool didAppend = result.appendVariant(PutByVariant::transition(identifier, structure, transition, conditionSet, offset)); 376 401 if (!didAppend) 377 return PutBy IdStatus(TakesSlowPath);402 return PutByStatus(LikelyTakesSlowPath); 378 403 } 379 404 … … 383 408 #endif 384 409 385 bool PutByIdStatus::makesCalls() const 386 { 387 if (m_state == MakesCalls) 410 bool PutByStatus::makesCalls() const 411 { 412 switch (m_state) { 413 case NoInformation: 414 case LikelyTakesSlowPath: 415 case ObservedTakesSlowPath: 416 return false; 417 case MakesCalls: 418 case ObservedSlowPathAndMakesCalls: 388 419 return true; 389 390 if (m_state != Simple) 420 case Simple: { 421 for (unsigned i = m_variants.size(); i--;) { 422 if (m_variants[i].makesCalls()) 423 return true; 424 } 391 425 return false; 392 393 for (unsigned i = m_variants.size(); i--;) { 394 if (m_variants[i].makesCalls()) 395 return true; 396 } 397 398 return false; 399 } 400 401 PutByIdStatus PutByIdStatus::slowVersion() const 402 { 403 return PutByIdStatus(makesCalls() ? MakesCalls : TakesSlowPath); 426 } 427 } 428 } 429 430 PutByStatus PutByStatus::slowVersion() const 431 { 432 if (observedStructureStubInfoSlowPath()) 433 return PutByStatus(makesCalls() ? ObservedSlowPathAndMakesCalls : ObservedTakesSlowPath); 434 return PutByStatus(makesCalls() ? MakesCalls : LikelyTakesSlowPath); 435 } 436 437 CacheableIdentifier PutByStatus::singleIdentifier() const 438 { 439 return singleIdentifierForICStatus(m_variants); 404 440 } 405 441 406 442 template<typename Visitor> 407 void PutByIdStatus::markIfCheap(Visitor& visitor) 408 { 409 for (PutByIdVariant& variant : m_variants) 443 void PutByStatus::visitAggregateImpl(Visitor& visitor) 444 { 445 for (PutByVariant& variant : m_variants) 446 variant.visitAggregate(visitor); 447 } 448 449 DEFINE_VISIT_AGGREGATE(PutByStatus); 450 451 template<typename Visitor> 452 void PutByStatus::markIfCheap(Visitor& visitor) 453 { 454 for (PutByVariant& variant : m_variants) 410 455 variant.markIfCheap(visitor); 411 456 } 412 457 413 template void PutBy IdStatus::markIfCheap(AbstractSlotVisitor&);414 template void PutBy IdStatus::markIfCheap(SlotVisitor&);415 416 bool PutBy IdStatus::finalize(VM& vm)417 { 418 for (PutBy IdVariant& variant : m_variants) {458 template void PutByStatus::markIfCheap(AbstractSlotVisitor&); 459 template void PutByStatus::markIfCheap(SlotVisitor&); 460 461 bool PutByStatus::finalize(VM& vm) 462 { 463 for (PutByVariant& variant : m_variants) { 419 464 if (!variant.finalize(vm)) 420 465 return false; … … 423 468 } 424 469 425 void PutBy IdStatus::merge(const PutByIdStatus& other)470 void PutByStatus::merge(const PutByStatus& other) 426 471 { 427 472 if (other.m_state == NoInformation) 428 473 return; 429 474 430 475 auto mergeSlow = [&] () { 431 *this = PutByIdStatus((makesCalls() || other.makesCalls()) ? MakesCalls : TakesSlowPath); 476 if (observedStructureStubInfoSlowPath() || other.observedStructureStubInfoSlowPath()) 477 *this = PutByStatus((makesCalls() || other.makesCalls()) ? ObservedSlowPathAndMakesCalls : ObservedTakesSlowPath); 478 else 479 *this = PutByStatus((makesCalls() || other.makesCalls()) ? MakesCalls : LikelyTakesSlowPath); 432 480 }; 433 481 434 482 switch (m_state) { 435 483 case NoInformation: … … 441 489 return mergeSlow(); 442 490 443 for (const PutBy IdVariant& other : other.m_variants) {491 for (const PutByVariant& other : other.m_variants) { 444 492 if (!appendVariant(other)) 445 493 return mergeSlow(); … … 448 496 return; 449 497 450 case TakesSlowPath: 498 case LikelyTakesSlowPath: 499 case ObservedTakesSlowPath: 451 500 case MakesCalls: 501 case ObservedSlowPathAndMakesCalls: 452 502 return mergeSlow(); 453 503 } … … 456 506 } 457 507 458 void PutBy IdStatus::filter(const StructureSet& set)508 void PutByStatus::filter(const StructureSet& set) 459 509 { 460 510 if (m_state != Simple) 461 511 return; 462 512 filterICStatusVariants(m_variants, set); 463 for (PutBy IdVariant& variant : m_variants)513 for (PutByVariant& variant : m_variants) 464 514 variant.fixTransitionToReplaceIfNecessary(); 465 515 if (m_variants.isEmpty()) … … 467 517 } 468 518 469 void PutBy IdStatus::dump(PrintStream& out) const519 void PutByStatus::dump(PrintStream& out) const 470 520 { 471 521 switch (m_state) { … … 473 523 out.print("(NoInformation)"); 474 524 return; 475 476 525 case Simple: 477 526 out.print("(", listDump(m_variants), ")"); 478 527 return; 479 480 case TakesSlowPath: 481 out.print("(TakesSlowPath)"); 528 case LikelyTakesSlowPath: 529 out.print("LikelyTakesSlowPath"); 530 return; 531 case ObservedTakesSlowPath: 532 out.print("ObservedTakesSlowPath"); 482 533 return; 483 534 case MakesCalls: 484 out.print("(MakesCalls)"); 535 out.print("MakesCalls"); 536 return; 537 case ObservedSlowPathAndMakesCalls: 538 out.print("ObservedSlowPathAndMakesCalls"); 485 539 return; 486 540 } -
trunk/Source/JavaScriptCore/bytecode/PutByStatus.h
r281614 r281615 30 30 #include "ICStatusMap.h" 31 31 #include "PrivateFieldPutKind.h" 32 #include "PutBy IdVariant.h"32 #include "PutByVariant.h" 33 33 #include "StubInfoSummary.h" 34 34 … … 44 44 typedef HashMap<CodeOrigin, StructureStubInfo*, CodeOriginApproximateHash> StubInfoMap; 45 45 46 class PutBy IdStatus final {46 class PutByStatus final { 47 47 WTF_MAKE_FAST_ALLOCATED; 48 48 public: … … 52 52 // It's cached as a simple store of some kind. 53 53 Simple, 54 // It's known to often take slow path. 55 TakesSlowPath, 56 // It's known to take paths that make calls. 57 MakesCalls 54 // It will likely take the slow path. 55 LikelyTakesSlowPath, 56 // It's known to take slow path. We also observed that the slow path was taken on StructureStubInfo. 57 ObservedTakesSlowPath, 58 // It will likely take the slow path and will make calls. 59 MakesCalls, 60 // It known to take paths that make calls. We also observed that the slow path was taken on StructureStubInfo. 61 ObservedSlowPathAndMakesCalls, 58 62 }; 59 63 60 PutBy IdStatus()64 PutByStatus() 61 65 : m_state(NoInformation) 62 66 { 63 67 } 64 68 65 explicit PutBy IdStatus(State state)69 explicit PutByStatus(State state) 66 70 : m_state(state) 67 71 { 68 ASSERT(m_state == NoInformation || m_state == TakesSlowPath || m_state == MakesCalls); 72 #if ASSERT_ENABLED 73 switch (m_state) { 74 case NoInformation: 75 case LikelyTakesSlowPath: 76 case ObservedTakesSlowPath: 77 case MakesCalls: 78 case ObservedSlowPathAndMakesCalls: 79 break; 80 default: 81 RELEASE_ASSERT_NOT_REACHED(); 82 break; 83 } 84 #endif 69 85 } 70 86 71 explicit PutByIdStatus(StubInfoSummary summary) 72 { 73 switch (summary) { 74 case StubInfoSummary::NoInformation: 75 m_state = NoInformation; 76 return; 77 case StubInfoSummary::Simple: 78 case StubInfoSummary::MakesCalls: 79 RELEASE_ASSERT_NOT_REACHED(); 80 return; 81 case StubInfoSummary::TakesSlowPath: 82 m_state = TakesSlowPath; 83 return; 84 case StubInfoSummary::TakesSlowPathAndMakesCalls: 85 m_state = MakesCalls; 86 return; 87 } 88 RELEASE_ASSERT_NOT_REACHED(); 89 } 87 explicit PutByStatus(StubInfoSummary, StructureStubInfo&); 90 88 91 PutBy IdStatus(const PutByIdVariant& variant)89 PutByStatus(const PutByVariant& variant) 92 90 : m_state(Simple) 93 91 { … … 95 93 } 96 94 97 static PutBy IdStatus computeFor(CodeBlock*, ICStatusMap&, BytecodeIndex, UniquedStringImpl* uid, ExitFlag, CallLinkStatus::ExitSiteData);98 static PutBy IdStatus computeFor(JSGlobalObject*, const StructureSet&, UniquedStringImpl* uid, bool isDirect, PrivateFieldPutKind);95 static PutByStatus computeFor(CodeBlock*, ICStatusMap&, BytecodeIndex, ExitFlag, CallLinkStatus::ExitSiteData); 96 static PutByStatus computeFor(JSGlobalObject*, const StructureSet&, CacheableIdentifier, bool isDirect, PrivateFieldPutKind); 99 97 100 static PutBy IdStatus computeFor(CodeBlock* baselineBlock, ICStatusMap& baselineMap, ICStatusContextStack& contextStack, CodeOrigin, UniquedStringImpl* uid);98 static PutByStatus computeFor(CodeBlock* baselineBlock, ICStatusMap& baselineMap, ICStatusContextStack&, CodeOrigin); 101 99 102 100 #if ENABLE(JIT) 103 static PutBy IdStatus computeForStubInfo(const ConcurrentJSLocker&, CodeBlock* baselineBlock, StructureStubInfo*, CodeOrigin, UniquedStringImpl* uid);101 static PutByStatus computeForStubInfo(const ConcurrentJSLocker&, CodeBlock* baselineBlock, StructureStubInfo*, CodeOrigin); 104 102 #endif 105 103 … … 109 107 bool operator!() const { return m_state == NoInformation; } 110 108 bool isSimple() const { return m_state == Simple; } 111 bool takesSlowPath() const { return m_state == TakesSlowPath || m_state == MakesCalls; } 109 bool takesSlowPath() const 110 { 111 switch (m_state) { 112 case LikelyTakesSlowPath: 113 case ObservedTakesSlowPath: 114 return true; 115 default: 116 return false; 117 } 118 } 112 119 bool makesCalls() const; 113 PutByIdStatus slowVersion() const; 120 PutByStatus slowVersion() const; 121 bool observedStructureStubInfoSlowPath() const { return m_state == ObservedTakesSlowPath || m_state == ObservedSlowPathAndMakesCalls; } 114 122 115 123 size_t numVariants() const { return m_variants.size(); } 116 const Vector<PutByIdVariant, 1>& variants() const { return m_variants; } 117 const PutByIdVariant& at(size_t index) const { return m_variants[index]; } 118 const PutByIdVariant& operator[](size_t index) const { return at(index); } 124 const Vector<PutByVariant, 1>& variants() const { return m_variants; } 125 const PutByVariant& at(size_t index) const { return m_variants[index]; } 126 const PutByVariant& operator[](size_t index) const { return at(index); } 127 CacheableIdentifier singleIdentifier() const; 119 128 129 DECLARE_VISIT_AGGREGATE; 120 130 template<typename Visitor> void markIfCheap(Visitor&); 121 131 bool finalize(VM&); 122 132 123 void merge(const PutBy IdStatus&);133 void merge(const PutByStatus&); 124 134 125 135 void filter(const StructureSet&); … … 129 139 private: 130 140 #if ENABLE(JIT) 131 static PutByIdStatus computeForStubInfo( 132 const ConcurrentJSLocker&, CodeBlock*, StructureStubInfo*, UniquedStringImpl* uid, 133 CallLinkStatus::ExitSiteData); 141 static PutByStatus computeForStubInfo(const ConcurrentJSLocker&, CodeBlock*, StructureStubInfo*, CallLinkStatus::ExitSiteData); 134 142 #endif 135 static PutBy IdStatus computeFromLLInt(CodeBlock*, BytecodeIndex, UniquedStringImpl* uid);143 static PutByStatus computeFromLLInt(CodeBlock*, BytecodeIndex); 136 144 137 bool appendVariant(const PutBy IdVariant&);145 bool appendVariant(const PutByVariant&); 138 146 void shrinkToFit(); 139 147 140 148 State m_state; 141 Vector<PutBy IdVariant, 1> m_variants;149 Vector<PutByVariant, 1> m_variants; 142 150 }; 143 151 -
trunk/Source/JavaScriptCore/bytecode/PutByVariant.cpp
r281614 r281615 25 25 26 26 #include "config.h" 27 #include "PutByIdVariant.h" 28 27 #include "PutByVariant.h" 28 29 #include "CacheableIdentifierInlines.h" 29 30 #include "CallLinkStatus.h" 30 31 #include "HeapInlines.h" … … 32 33 namespace JSC { 33 34 34 PutBy IdVariant::PutByIdVariant(const PutByIdVariant& other)35 : PutBy IdVariant()35 PutByVariant::PutByVariant(const PutByVariant& other) 36 : PutByVariant(other.m_identifier) 36 37 { 37 38 *this = other; 38 39 } 39 40 40 PutBy IdVariant& PutByIdVariant::operator=(const PutByIdVariant& other)41 PutByVariant& PutByVariant::operator=(const PutByVariant& other) 41 42 { 42 43 m_kind = other.m_kind; … … 49 50 else 50 51 m_callLinkStatus = nullptr; 52 m_identifier = other.m_identifier; 51 53 return *this; 52 54 } 53 55 54 PutByIdVariant PutByIdVariant::replace( 55 const StructureSet& structure, PropertyOffset offset) 56 { 57 PutByIdVariant result; 56 PutByVariant PutByVariant::replace(CacheableIdentifier identifier, const StructureSet& structure, PropertyOffset offset) 57 { 58 PutByVariant result(WTFMove(identifier)); 58 59 result.m_kind = Replace; 59 60 result.m_oldStructure = structure; … … 62 63 } 63 64 64 PutByIdVariant PutByIdVariant::transition( 65 const StructureSet& oldStructure, Structure* newStructure, 66 const ObjectPropertyConditionSet& conditionSet, PropertyOffset offset) 67 { 68 PutByIdVariant result; 65 PutByVariant PutByVariant::transition(CacheableIdentifier identifier, const StructureSet& oldStructure, Structure* newStructure, const ObjectPropertyConditionSet& conditionSet, PropertyOffset offset) 66 { 67 PutByVariant result(WTFMove(identifier)); 69 68 result.m_kind = Transition; 70 69 result.m_oldStructure = oldStructure; … … 75 74 } 76 75 77 PutByIdVariant PutByIdVariant::setter( 78 const StructureSet& structure, PropertyOffset offset, 79 const ObjectPropertyConditionSet& conditionSet, 80 std::unique_ptr<CallLinkStatus> callLinkStatus) 81 { 82 PutByIdVariant result; 76 PutByVariant PutByVariant::setter(CacheableIdentifier identifier, const StructureSet& structure, PropertyOffset offset, const ObjectPropertyConditionSet& conditionSet, std::unique_ptr<CallLinkStatus> callLinkStatus) 77 { 78 PutByVariant result(WTFMove(identifier)); 83 79 result.m_kind = Setter; 84 80 result.m_oldStructure = structure; … … 89 85 } 90 86 91 Structure* PutBy IdVariant::oldStructureForTransition() const87 Structure* PutByVariant::oldStructureForTransition() const 92 88 { 93 89 RELEASE_ASSERT(kind() == Transition); … … 103 99 } 104 100 105 void PutBy IdVariant::fixTransitionToReplaceIfNecessary()101 void PutByVariant::fixTransitionToReplaceIfNecessary() 106 102 { 107 103 if (kind() != Transition) … … 121 117 } 122 118 123 bool PutBy IdVariant::writesStructures() const119 bool PutByVariant::writesStructures() const 124 120 { 125 121 switch (kind()) { … … 132 128 } 133 129 134 bool PutBy IdVariant::reallocatesStorage() const130 bool PutByVariant::reallocatesStorage() const 135 131 { 136 132 switch (kind()) { … … 144 140 } 145 141 146 bool PutBy IdVariant::makesCalls() const142 bool PutByVariant::makesCalls() const 147 143 { 148 144 return kind() == Setter; 149 145 } 150 146 151 bool PutByIdVariant::attemptToMerge(const PutByIdVariant& other) 152 { 147 bool PutByVariant::attemptToMerge(const PutByVariant& other) 148 { 149 if (!!m_identifier != !!other.m_identifier) 150 return false; 151 152 if (m_identifier && (m_identifier != other.m_identifier)) 153 return false; 154 153 155 if (m_offset != other.m_offset) 154 156 return false; … … 170 172 171 173 case Transition: { 172 PutBy IdVariant newVariant = other;174 PutByVariant newVariant = other; 173 175 if (newVariant.attemptToMergeTransitionWithReplace(*this)) { 174 176 *this = newVariant; … … 240 242 } 241 243 242 bool PutBy IdVariant::attemptToMergeTransitionWithReplace(const PutByIdVariant& replace)244 bool PutByVariant::attemptToMergeTransitionWithReplace(const PutByVariant& replace) 243 245 { 244 246 ASSERT(m_kind == Transition); … … 264 266 265 267 template<typename Visitor> 266 void PutByIdVariant::markIfCheap(Visitor& visitor) 268 void PutByVariant::visitAggregateImpl(Visitor& visitor) 269 { 270 m_identifier.visitAggregate(visitor); 271 } 272 273 DEFINE_VISIT_AGGREGATE(PutByVariant); 274 275 template<typename Visitor> 276 void PutByVariant::markIfCheap(Visitor& visitor) 267 277 { 268 278 m_oldStructure.markIfCheap(visitor); … … 271 281 } 272 282 273 template void PutBy IdVariant::markIfCheap(AbstractSlotVisitor&);274 template void PutBy IdVariant::markIfCheap(SlotVisitor&);275 276 bool PutBy IdVariant::finalize(VM& vm)283 template void PutByVariant::markIfCheap(AbstractSlotVisitor&); 284 template void PutByVariant::markIfCheap(SlotVisitor&); 285 286 bool PutByVariant::finalize(VM& vm) 277 287 { 278 288 if (!m_oldStructure.isStillAlive(vm)) … … 287 297 } 288 298 289 void PutBy IdVariant::dump(PrintStream& out) const299 void PutByVariant::dump(PrintStream& out) const 290 300 { 291 301 dumpInContext(out, nullptr); 292 302 } 293 303 294 void PutByIdVariant::dumpInContext(PrintStream& out, DumpContext* context) const 295 { 304 void PutByVariant::dumpInContext(PrintStream& out, DumpContext* context) const 305 { 306 out.print("<"); 307 out.print("id='", m_identifier, "', "); 296 308 switch (kind()) { 297 309 case NotSet: 298 out.print(" <empty>");310 out.print("empty>"); 299 311 return; 300 312 301 313 case Replace: 302 314 out.print( 303 " <Replace: ", inContext(structure(), context), ", offset = ", offset(), ", ", ">");315 "Replace: ", inContext(structure(), context), ", offset = ", offset(), ", ", ">"); 304 316 return; 305 317 306 318 case Transition: 307 319 out.print( 308 " <Transition: ", inContext(oldStructure(), context), " to ",320 "Transition: ", inContext(oldStructure(), context), " to ", 309 321 pointerDumpInContext(newStructure(), context), ", [", 310 322 inContext(m_conditionSet, context), "], offset = ", offset(), ", ", ">"); … … 313 325 case Setter: 314 326 out.print( 315 " <Setter: ", inContext(structure(), context), ", [",327 "Setter: ", inContext(structure(), context), ", [", 316 328 inContext(m_conditionSet, context), "]"); 317 329 out.print(", offset = ", m_offset); -
trunk/Source/JavaScriptCore/bytecode/PutByVariant.h
r281614 r281615 34 34 class CallLinkStatus; 35 35 36 class PutBy IdVariant {36 class PutByVariant { 37 37 WTF_MAKE_FAST_ALLOCATED; 38 38 public: … … 44 44 }; 45 45 46 PutBy IdVariant()46 PutByVariant(CacheableIdentifier identifier) 47 47 : m_kind(NotSet) 48 48 , m_offset(invalidOffset) 49 49 , m_newStructure(nullptr) 50 , m_identifier(WTFMove(identifier)) 50 51 { 51 52 } 52 53 53 PutBy IdVariant(const PutByIdVariant&);54 PutBy IdVariant& operator=(const PutByIdVariant&);54 PutByVariant(const PutByVariant&); 55 PutByVariant& operator=(const PutByVariant&); 55 56 56 static PutBy IdVariant replace(const StructureSet&, PropertyOffset);57 static PutByVariant replace(CacheableIdentifier, const StructureSet&, PropertyOffset); 57 58 58 static PutByIdVariant transition( 59 const StructureSet& oldStructure, Structure* newStructure, 60 const ObjectPropertyConditionSet&, PropertyOffset); 59 static PutByVariant transition(CacheableIdentifier, const StructureSet& oldStructure, Structure* newStructure, const ObjectPropertyConditionSet&, PropertyOffset); 61 60 62 static PutByIdVariant setter( 63 const StructureSet&, PropertyOffset, const ObjectPropertyConditionSet&, 64 std::unique_ptr<CallLinkStatus>); 61 static PutByVariant setter(CacheableIdentifier, const StructureSet&, PropertyOffset, const ObjectPropertyConditionSet&, std::unique_ptr<CallLinkStatus>); 65 62 66 63 Kind kind() const { return m_kind; } … … 131 128 } 132 129 133 bool attemptToMerge(const PutBy IdVariant& other);130 bool attemptToMerge(const PutByVariant& other); 134 131 132 DECLARE_VISIT_AGGREGATE; 135 133 template<typename Visitor> void markIfCheap(Visitor&); 136 134 bool finalize(VM&); … … 139 137 void dumpInContext(PrintStream&, DumpContext*) const; 140 138 141 bool overlaps(const PutByIdVariant& other) 139 CacheableIdentifier identifier() const { return m_identifier; } 140 141 bool overlaps(const PutByVariant& other) 142 142 { 143 if (!!m_identifier != !!other.m_identifier) 144 return true; 145 if (m_identifier) { 146 if (m_identifier != other.m_identifier) 147 return false; 148 } 143 149 return structureSet().overlaps(other.structureSet()); 144 150 } 145 151 146 152 private: 147 bool attemptToMergeTransitionWithReplace(const PutBy IdVariant& replace);153 bool attemptToMergeTransitionWithReplace(const PutByVariant& replace); 148 154 149 155 Kind m_kind; … … 153 159 ObjectPropertyConditionSet m_conditionSet; 154 160 std::unique_ptr<CallLinkStatus> m_callLinkStatus; 161 CacheableIdentifier m_identifier; 155 162 }; 156 163 -
trunk/Source/JavaScriptCore/bytecode/RecordedStatuses.cpp
r280050 r281615 63 63 } 64 64 65 PutBy IdStatus* RecordedStatuses::addPutByIdStatus(const CodeOrigin& codeOrigin, const PutByIdStatus& status)65 PutByStatus* RecordedStatuses::addPutByStatus(const CodeOrigin& codeOrigin, const PutByStatus& status) 66 66 { 67 auto statusPtr = makeUnique<PutBy IdStatus>(status);68 PutBy IdStatus* result = statusPtr.get();67 auto statusPtr = makeUnique<PutByStatus>(status); 68 PutByStatus* result = statusPtr.get(); 69 69 puts.append(std::make_pair(codeOrigin, WTFMove(statusPtr))); 70 70 return result; … … 107 107 { 108 108 for (auto& pair : gets) 109 pair.second->visitAggregate(visitor); 110 for (auto& pair : puts) 109 111 pair.second->visitAggregate(visitor); 110 112 for (auto& pair : ins) -
trunk/Source/JavaScriptCore/bytecode/RecordedStatuses.h
r278445 r281615 31 31 #include "GetByStatus.h" 32 32 #include "InByStatus.h" 33 #include "PutBy IdStatus.h"33 #include "PutByStatus.h" 34 34 #include "SetPrivateBrandStatus.h" 35 35 … … 49 49 CallLinkStatus* addCallLinkStatus(const CodeOrigin&, const CallLinkStatus&); 50 50 GetByStatus* addGetByStatus(const CodeOrigin&, const GetByStatus&); 51 PutBy IdStatus* addPutByIdStatus(const CodeOrigin&, const PutByIdStatus&);51 PutByStatus* addPutByStatus(const CodeOrigin&, const PutByStatus&); 52 52 InByStatus* addInByStatus(const CodeOrigin&, const InByStatus&); 53 53 DeleteByStatus* addDeleteByStatus(const CodeOrigin&, const DeleteByStatus&); … … 77 77 Vector<std::pair<CodeOrigin, std::unique_ptr<CallLinkStatus>>> calls; 78 78 Vector<std::pair<CodeOrigin, std::unique_ptr<GetByStatus>>> gets; 79 Vector<std::pair<CodeOrigin, std::unique_ptr<PutBy IdStatus>>> puts;79 Vector<std::pair<CodeOrigin, std::unique_ptr<PutByStatus>>> puts; 80 80 Vector<std::pair<CodeOrigin, std::unique_ptr<InByStatus>>> ins; 81 81 Vector<std::pair<CodeOrigin, std::unique_ptr<DeleteByStatus>>> deletes; -
trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp
r280066 r281615 282 282 resetGetBy(codeBlock, *this, GetByKind::PrivateName); 283 283 break; 284 case AccessType::Put: 285 resetPutByID(codeBlock, *this); 284 case AccessType::PutById: 285 resetPutBy(codeBlock, *this, PutByKind::ById); 286 break; 287 case AccessType::PutByVal: 288 resetPutBy(codeBlock, *this, PutByKind::ByVal); 286 289 break; 287 290 case AccessType::InById: -
trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.h
r280066 r281615 55 55 TryGetById, 56 56 GetByVal, 57 Put, 57 PutById, 58 PutByVal, 58 59 InById, 59 60 InByVal, … … 366 367 } regs; 367 368 GPRReg m_stubInfoGPR { InvalidGPRReg }; 369 GPRReg m_arrayProfileGPR { InvalidGPRReg }; 368 370 #if USE(JSVALUE32_64) 369 371 GPRReg valueTagGPR; -
trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
r280760 r281615 48 48 #include "MathCommon.h" 49 49 #include "NumberConstructor.h" 50 #include "PutBy IdStatus.h"50 #include "PutByStatus.h" 51 51 #include "RegExpObject.h" 52 52 #include "SetPrivateBrandStatus.h" … … 3974 3974 3975 3975 for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) { 3976 const PutBy IdVariant& variant = node->multiPutByOffsetData().variants[i];3976 const PutByVariant& variant = node->multiPutByOffsetData().variants[i]; 3977 3977 RegisteredStructureSet thisSet = *m_graph.addStructureSet(variant.oldStructure()); 3978 3978 thisSet.filter(base); … … 3983 3983 resultingValue.merge(thisValue); 3984 3984 3985 if (variant.kind() == PutBy IdVariant::Transition) {3985 if (variant.kind() == PutByVariant::Transition) { 3986 3986 RegisteredStructure newStructure = m_graph.registerStructure(variant.newStructure()); 3987 3987 if (thisSet.onlyStructure() != newStructure) { … … 3991 3991 newSet.add(newStructure); 3992 3992 } else { 3993 ASSERT(variant.kind() == PutBy IdVariant::Replace);3993 ASSERT(variant.kind() == PutByVariant::Replace); 3994 3994 newSet.merge(thisSet); 3995 3995 } … … 4141 4141 bool isDirect = node->op() == PutByIdDirect || node->op() == PutPrivateNameById; 4142 4142 auto privateFieldPutKind = node->op() == PutPrivateNameById ? node->privateFieldPutKind() : PrivateFieldPutKind::none(); 4143 PutBy IdStatus status = PutByIdStatus::computeFor(4143 PutByStatus status = PutByStatus::computeFor( 4144 4144 m_graph.globalObjectFor(node->origin.semantic), 4145 4145 value.m_structure.toStructureSet(), 4146 node->cacheableIdentifier() .uid(),4146 node->cacheableIdentifier(), 4147 4147 isDirect, privateFieldPutKind); 4148 4148 … … 4152 4152 TransitionVector transitions; 4153 4153 4154 for (const PutBy IdVariant& variant : status.variants()) {4154 for (const PutByVariant& variant : status.variants()) { 4155 4155 for (const ObjectPropertyCondition& condition : variant.conditionSet()) { 4156 4156 if (!m_graph.watchCondition(condition)) { … … 4163 4163 break; 4164 4164 4165 if (variant.kind() == PutBy IdVariant::Transition) {4165 if (variant.kind() == PutByVariant::Transition) { 4166 4166 RegisteredStructure newStructure = m_graph.registerStructure(variant.newStructure()); 4167 4167 transitions.append( … … 4170 4170 newSet.add(newStructure); 4171 4171 } else { 4172 ASSERT(variant.kind() == PutBy IdVariant::Replace);4172 ASSERT(variant.kind() == PutByVariant::Replace); 4173 4173 newSet.merge(*m_graph.addStructureSet(variant.oldStructure())); 4174 4174 } … … 4474 4474 case FilterCallLinkStatus: 4475 4475 case FilterGetByStatus: 4476 case FilterPutBy IdStatus:4476 case FilterPutByStatus: 4477 4477 case FilterInByStatus: 4478 4478 case FilterDeleteByStatus: … … 4653 4653 } 4654 4654 4655 case FilterPutBy IdStatus: {4655 case FilterPutByStatus: { 4656 4656 AbstractValue& value = forNode(node->child1()); 4657 4657 if (value.m_structure.isFinite()) 4658 node->putBy IdStatus()->filter(value.m_structure.toStructureSet());4658 node->putByStatus()->filter(value.m_structure.toStructureSet()); 4659 4659 break; 4660 4660 } -
trunk/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp
r278445 r281615 403 403 404 404 case FilterGetByStatus: 405 case FilterPutBy IdStatus:405 case FilterPutByStatus: 406 406 case FilterCallLinkStatus: 407 407 case FilterInByStatus: … … 1266 1266 case GetButterfly: 1267 1267 case FilterGetByStatus: 1268 case FilterPutBy IdStatus:1268 case FilterPutByStatus: 1269 1269 case FilterCallLinkStatus: 1270 1270 case FilterInByStatus: -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r280760 r281615 34 34 #include "BooleanConstructor.h" 35 35 #include "BuiltinNames.h" 36 #include "ByValInfo.h"37 36 #include "BytecodeGenerator.h" 38 37 #include "BytecodeOperandsForCheckpoint.h" … … 75 74 #include "PrivateFieldPutKind.h" 76 75 #include "PutByIdFlags.h" 77 #include "PutBy IdStatus.h"76 #include "PutByStatus.h" 78 77 #include "RegExpPrototype.h" 79 78 #include "SetPrivateBrandStatus.h" … … 240 239 void checkPresenceForReplace(Node* base, UniquedStringImpl*, PropertyOffset, const StructureSet&); 241 240 242 // Works with both GetByVariant and the setter form of PutBy IdVariant.241 // Works with both GetByVariant and the setter form of PutByVariant. 243 242 template<typename VariantType> 244 243 Node* load(SpeculatedType, Node* base, unsigned identifierNumber, const VariantType&); 245 244 246 Node* store(Node* base, unsigned identifier, const PutBy IdVariant&, Node* value);245 Node* store(Node* base, unsigned identifier, const PutByVariant&, Node* value); 247 246 248 247 template<typename Op> … … 254 253 VirtualRegister destination, SpeculatedType prediction, Node* base, CacheableIdentifier, unsigned identifierNumber, GetByStatus); 255 254 void emitPutById( 256 Node* base, CacheableIdentifier, Node* value, const PutBy IdStatus&, bool isDirect, ECMAMode);255 Node* base, CacheableIdentifier, Node* value, const PutByStatus&, bool isDirect, ECMAMode); 257 256 void handlePutById( 258 Node* base, CacheableIdentifier, unsigned identifierNumber, Node* value, const PutBy IdStatus&,257 Node* base, CacheableIdentifier, unsigned identifierNumber, Node* value, const PutByStatus&, 259 258 bool isDirect, BytecodeIndex osrExitIndex, ECMAMode); 260 259 261 260 void handlePutPrivateNameById( 262 Node* base, CacheableIdentifier, unsigned identifierNumber, Node* value, const PutBy IdStatus&, PrivateFieldPutKind);261 Node* base, CacheableIdentifier, unsigned identifierNumber, Node* value, const PutByStatus&, PrivateFieldPutKind); 263 262 264 263 void handleDeleteById( … … 4515 4514 // the structures in the variant.structureSet() agree on the prototype (it would be 4516 4515 // hilariously rare if they didn't). Note that we are relying on structureSet() having 4517 // at least one element. That will always be true here because of how GetByStatus/PutBy IdStatus work.4516 // at least one element. That will always be true here because of how GetByStatus/PutByStatus work. 4518 4517 4519 4518 // FIXME: right now, if we have an OPCS, we have mono proto. However, this will … … 4594 4593 } 4595 4594 4596 Node* ByteCodeParser::store(Node* base, unsigned identifier, const PutBy IdVariant& variant, Node* value)4595 Node* ByteCodeParser::store(Node* base, unsigned identifier, const PutByVariant& variant, Node* value) 4597 4596 { 4598 RELEASE_ASSERT(variant.kind() == PutBy IdVariant::Replace);4597 RELEASE_ASSERT(variant.kind() == PutByVariant::Replace); 4599 4598 4600 4599 checkPresenceForReplace(base, m_graph.identifiers()[identifier], variant.offset(), variant.structure()); … … 4999 4998 5000 4999 void ByteCodeParser::emitPutById( 5001 Node* base, CacheableIdentifier identifier, Node* value, const PutBy IdStatus& putByIdStatus, bool isDirect, ECMAMode ecmaMode)5000 Node* base, CacheableIdentifier identifier, Node* value, const PutByStatus& putByStatus, bool isDirect, ECMAMode ecmaMode) 5002 5001 { 5003 5002 if (isDirect) 5004 5003 addToGraph(PutByIdDirect, OpInfo(identifier), OpInfo(ecmaMode), base, value); 5005 5004 else 5006 addToGraph(putBy IdStatus.makesCalls() ? PutByIdFlush : PutById, OpInfo(identifier), OpInfo(ecmaMode), base, value);5005 addToGraph(putByStatus.makesCalls() ? PutByIdFlush : PutById, OpInfo(identifier), OpInfo(ecmaMode), base, value); 5007 5006 } 5008 5007 5009 5008 void ByteCodeParser::handlePutById( 5010 5009 Node* base, CacheableIdentifier identifier, unsigned identifierNumber, Node* value, 5011 const PutBy IdStatus& putByIdStatus, bool isDirect, BytecodeIndex osrExitIndex, ECMAMode ecmaMode)5010 const PutByStatus& putByStatus, bool isDirect, BytecodeIndex osrExitIndex, ECMAMode ecmaMode) 5012 5011 { 5013 if (!putBy IdStatus.isSimple() || !putByIdStatus.numVariants() || !Options::useAccessInlining()) {5014 if (!putBy IdStatus.isSet())5012 if (!putByStatus.isSimple() || !putByStatus.numVariants() || !Options::useAccessInlining()) { 5013 if (!putByStatus.isSet()) 5015 5014 addToGraph(ForceOSRExit); 5016 emitPutById(base, identifier, value, putBy IdStatus, isDirect, ecmaMode);5015 emitPutById(base, identifier, value, putByStatus, isDirect, ecmaMode); 5017 5016 return; 5018 5017 } 5019 5018 5020 if (putBy IdStatus.numVariants() > 1) {5021 if (!m_graph.m_plan.isFTL() || putBy IdStatus.makesCalls()5019 if (putByStatus.numVariants() > 1) { 5020 if (!m_graph.m_plan.isFTL() || putByStatus.makesCalls() 5022 5021 || !Options::usePolymorphicAccessInlining() 5023 || putBy IdStatus.numVariants() > Options::maxPolymorphicAccessInliningListSize()) {5024 emitPutById(base, identifier, value, putBy IdStatus, isDirect, ecmaMode);5022 || putByStatus.numVariants() > Options::maxPolymorphicAccessInliningListSize()) { 5023 emitPutById(base, identifier, value, putByStatus, isDirect, ecmaMode); 5025 5024 return; 5026 5025 } 5027 5026 5028 5027 if (!isDirect) { 5029 for (unsigned variantIndex = putBy IdStatus.numVariants(); variantIndex--;) {5030 if (putBy IdStatus[variantIndex].kind() != PutByIdVariant::Transition)5028 for (unsigned variantIndex = putByStatus.numVariants(); variantIndex--;) { 5029 if (putByStatus[variantIndex].kind() != PutByVariant::Transition) 5031 5030 continue; 5032 if (!check(putBy IdStatus[variantIndex].conditionSet())) {5033 emitPutById(base, identifier, value, putBy IdStatus, isDirect, ecmaMode);5031 if (!check(putByStatus[variantIndex].conditionSet())) { 5032 emitPutById(base, identifier, value, putByStatus, isDirect, ecmaMode); 5034 5033 return; 5035 5034 } … … 5040 5039 m_graph.compilation()->noticeInlinedPutById(); 5041 5040 5042 addToGraph(FilterPutBy IdStatus, OpInfo(m_graph.m_plan.recordedStatuses().addPutByIdStatus(currentCodeOrigin(), putByIdStatus)), base);5043 5044 for (const PutBy IdVariant& variant : putByIdStatus.variants()) {5041 addToGraph(FilterPutByStatus, OpInfo(m_graph.m_plan.recordedStatuses().addPutByStatus(currentCodeOrigin(), putByStatus)), base); 5042 5043 for (const PutByVariant& variant : putByStatus.variants()) { 5045 5044 for (Structure* structure : variant.oldStructure()) 5046 5045 m_graph.registerStructure(structure); 5047 if (variant.kind() == PutBy IdVariant::Transition)5046 if (variant.kind() == PutByVariant::Transition) 5048 5047 m_graph.registerStructure(variant.newStructure()); 5049 5048 } 5050 5049 5051 5050 MultiPutByOffsetData* data = m_graph.m_multiPutByOffsetData.add(); 5052 data->variants = putBy IdStatus.variants();5051 data->variants = putByStatus.variants(); 5053 5052 data->identifierNumber = identifierNumber; 5054 5053 addToGraph(MultiPutByOffset, OpInfo(data), base, value); … … 5056 5055 } 5057 5056 5058 ASSERT(putBy IdStatus.numVariants() == 1);5059 const PutBy IdVariant& variant = putByIdStatus[0];5057 ASSERT(putByStatus.numVariants() == 1); 5058 const PutByVariant& variant = putByStatus[0]; 5060 5059 5061 5060 switch (variant.kind()) { 5062 case PutBy IdVariant::Replace: {5063 addToGraph(FilterPutBy IdStatus, OpInfo(m_graph.m_plan.recordedStatuses().addPutByIdStatus(currentCodeOrigin(), putByIdStatus)), base);5061 case PutByVariant::Replace: { 5062 addToGraph(FilterPutByStatus, OpInfo(m_graph.m_plan.recordedStatuses().addPutByStatus(currentCodeOrigin(), putByStatus)), base); 5064 5063 5065 5064 store(base, identifierNumber, variant, value); … … 5069 5068 } 5070 5069 5071 case PutBy IdVariant::Transition: {5072 addToGraph(FilterPutBy IdStatus, OpInfo(m_graph.m_plan.recordedStatuses().addPutByIdStatus(currentCodeOrigin(), putByIdStatus)), base);5070 case PutByVariant::Transition: { 5071 addToGraph(FilterPutByStatus, OpInfo(m_graph.m_plan.recordedStatuses().addPutByStatus(currentCodeOrigin(), putByStatus)), base); 5073 5072 5074 5073 addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.oldStructure())), base); 5075 5074 if (!check(variant.conditionSet())) { 5076 emitPutById(base, identifier, value, putBy IdStatus, isDirect, ecmaMode);5075 emitPutById(base, identifier, value, putByStatus, isDirect, ecmaMode); 5077 5076 return; 5078 5077 } … … 5136 5135 } 5137 5136 5138 case PutBy IdVariant::Setter: {5139 addToGraph(FilterPutBy IdStatus, OpInfo(m_graph.m_plan.recordedStatuses().addPutByIdStatus(currentCodeOrigin(), putByIdStatus)), base);5137 case PutByVariant::Setter: { 5138 addToGraph(FilterPutByStatus, OpInfo(m_graph.m_plan.recordedStatuses().addPutByStatus(currentCodeOrigin(), putByStatus)), base); 5140 5139 5141 5140 Node* loadedValue = load(SpecCellOther, base, identifierNumber, variant); 5142 5141 if (!loadedValue) { 5143 emitPutById(base, identifier, value, putBy IdStatus, isDirect, ecmaMode);5142 emitPutById(base, identifier, value, putByStatus, isDirect, ecmaMode); 5144 5143 return; 5145 5144 } … … 5185 5184 5186 5185 default: { 5187 emitPutById(base, identifier, value, putBy IdStatus, isDirect, ecmaMode);5186 emitPutById(base, identifier, value, putByStatus, isDirect, ecmaMode); 5188 5187 return; 5189 5188 } } … … 5192 5191 void ByteCodeParser::handlePutPrivateNameById( 5193 5192 Node* base, CacheableIdentifier identifier, unsigned identifierNumber, Node* value, 5194 const PutBy IdStatus& putByIdStatus, PrivateFieldPutKind privateFieldPutKind)5193 const PutByStatus& putByStatus, PrivateFieldPutKind privateFieldPutKind) 5195 5194 { 5196 if (!putBy IdStatus.isSimple() || !putByIdStatus.numVariants() || !Options::useAccessInlining()) {5197 if (!putBy IdStatus.isSet())5195 if (!putByStatus.isSimple() || !putByStatus.numVariants() || !Options::useAccessInlining()) { 5196 if (!putByStatus.isSet()) 5198 5197 addToGraph(ForceOSRExit); 5199 5198 addToGraph(PutPrivateNameById, OpInfo(identifier), OpInfo(privateFieldPutKind), base, value); … … 5201 5200 } 5202 5201 5203 if (putBy IdStatus.numVariants() > 1) {5204 if (!m_graph.m_plan.isFTL() || putBy IdStatus.makesCalls()5202 if (putByStatus.numVariants() > 1) { 5203 if (!m_graph.m_plan.isFTL() || putByStatus.makesCalls() 5205 5204 || !Options::usePolymorphicAccessInlining() 5206 || putBy IdStatus.numVariants() > Options::maxPolymorphicAccessInliningListSize()) {5205 || putByStatus.numVariants() > Options::maxPolymorphicAccessInliningListSize()) { 5207 5206 addToGraph(PutPrivateNameById, OpInfo(identifier), OpInfo(privateFieldPutKind), base, value); 5208 5207 return; … … 5212 5211 m_graph.compilation()->noticeInlinedPutById(); 5213 5212 5214 addToGraph(FilterPutBy IdStatus, OpInfo(m_graph.m_plan.recordedStatuses().addPutByIdStatus(currentCodeOrigin(), putByIdStatus)), base);5215 5216 for (const PutBy IdVariant& variant : putByIdStatus.variants()) {5213 addToGraph(FilterPutByStatus, OpInfo(m_graph.m_plan.recordedStatuses().addPutByStatus(currentCodeOrigin(), putByStatus)), base); 5214 5215 for (const PutByVariant& variant : putByStatus.variants()) { 5217 5216 for (Structure* structure : variant.oldStructure()) 5218 5217 m_graph.registerStructure(structure); 5219 if (variant.kind() == PutBy IdVariant::Transition)5218 if (variant.kind() == PutByVariant::Transition) 5220 5219 m_graph.registerStructure(variant.newStructure()); 5221 5220 } 5222 5221 5223 5222 MultiPutByOffsetData* data = m_graph.m_multiPutByOffsetData.add(); 5224 data->variants = putBy IdStatus.variants();5223 data->variants = putByStatus.variants(); 5225 5224 data->identifierNumber = identifierNumber; 5226 5225 addToGraph(MultiPutByOffset, OpInfo(data), base, value); … … 5228 5227 } 5229 5228 5230 ASSERT(putBy IdStatus.numVariants() == 1);5231 const PutBy IdVariant& variant = putByIdStatus[0];5229 ASSERT(putByStatus.numVariants() == 1); 5230 const PutByVariant& variant = putByStatus[0]; 5232 5231 5233 5232 switch (variant.kind()) { 5234 case PutBy IdVariant::Replace: {5233 case PutByVariant::Replace: { 5235 5234 ASSERT(privateFieldPutKind.isSet()); 5236 addToGraph(FilterPutBy IdStatus, OpInfo(m_graph.m_plan.recordedStatuses().addPutByIdStatus(currentCodeOrigin(), putByIdStatus)), base);5235 addToGraph(FilterPutByStatus, OpInfo(m_graph.m_plan.recordedStatuses().addPutByStatus(currentCodeOrigin(), putByStatus)), base); 5237 5236 5238 5237 store(base, identifierNumber, variant, value); … … 5242 5241 } 5243 5242 5244 case PutBy IdVariant::Transition: {5243 case PutByVariant::Transition: { 5245 5244 ASSERT(privateFieldPutKind.isDefine()); 5246 addToGraph(FilterPutBy IdStatus, OpInfo(m_graph.m_plan.recordedStatuses().addPutByIdStatus(currentCodeOrigin(), putByIdStatus)), base);5245 addToGraph(FilterPutByStatus, OpInfo(m_graph.m_plan.recordedStatuses().addPutByStatus(currentCodeOrigin(), putByStatus)), base); 5247 5246 5248 5247 addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.oldStructure())), base); … … 6453 6452 Node* property = get(bytecode.m_property); 6454 6453 Node* value = get(bytecode.m_value); 6455 bool tryCompileAsPutByOffset = false; 6456 6457 CacheableIdentifier identifier; 6458 unsigned identifierNumber = std::numeric_limits<unsigned>::max(); 6459 PutByIdStatus putByIdStatus; 6460 { 6461 ConcurrentJSLocker locker(m_inlineStackTop->m_profiledBlock->m_lock); 6462 ByValInfo* byValInfo = m_inlineStackTop->m_baselineMap.get(CodeOrigin(currentCodeOrigin().bytecodeIndex())).byValInfo; 6463 // FIXME: When the bytecode is not compiled in the baseline JIT, byValInfo becomes null. 6464 // At that time, there is no information. For `put_private_name`, we might have some info from 6465 // LLInt IC, including cached cell that we could use if ByVal is not available. 6466 // https://bugs.webkit.org/show_bug.cgi?id=216779 6467 if (byValInfo 6468 && byValInfo->stubInfo 6469 && !byValInfo->tookSlowPath 6470 && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIdent) 6471 && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType) 6472 && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadConstantValue)) { 6473 tryCompileAsPutByOffset = true; 6474 identifier = byValInfo->cachedId; 6475 ASSERT(identifier.isSymbolCell()); 6476 identifierNumber = m_graph.identifiers().ensure(identifier.uid()); 6477 UniquedStringImpl* uid = m_graph.identifiers()[identifierNumber]; 6478 FrozenValue* frozen = m_graph.freezeStrong(identifier.cell()); 6479 6480 addToGraph(CheckIsConstant, OpInfo(frozen), property); 6481 6482 putByIdStatus = PutByIdStatus::computeForStubInfo( 6483 locker, m_inlineStackTop->m_profiledBlock, 6484 byValInfo->stubInfo, currentCodeOrigin(), uid); 6454 bool compiledAsPutPrivateNameById = false; 6455 6456 if (!m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIdent) 6457 && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType) 6458 && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadConstantValue)) { 6459 6460 PutByStatus status = PutByStatus::computeFor(m_inlineStackTop->m_profiledBlock, m_inlineStackTop->m_baselineMap, m_icContextStack, currentCodeOrigin()); 6461 6462 if (CacheableIdentifier identifier = status.singleIdentifier()) { 6463 UniquedStringImpl* uid = identifier.uid(); 6464 unsigned identifierNumber = m_graph.identifiers().ensure(uid); 6465 if (identifier.isCell()) { 6466 FrozenValue* frozen = m_graph.freezeStrong(identifier.cell()); 6467 if (identifier.isSymbolCell()) 6468 addToGraph(CheckIsConstant, OpInfo(frozen), property); 6469 else 6470 addToGraph(CheckIdent, OpInfo(uid), property); 6471 } else 6472 addToGraph(CheckIdent, OpInfo(uid), property); 6473 6474 handlePutPrivateNameById(base, identifier, identifierNumber, value, status, bytecode.m_putKind); 6475 compiledAsPutPrivateNameById = true; 6485 6476 } 6486 6477 } 6487 6478 6488 if (tryCompileAsPutByOffset) 6489 handlePutPrivateNameById(base, identifier, identifierNumber, value, putByIdStatus, bytecode.m_putKind); 6490 else 6479 if (!compiledAsPutPrivateNameById) 6491 6480 addToGraph(PutPrivateName, OpInfo(), OpInfo(bytecode.m_putKind), base, property, value); 6492 6481 … … 6568 6557 bool direct = bytecode.m_flags.isDirect(); 6569 6558 6570 PutBy IdStatus putByIdStatus = PutByIdStatus::computeFor(6559 PutByStatus putByStatus = PutByStatus::computeFor( 6571 6560 m_inlineStackTop->m_profiledBlock, 6572 6561 m_inlineStackTop->m_baselineMap, m_icContextStack, 6573 currentCodeOrigin() , m_graph.identifiers()[identifierNumber]);6562 currentCodeOrigin()); 6574 6563 6575 handlePutById(base, CacheableIdentifier::createFromIdentifierOwnedByCodeBlock(m_inlineStackTop->m_profiledBlock, uid), identifierNumber, value, putBy IdStatus, direct, nextOpcodeIndex(), bytecode.m_flags.ecmaMode());6564 handlePutById(base, CacheableIdentifier::createFromIdentifierOwnedByCodeBlock(m_inlineStackTop->m_profiledBlock, uid), identifierNumber, value, putByStatus, direct, nextOpcodeIndex(), bytecode.m_flags.ecmaMode()); 6576 6565 NEXT_OPCODE(op_put_by_id); 6577 6566 } … … 7980 7969 addToGraph(ForceOSRExit); 7981 7970 7982 PutBy IdStatus status;7971 PutByStatus status; 7983 7972 if (uid) 7984 status = PutBy IdStatus::computeFor(globalObject, structure, uid, false, PrivateFieldPutKind::none());7973 status = PutByStatus::computeFor(globalObject, structure, CacheableIdentifier::createFromIdentifierOwnedByCodeBlock(m_inlineStackTop->m_profiledBlock, uid), false, PrivateFieldPutKind::none()); 7985 7974 else 7986 status = PutBy IdStatus(PutByIdStatus::TakesSlowPath);7975 status = PutByStatus(PutByStatus::LikelyTakesSlowPath); 7987 7976 if (status.numVariants() != 1 7988 || status[0].kind() != PutBy IdVariant::Replace7977 || status[0].kind() != PutByVariant::Replace 7989 7978 || status[0].structure().size() != 1) { 7990 7979 addToGraph(PutById, OpInfo(CacheableIdentifier::createFromIdentifierOwnedByCodeBlock(m_inlineStackTop->m_profiledBlock, uid)), OpInfo(bytecode.m_getPutInfo.ecmaMode()), get(bytecode.m_scope), get(bytecode.m_value)); … … 8815 8804 void ByteCodeParser::handlePutByVal(Bytecode bytecode, BytecodeIndex osrExitIndex) 8816 8805 { 8806 CodeBlock* codeBlock = m_inlineStackTop->m_codeBlock; 8817 8807 Node* base = get(bytecode.m_base); 8818 8808 Node* property = get(bytecode.m_property); … … 8820 8810 bool isDirect = Bytecode::opcodeID == op_put_by_val_direct; 8821 8811 bool compiledAsPutById = false; 8822 { 8823 CacheableIdentifier identifier; 8824 unsigned identifierNumber = std::numeric_limits<unsigned>::max(); 8825 PutByIdStatus putByIdStatus; 8826 { 8827 ConcurrentJSLocker locker(m_inlineStackTop->m_profiledBlock->m_lock); 8828 ByValInfo* byValInfo = m_inlineStackTop->m_baselineMap.get(CodeOrigin(currentCodeOrigin().bytecodeIndex())).byValInfo; 8829 // FIXME: When the bytecode is not compiled in the baseline JIT, byValInfo becomes null. 8830 // At that time, there is no information. 8831 if (byValInfo 8832 && byValInfo->stubInfo 8833 && !byValInfo->tookSlowPath 8834 && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIdent) 8835 && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType) 8836 && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadConstantValue)) { 8837 compiledAsPutById = true; 8838 identifier = byValInfo->cachedId; 8839 identifierNumber = m_graph.identifiers().ensure(identifier.uid()); 8840 UniquedStringImpl* uid = m_graph.identifiers()[identifierNumber]; 8841 FrozenValue* frozen = nullptr; 8842 if (identifier.isCell()) 8843 frozen = m_graph.freezeStrong(identifier.cell()); 8844 8812 8813 PutByStatus status = PutByStatus::computeFor(m_inlineStackTop->m_profiledBlock, m_inlineStackTop->m_baselineMap, m_icContextStack, currentCodeOrigin()); 8814 8815 if (!m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIdent) 8816 && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType) 8817 && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadConstantValue)) { 8818 if (CacheableIdentifier identifier = status.singleIdentifier()) { 8819 UniquedStringImpl* uid = identifier.uid(); 8820 unsigned identifierNumber = m_graph.identifiers().ensure(uid); 8821 if (identifier.isCell()) { 8822 FrozenValue* frozen = m_graph.freezeStrong(identifier.cell()); 8845 8823 if (identifier.isSymbolCell()) 8846 8824 addToGraph(CheckIsConstant, OpInfo(frozen), property); 8847 else { 8848 ASSERT(!uid->isSymbol()); 8825 else 8826 addToGraph(CheckIdent, OpInfo(uid), property); 8827 } else 8828 addToGraph(CheckIdent, OpInfo(uid), property); 8829 8830 handlePutById(base, identifier, identifierNumber, value, status, isDirect, osrExitIndex, bytecode.m_ecmaMode); 8831 compiledAsPutById = true; 8832 } else if (status.takesSlowPath()) { 8833 // Even though status is taking a slow path, it is possible that this node still has constant identifier and using PutById is always better in that case. 8834 UniquedStringImpl* uid = nullptr; 8835 JSCell* propertyCell = nullptr; 8836 if (auto* symbol = property->dynamicCastConstant<Symbol*>(*m_vm)) { 8837 uid = &symbol->uid(); 8838 propertyCell = symbol; 8839 FrozenValue* frozen = m_graph.freezeStrong(symbol); 8840 addToGraph(CheckIsConstant, OpInfo(frozen), property); 8841 } else if (auto* string = property->dynamicCastConstant<JSString*>(*m_vm)) { 8842 if (auto* impl = string->tryGetValueImpl(); impl->isAtom() && !parseIndex(*const_cast<StringImpl*>(impl))) { 8843 uid = bitwise_cast<UniquedStringImpl*>(impl); 8844 propertyCell = string; 8845 m_graph.freezeStrong(string); 8849 8846 addToGraph(CheckIdent, OpInfo(uid), property); 8850 8847 } 8851 8852 putByIdStatus = PutByIdStatus::computeForStubInfo( 8853 locker, m_inlineStackTop->m_profiledBlock, 8854 byValInfo->stubInfo, currentCodeOrigin(), uid); 8855 8856 } 8857 } 8858 8859 if (compiledAsPutById) 8860 handlePutById(base, identifier, identifierNumber, value, putByIdStatus, isDirect, osrExitIndex, bytecode.m_ecmaMode); 8848 } 8849 8850 if (uid) { 8851 unsigned identifierNumber = m_graph.identifiers().ensure(uid); 8852 handlePutById(base, CacheableIdentifier::createFromCell(propertyCell), identifierNumber, value, status, isDirect, osrExitIndex, bytecode.m_ecmaMode); 8853 compiledAsPutById = true; 8854 } 8855 } 8861 8856 } 8862 8857 8863 8858 if (!compiledAsPutById) { 8864 ArrayMode arrayMode = getArrayMode(bytecode.metadata( m_inlineStackTop->m_codeBlock).m_arrayProfile, Array::Write);8859 ArrayMode arrayMode = getArrayMode(bytecode.metadata(codeBlock).m_arrayProfile, Array::Write); 8865 8860 8866 8861 addVarArgChild(base); … … 8869 8864 addVarArgChild(nullptr); // Leave room for property storage. 8870 8865 addVarArgChild(nullptr); // Leave room for length. 8871 addToGraph(Node::VarArg, isDirect ? PutByValDirect : PutByVal, OpInfo(arrayMode.asWord()), OpInfo(bytecode.m_ecmaMode));8866 Node* putByVal = addToGraph(Node::VarArg, isDirect ? PutByValDirect : PutByVal, OpInfo(arrayMode.asWord()), OpInfo(bytecode.m_ecmaMode)); 8872 8867 m_exitOK = false; // PutByVal and PutByValDirect must be treated as if they clobber exit state, since FixupPhase may make them generic. 8868 if (status.observedStructureStubInfoSlowPath()) 8869 m_graph.m_slowPutByVal.add(putByVal); 8873 8870 } 8874 8871 } -
trunk/Source/JavaScriptCore/dfg/DFGClobberize.h
r280760 r281615 570 570 case FilterCallLinkStatus: 571 571 case FilterGetByStatus: 572 case FilterPutBy IdStatus:572 case FilterPutByStatus: 573 573 case FilterInByStatus: 574 574 case FilterDeleteByStatus: -
trunk/Source/JavaScriptCore/dfg/DFGClobbersExitState.cpp
r278445 r281615 82 82 case FilterCallLinkStatus: 83 83 case FilterGetByStatus: 84 case FilterPutBy IdStatus:84 case FilterPutByStatus: 85 85 case FilterInByStatus: 86 86 case FilterDeleteByStatus: -
trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
r278696 r281615 39 39 #include "GetByStatus.h" 40 40 #include "JSCInlines.h" 41 #include "PutBy IdStatus.h"41 #include "PutByStatus.h" 42 42 #include "StructureCache.h" 43 43 … … 502 502 503 503 for (unsigned i = 0; i < data.variants.size(); ++i) { 504 PutBy IdVariant& variant = data.variants[i];504 PutByVariant& variant = data.variants[i]; 505 505 variant.oldStructure().genericFilter([&] (Structure* structure) -> bool { 506 506 return baseValue.contains(m_graph.registerStructure(structure)); … … 514 514 } 515 515 516 if (variant.kind() == PutBy IdVariant::Transition516 if (variant.kind() == PutByVariant::Transition 517 517 && variant.oldStructure().onlyStructure() == variant.newStructure()) { 518 variant = PutByIdVariant::replace( 519 variant.oldStructure(), 520 variant.offset()); 518 variant = PutByVariant::replace(variant.identifier(), variant.oldStructure(), variant.offset()); 521 519 changed = true; 522 520 } … … 1214 1212 } 1215 1213 1216 void emitPutByOffset(unsigned indexInBlock, Node* node, const AbstractValue& baseValue, const PutBy IdVariant& variant, unsigned identifierNumber)1214 void emitPutByOffset(unsigned indexInBlock, Node* node, const AbstractValue& baseValue, const PutByVariant& variant, unsigned identifierNumber) 1217 1215 { 1218 1216 NodeOrigin origin = node->origin; … … 1225 1223 1226 1224 Transition* transition = nullptr; 1227 if (variant.kind() == PutBy IdVariant::Transition) {1225 if (variant.kind() == PutByVariant::Transition) { 1228 1226 transition = m_graph.m_transitions.add( 1229 1227 m_graph.registerStructure(variant.oldStructureForTransition()), m_graph.registerStructure(variant.newStructure())); … … 1270 1268 node->origin.exitOK = canExit; 1271 1269 1272 if (variant.kind() == PutBy IdVariant::Transition) {1270 if (variant.kind() == PutByVariant::Transition) { 1273 1271 if (didAllocateStorage) { 1274 1272 m_insertionSet.insertNode( … … 1407 1405 return; 1408 1406 1409 PutBy IdStatus status = PutByIdStatus::computeFor(1407 PutByStatus status = PutByStatus::computeFor( 1410 1408 m_graph.globalObjectFor(origin.semantic), 1411 1409 baseValue.m_structure.toStructureSet(), 1412 node->cacheableIdentifier() .uid(),1410 node->cacheableIdentifier(), 1413 1411 isDirect, privateFieldPutKind); 1414 1412 … … 1425 1423 RegisteredStructureSet newSet; 1426 1424 TransitionVector transitions; 1427 for (const PutBy IdVariant& variant : status.variants()) {1428 if (variant.kind() == PutBy IdVariant::Transition) {1425 for (const PutByVariant& variant : status.variants()) { 1426 if (variant.kind() == PutByVariant::Transition) { 1429 1427 for (const ObjectPropertyCondition& condition : variant.conditionSet()) { 1430 1428 if (m_graph.watchCondition(condition)) … … 1449 1447 newSet.add(newStructure); 1450 1448 } else { 1451 ASSERT(variant.kind() == PutBy IdVariant::Replace);1449 ASSERT(variant.kind() == PutByVariant::Replace); 1452 1450 ASSERT(privateFieldPutKind.isNone() || privateFieldPutKind.isSet()); 1453 1451 DFG_ASSERT(m_graph, node, variant.conditionSet().isEmpty()); … … 1465 1463 1466 1464 m_insertionSet.insertNode( 1467 indexInBlock, SpecNone, FilterPutBy IdStatus, node->origin,1468 OpInfo(m_graph.m_plan.recordedStatuses().addPutBy IdStatus(node->origin.semantic, status)),1465 indexInBlock, SpecNone, FilterPutByStatus, node->origin, 1466 OpInfo(m_graph.m_plan.recordedStatuses().addPutByStatus(node->origin.semantic, status)), 1469 1467 Edge(baseNode)); 1470 1468 -
trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
r280760 r281615 248 248 case FilterCallLinkStatus: 249 249 case FilterGetByStatus: 250 case FilterPutBy IdStatus:250 case FilterPutByStatus: 251 251 case FilterInByStatus: 252 252 case FilterDeleteByStatus: -
trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
r280760 r281615 1235 1235 fixEdge<CellUse>(child1); 1236 1236 fixEdge<SymbolUse>(child2); 1237 break; 1238 } 1239 if (!m_graph.m_slowPutByVal.contains(node)) { 1240 fixEdge<CellUse>(child1); 1237 1241 break; 1238 1242 } … … 2866 2870 case FilterCallLinkStatus: 2867 2871 case FilterGetByStatus: 2868 case FilterPutBy IdStatus:2872 case FilterPutByStatus: 2869 2873 case FilterInByStatus: 2870 2874 case FilterDeleteByStatus: -
trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp
r280760 r281615 386 386 if (node->hasInByStatus()) 387 387 out.print(comma, *node->inByStatus()); 388 if (node->hasPutBy IdStatus())389 out.print(comma, *node->putBy IdStatus());388 if (node->hasPutByStatus()) 389 out.print(comma, *node->putByStatus()); 390 390 if (node->hasEnumeratorMetadata()) 391 391 out.print(comma, "enumeratorModes = ", node->enumeratorMetadata().toRaw()); -
trunk/Source/JavaScriptCore/dfg/DFGGraph.h
r278945 r281615 1203 1203 1204 1204 HashSet<Node*> m_slowGetByVal; 1205 HashSet<Node*> m_slowPutByVal; 1205 1206 1206 1207 private: -
trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
r278445 r281615 253 253 finalizeInlineCaches(m_getByVals, linkBuffer); 254 254 finalizeInlineCaches(m_putByIds, linkBuffer); 255 finalizeInlineCaches(m_putByVals, linkBuffer); 255 256 finalizeInlineCaches(m_delByIds, linkBuffer); 256 257 finalizeInlineCaches(m_delByVals, linkBuffer); -
trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.h
r278656 r281615 200 200 } 201 201 202 void addPutByVal(const JITPutByValGenerator& gen, SlowPathGenerator* slowPath) 203 { 204 m_putByVals.append(InlineCacheWrapper<JITPutByValGenerator>(gen, slowPath)); 205 } 206 202 207 void addDelById(const JITDelByIdGenerator& gen, SlowPathGenerator* slowPath) 203 208 { … … 361 366 Vector<InlineCacheWrapper<JITGetByValGenerator>, 4> m_getByVals; 362 367 Vector<InlineCacheWrapper<JITPutByIdGenerator>, 4> m_putByIds; 368 Vector<InlineCacheWrapper<JITPutByValGenerator>, 4> m_putByVals; 363 369 Vector<InlineCacheWrapper<JITDelByIdGenerator>, 4> m_delByIds; 364 370 Vector<InlineCacheWrapper<JITDelByValGenerator>, 4> m_delByVals; -
trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp
r280760 r281615 107 107 case FilterCallLinkStatus: 108 108 case FilterGetByStatus: 109 case FilterPutBy IdStatus:109 case FilterPutByStatus: 110 110 case FilterInByStatus: 111 111 case FilterDeleteByStatus: -
trunk/Source/JavaScriptCore/dfg/DFGNode.h
r280760 r281615 56 56 #include "Operands.h" 57 57 #include "PrivateFieldPutKind.h" 58 #include "PutBy IdVariant.h"58 #include "PutByVariant.h" 59 59 #include "SetPrivateBrandVariant.h" 60 60 #include "SpeculatedType.h" … … 93 93 struct MultiPutByOffsetData { 94 94 unsigned identifierNumber; 95 Vector<PutBy IdVariant, 2> variants;95 Vector<PutByVariant, 2> variants; 96 96 97 97 bool writesStructures() const; … … 3211 3211 } 3212 3212 3213 bool hasPutBy IdStatus()3214 { 3215 return op() == FilterPutBy IdStatus;3216 } 3217 3218 PutBy IdStatus* putByIdStatus()3219 { 3220 ASSERT(hasPutBy IdStatus());3221 return m_opInfo.as<PutBy IdStatus*>();3213 bool hasPutByStatus() 3214 { 3215 return op() == FilterPutByStatus; 3216 } 3217 3218 PutByStatus* putByStatus() 3219 { 3220 ASSERT(hasPutByStatus()); 3221 return m_opInfo.as<PutByStatus*>(); 3222 3222 } 3223 3223 -
trunk/Source/JavaScriptCore/dfg/DFGNodeType.h
r280760 r281615 547 547 macro(FilterGetByStatus, NodeMustGenerate) \ 548 548 macro(FilterInByStatus, NodeMustGenerate) \ 549 macro(FilterPutBy IdStatus, NodeMustGenerate) \549 macro(FilterPutByStatus, NodeMustGenerate) \ 550 550 macro(FilterDeleteByStatus, NodeMustGenerate) \ 551 551 macro(FilterCheckPrivateBrandStatus, NodeMustGenerate) \ -
trunk/Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp
r279256 r281615 216 216 case InlineCallFrame::GetterCall: 217 217 case InlineCallFrame::SetterCall: { 218 if (callInstruction.opcodeID() == op_put_by_val) {219 // We compile op_put_by_val as PutById and inlines SetterCall only when we found StructureStubInfo for this op_put_by_val.220 // But still it is possible that we cannot find StructureStubInfo here. Let's consider the following scenario.221 // 1. Baseline CodeBlock (A) is compiled.222 // 2. (A) gets DFG (B).223 // 3. Since (A) collects enough information for put_by_val, (B) can get StructureStubInfo from (A) and copmile it as inlined Setter call.224 // 4. (A)'s JITData is destroyed since it is not executed. Then, (A) becomes LLInt.225 // 5. The CodeBlock inlining (A) gets OSR exit. So (A) is executed and (A) eventually gets Baseline CodeBlock again.226 // 6. (B) gets OSR exit. (B) attempts to search for StructureStubInfo in (A) for PutById (originally, put_by_val). But it does not exist since (A)'s JITData is cleared once.227 ByValInfo* byValInfo = baselineCodeBlockForCaller->findByValInfo(CodeOrigin(callBytecodeIndex));228 RELEASE_ASSERT(byValInfo);229 jumpTarget = byValInfo->doneTarget.retagged<JSEntryPtrTag>();230 break;231 }232 233 218 StructureStubInfo* stubInfo = baselineCodeBlockForCaller->findStubInfo(CodeOrigin(callBytecodeIndex)); 234 219 RELEASE_ASSERT(stubInfo); -
trunk/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp
r278445 r281615 1259 1259 case FilterCallLinkStatus: 1260 1260 case FilterGetByStatus: 1261 case FilterPutBy IdStatus:1261 case FilterPutByStatus: 1262 1262 case FilterInByStatus: 1263 1263 case FilterDeleteByStatus: … … 2555 2555 // at this point, we can simply trust that the incoming value has the right type 2556 2556 // for whatever structure we are using. 2557 data->variants.append( 2558 PutByIdVariant::replace(currentSet, currentOffset)); 2557 data->variants.append(PutByVariant::replace(nullptr, currentSet, currentOffset)); 2559 2558 currentOffset = offset; 2560 2559 currentSet.clear(); … … 2562 2561 currentSet.add(structure.get()); 2563 2562 } 2564 data->variants.append( 2565 PutByIdVariant::replace(currentSet, currentOffset)); 2563 data->variants.append(PutByVariant::replace(nullptr, currentSet, currentOffset)); 2566 2564 } 2567 2565 … … 2616 2614 case FilterCallLinkStatus: 2617 2615 case FilterGetByStatus: 2618 case FilterPutBy IdStatus:2616 case FilterPutByStatus: 2619 2617 case FilterInByStatus: 2620 2618 case FilterDeleteByStatus: -
trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
r280760 r281615 1450 1450 case FilterCallLinkStatus: 1451 1451 case FilterGetByStatus: 1452 case FilterPutBy IdStatus:1452 case FilterPutByStatus: 1453 1453 case FilterInByStatus: 1454 1454 case FilterDeleteByStatus: -
trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
r280760 r281615 360 360 case FilterCallLinkStatus: 361 361 case FilterGetByStatus: 362 case FilterPutBy IdStatus:362 case FilterPutByStatus: 363 363 case FilterInByStatus: 364 364 case FilterDeleteByStatus: -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
r281324 r281615 2691 2691 case Array::Generic: { 2692 2692 ASSERT(node->op() == PutByVal || node->op() == PutByValDirect); 2693 2694 if (child1.useKind() == CellUse) { 2695 if (child2.useKind() == StringUse) { 2696 compilePutByValForCellWithString(node, child1, child2, child3); 2697 alreadyHandled = true; 2698 break; 2693 if (m_graph.m_slowPutByVal.contains(node)) { 2694 if (child1.useKind() == CellUse) { 2695 if (child2.useKind() == StringUse) { 2696 compilePutByValForCellWithString(node, child1, child2, child3); 2697 alreadyHandled = true; 2698 break; 2699 } 2700 2701 if (child2.useKind() == SymbolUse) { 2702 compilePutByValForCellWithSymbol(node, child1, child2, child3); 2703 alreadyHandled = true; 2704 break; 2705 } 2699 2706 } 2700 2707 2701 if (child2.useKind() == SymbolUse) { 2702 compilePutByValForCellWithSymbol(node, child1, child2, child3); 2703 alreadyHandled = true; 2704 break; 2705 } 2708 SpeculateCellOperand base(this, child1); // Save a register, speculate cell. We'll probably be right. 2709 JSValueOperand property(this, child2); 2710 JSValueOperand value(this, child3); 2711 GPRReg baseGPR = base.gpr(); 2712 JSValueRegs propertyRegs = property.jsValueRegs(); 2713 JSValueRegs valueRegs = value.jsValueRegs(); 2714 2715 flushRegisters(); 2716 if (node->op() == PutByValDirect) 2717 callOperation(node->ecmaMode().isStrict() ? operationPutByValDirectCellStrict : operationPutByValDirectCellNonStrict, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, propertyRegs, valueRegs); 2718 else 2719 callOperation(node->ecmaMode().isStrict() ? operationPutByValCellStrict : operationPutByValCellNonStrict, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, propertyRegs, valueRegs); 2720 m_jit.exceptionCheck(); 2721 2722 noResult(node); 2723 alreadyHandled = true; 2724 break; 2706 2725 } 2707 2708 SpeculateCellOperand base(this, child1); // Save a register, speculate cell. We'll probably be right.2709 JSValueOperand property(this, child2 );2710 JSValueOperand value(this, child3 );2711 GPRReg baseGPR = base.gpr();2726 2727 JSValueOperand base(this, child1, ManualOperandSpeculation); 2728 JSValueOperand property(this, child2, ManualOperandSpeculation); 2729 JSValueOperand value(this, child3, ManualOperandSpeculation); 2730 JSValueRegs baseRegs = base.jsValueRegs(); 2712 2731 JSValueRegs propertyRegs = property.jsValueRegs(); 2713 2732 JSValueRegs valueRegs = value.jsValueRegs(); 2714 2715 flushRegisters(); 2716 if (node->op() == PutByValDirect) 2717 callOperation(node->ecmaMode().isStrict() ? operationPutByValDirectCellStrict : operationPutByValDirectCellNonStrict, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, propertyRegs, valueRegs); 2718 else 2719 callOperation(node->ecmaMode().isStrict() ? operationPutByValCellStrict : operationPutByValCellNonStrict, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), baseGPR, propertyRegs, valueRegs); 2720 m_jit.exceptionCheck(); 2721 2733 2734 speculate(node, child1); 2735 speculate(node, child2); 2736 speculate(node, child3); 2737 2738 CodeOrigin codeOrigin = node->origin.semantic; 2739 CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream->size()); 2740 RegisterSet usedRegisters = this->usedRegisters(); 2741 bool isDirect = node->op() == PutByValDirect; 2742 ECMAMode ecmaMode = node->ecmaMode(); 2743 2744 JITPutByValGenerator gen( 2745 m_jit.codeBlock(), JITType::DFGJIT, codeOrigin, callSite, AccessType::PutByVal, usedRegisters, 2746 baseRegs, propertyRegs, valueRegs, InvalidGPRReg, InvalidGPRReg); 2747 2748 if (m_state.forNode(child2).isType(SpecString)) 2749 gen.stubInfo()->propertyIsString = true; 2750 else if (m_state.forNode(child2).isType(SpecInt32Only)) 2751 gen.stubInfo()->propertyIsInt32 = true; 2752 else if (m_state.forNode(child2).isType(SpecSymbol)) 2753 gen.stubInfo()->propertyIsSymbol = true; 2754 2755 gen.generateFastPath(m_jit); 2756 2757 JITCompiler::JumpList slowCases; 2758 slowCases.append(gen.slowPathJump()); 2759 2760 std::unique_ptr<SlowPathGenerator> slowPath; 2761 auto operation = isDirect ? (ecmaMode.isStrict() ? operationDirectPutByValStrictOptimize : operationDirectPutByValNonStrictOptimize) : (ecmaMode.isStrict() ? operationPutByValStrictOptimize : operationPutByValNonStrictOptimize); 2762 slowPath = slowPathCall( 2763 slowCases, this, operation, 2764 NoResult, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(codeOrigin)), baseRegs, propertyRegs, valueRegs, gen.stubInfo(), nullptr); 2765 2766 m_jit.addPutByVal(gen, slowPath.get()); 2767 addSlowPathGenerator(WTFMove(slowPath)); 2768 2722 2769 noResult(node); 2723 2770 alreadyHandled = true; … … 4323 4370 case FilterCallLinkStatus: 4324 4371 case FilterGetByStatus: 4325 case FilterPutBy IdStatus:4372 case FilterPutByStatus: 4326 4373 case FilterInByStatus: 4327 4374 case FilterDeleteByStatus: -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r280760 r281615 3178 3178 case Array::Generic: { 3179 3179 DFG_ASSERT(m_jit.graph(), node, node->op() == PutByVal || node->op() == PutByValDirect, node->op()); 3180 3181 if (child1.useKind() == CellUse) { 3182 if (child2.useKind() == StringUse) { 3183 compilePutByValForCellWithString(node, child1, child2, child3); 3184 alreadyHandled = true; 3185 break; 3180 if (m_graph.m_slowPutByVal.contains(node) || (child1.useKind() != CellUse && child1.useKind() != KnownCellUse)) { 3181 if (child1.useKind() == CellUse) { 3182 if (child2.useKind() == StringUse) { 3183 compilePutByValForCellWithString(node, child1, child2, child3); 3184 alreadyHandled = true; 3185 break; 3186 } 3187 3188 if (child2.useKind() == SymbolUse) { 3189 compilePutByValForCellWithSymbol(node, child1, child2, child3); 3190 alreadyHandled = true; 3191 break; 3192 } 3186 3193 } 3187 3194 3188 if (child2.useKind() == SymbolUse) { 3189 compilePutByValForCellWithSymbol(node, child1, child2, child3); 3190 alreadyHandled = true; 3191 break; 3192 } 3195 JSValueOperand arg1(this, child1); 3196 JSValueOperand arg2(this, child2); 3197 JSValueOperand arg3(this, child3); 3198 GPRReg arg1GPR = arg1.gpr(); 3199 GPRReg arg2GPR = arg2.gpr(); 3200 GPRReg arg3GPR = arg3.gpr(); 3201 flushRegisters(); 3202 if (node->op() == PutByValDirect) 3203 callOperation(node->ecmaMode().isStrict() ? operationPutByValDirectStrict : operationPutByValDirectNonStrict, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), arg1GPR, arg2GPR, arg3GPR); 3204 else 3205 callOperation(node->ecmaMode().isStrict() ? operationPutByValStrict : operationPutByValNonStrict, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), arg1GPR, arg2GPR, arg3GPR); 3206 m_jit.exceptionCheck(); 3207 3208 noResult(node); 3209 alreadyHandled = true; 3210 break; 3193 3211 } 3194 3195 JSValueOperand arg1(this, child1); 3196 JSValueOperand arg2(this, child2); 3197 JSValueOperand arg3(this, child3); 3198 GPRReg arg1GPR = arg1.gpr(); 3199 GPRReg arg2GPR = arg2.gpr(); 3200 GPRReg arg3GPR = arg3.gpr(); 3201 flushRegisters(); 3202 if (node->op() == PutByValDirect) 3203 callOperation(node->ecmaMode().isStrict() ? operationPutByValDirectStrict : operationPutByValDirectNonStrict, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), arg1GPR, arg2GPR, arg3GPR); 3204 else 3205 callOperation(node->ecmaMode().isStrict() ? operationPutByValStrict : operationPutByValNonStrict, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(node->origin.semantic)), arg1GPR, arg2GPR, arg3GPR); 3206 m_jit.exceptionCheck(); 3207 3212 3213 SpeculateCellOperand base(this, child1); 3214 JSValueOperand property(this, child2, ManualOperandSpeculation); 3215 JSValueOperand value(this, child3, ManualOperandSpeculation); 3216 GPRReg baseGPR = base.gpr(); 3217 GPRReg propertyGPR = property.gpr(); 3218 GPRReg valueGPR = value.gpr(); 3219 3220 GPRTemporary stubInfo; 3221 GPRReg stubInfoGPR = InvalidGPRReg; 3222 if (JITCode::useDataIC(JITType::DFGJIT)) { 3223 stubInfo = GPRTemporary(this); 3224 stubInfoGPR = stubInfo.gpr(); 3225 } 3226 3227 speculate(node, child2); 3228 speculate(node, child3); 3229 3230 CodeOrigin codeOrigin = node->origin.semantic; 3231 CallSiteIndex callSite = m_jit.recordCallSiteAndGenerateExceptionHandlingOSRExitIfNeeded(codeOrigin, m_stream->size()); 3232 RegisterSet usedRegisters = this->usedRegisters(); 3233 bool isDirect = node->op() == PutByValDirect; 3234 ECMAMode ecmaMode = node->ecmaMode(); 3235 3236 JITPutByValGenerator gen( 3237 m_jit.codeBlock(), JITType::DFGJIT, codeOrigin, callSite, AccessType::PutByVal, usedRegisters, 3238 JSValueRegs(baseGPR), JSValueRegs(propertyGPR), JSValueRegs(valueGPR), InvalidGPRReg, stubInfoGPR); 3239 3240 if (m_state.forNode(child2).isType(SpecString)) 3241 gen.stubInfo()->propertyIsString = true; 3242 else if (m_state.forNode(child2).isType(SpecInt32Only)) 3243 gen.stubInfo()->propertyIsInt32 = true; 3244 else if (m_state.forNode(child2).isType(SpecSymbol)) 3245 gen.stubInfo()->propertyIsSymbol = true; 3246 3247 gen.generateFastPath(m_jit); 3248 3249 JITCompiler::JumpList slowCases; 3250 if (!JITCode::useDataIC(JITType::DFGJIT)) 3251 slowCases.append(gen.slowPathJump()); 3252 3253 std::unique_ptr<SlowPathGenerator> slowPath; 3254 auto operation = isDirect ? (ecmaMode.isStrict() ? operationDirectPutByValStrictOptimize : operationDirectPutByValNonStrictOptimize) : (ecmaMode.isStrict() ? operationPutByValStrictOptimize : operationPutByValNonStrictOptimize); 3255 if (JITCode::useDataIC(JITType::DFGJIT)) { 3256 slowPath = slowPathICCall( 3257 slowCases, this, gen.stubInfo(), stubInfoGPR, CCallHelpers::Address(stubInfoGPR, StructureStubInfo::offsetOfSlowOperation()), operation, 3258 NoResult, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(codeOrigin)), baseGPR, propertyGPR, valueGPR, stubInfoGPR, nullptr); 3259 } else { 3260 slowPath = slowPathCall( 3261 slowCases, this, operation, 3262 NoResult, TrustedImmPtr::weakPointer(m_graph, m_graph.globalObjectFor(codeOrigin)), baseGPR, propertyGPR, valueGPR, gen.stubInfo(), nullptr); 3263 } 3264 3265 m_jit.addPutByVal(gen, slowPath.get()); 3266 addSlowPathGenerator(WTFMove(slowPath)); 3267 3208 3268 noResult(node); 3209 3269 alreadyHandled = true; … … 5872 5932 case FilterCallLinkStatus: 5873 5933 case FilterGetByStatus: 5874 case FilterPutBy IdStatus:5934 case FilterPutByStatus: 5875 5935 case FilterInByStatus: 5876 5936 case FilterDeleteByStatus: -
trunk/Source/JavaScriptCore/dfg/DFGStoreBarrierInsertionPhase.cpp
r272580 r281615 234 234 case PutByValAlias: { 235 235 switch (m_node->arrayMode().modeForPut().type()) { 236 case Array::Generic: 237 case Array::BigInt64Array: 238 case Array::BigUint64Array: { 239 Edge child1 = m_graph.varArgChild(m_node, 0); 240 Edge child3 = m_graph.varArgChild(m_node, 2); 241 if (!m_graph.m_slowPutByVal.contains(m_node) && (child1.useKind() == CellUse || child1.useKind() == KnownCellUse)) 242 considerBarrier(child1, child3); 243 break; 244 } 236 245 case Array::Contiguous: 237 246 case Array::ArrayStorage: -
trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp
r278696 r281615 313 313 case MultiPutByOffset: 314 314 for (unsigned i = node->multiPutByOffsetData().variants.size(); i--;) { 315 const PutBy IdVariant& variant = node->multiPutByOffsetData().variants[i];316 if (variant.kind() != PutBy IdVariant::Transition)315 const PutByVariant& variant = node->multiPutByOffsetData().variants[i]; 316 if (variant.kind() != PutByVariant::Transition) 317 317 continue; 318 318 VALIDATE((node), !variant.oldStructureForTransition()->dfgShouldWatch()); -
trunk/Source/JavaScriptCore/dfg/DFGVarargsForwardingPhase.cpp
r278445 r281615 197 197 198 198 case FilterGetByStatus: 199 case FilterPutBy IdStatus:199 case FilterPutByStatus: 200 200 case FilterCallLinkStatus: 201 201 case FilterInByStatus: … … 422 422 423 423 case FilterGetByStatus: 424 case FilterPutBy IdStatus:424 case FilterPutByStatus: 425 425 case FilterCallLinkStatus: 426 426 case FilterInByStatus: -
trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
r280760 r281615 408 408 case FilterCallLinkStatus: 409 409 case FilterGetByStatus: 410 case FilterPutBy IdStatus:410 case FilterPutByStatus: 411 411 case FilterInByStatus: 412 412 case FilterDeleteByStatus: -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r281565 r281615 1650 1650 case FilterCallLinkStatus: 1651 1651 case FilterGetByStatus: 1652 case FilterPutBy IdStatus:1652 case FilterPutByStatus: 1653 1653 case FilterInByStatus: 1654 1654 case FilterDeleteByStatus: … … 5557 5557 case Array::BigUint64Array: 5558 5558 case Array::Generic: { 5559 if (child1.useKind() == CellUse) { 5560 V_JITOperation_GCCJ operation = nullptr; 5561 if (child2.useKind() == StringUse) { 5562 if (m_node->op() == PutByValDirect) { 5563 if (m_node->ecmaMode().isStrict()) 5564 operation = operationPutByValDirectCellStringStrict; 5565 else 5566 operation = operationPutByValDirectCellStringNonStrict; 5559 if (m_graph.m_slowPutByVal.contains(m_node) || (child1.useKind() != CellUse && child1.useKind() != KnownCellUse)) { 5560 if (child1.useKind() == CellUse) { 5561 V_JITOperation_GCCJ operation = nullptr; 5562 if (child2.useKind() == StringUse) { 5563 if (m_node->op() == PutByValDirect) { 5564 if (m_node->ecmaMode().isStrict()) 5565 operation = operationPutByValDirectCellStringStrict; 5566 else 5567 operation = operationPutByValDirectCellStringNonStrict; 5568 } else { 5569 if (m_node->ecmaMode().isStrict()) 5570 operation = operationPutByValCellStringStrict; 5571 else 5572 operation = operationPutByValCellStringNonStrict; 5573 } 5574 vmCall(Void, operation, weakPointer(globalObject), lowCell(child1), lowString(child2), lowJSValue(child3)); 5575 return; 5576 } 5577 5578 if (child2.useKind() == SymbolUse) { 5579 if (m_node->op() == PutByValDirect) { 5580 if (m_node->ecmaMode().isStrict()) 5581 operation = operationPutByValDirectCellSymbolStrict; 5582 else 5583 operation = operationPutByValDirectCellSymbolNonStrict; 5584 } else { 5585 if (m_node->ecmaMode().isStrict()) 5586 operation = operationPutByValCellSymbolStrict; 5587 else 5588 operation = operationPutByValCellSymbolNonStrict; 5589 } 5590 vmCall(Void, operation, weakPointer(globalObject), lowCell(child1), lowSymbol(child2), lowJSValue(child3)); 5591 return; 5592 } 5593 } 5594 5595 V_JITOperation_GJJJ operation; 5596 if (m_node->op() == PutByValDirect) { 5597 if (m_node->ecmaMode().isStrict()) 5598 operation = operationPutByValDirectStrict; 5599 else 5600 operation = operationPutByValDirectNonStrict; 5601 } else { 5602 if (m_node->ecmaMode().isStrict()) 5603 operation = operationPutByValStrict; 5604 else 5605 operation = operationPutByValNonStrict; 5606 } 5607 5608 vmCall( 5609 Void, operation, weakPointer(globalObject), 5610 lowJSValue(child1), lowJSValue(child2), lowJSValue(child3)); 5611 return; 5612 } 5613 5614 Node* node = m_node; 5615 5616 LValue base = lowCell(child1); 5617 LValue property = lowJSValue(child2, ManualOperandSpeculation); 5618 LValue value = lowJSValue(child3, ManualOperandSpeculation); 5619 5620 speculate(child2); 5621 speculate(child3); 5622 bool propertyIsString = false; 5623 bool propertyIsInt32 = false; 5624 bool propertyIsSymbol = false; 5625 if (abstractValue(child2).isType(SpecString)) 5626 propertyIsString = true; 5627 else if (abstractValue(child2).isType(SpecInt32Only)) 5628 propertyIsInt32 = true; 5629 else if (abstractValue(child2).isType(SpecSymbol)) 5630 propertyIsSymbol = true; 5631 5632 PatchpointValue* patchpoint = m_out.patchpoint(Void); 5633 patchpoint->appendSomeRegister(base); 5634 patchpoint->appendSomeRegister(property); 5635 patchpoint->appendSomeRegister(value); 5636 patchpoint->append(m_notCellMask, ValueRep::lateReg(GPRInfo::notCellMaskRegister)); 5637 patchpoint->append(m_numberTag, ValueRep::lateReg(GPRInfo::numberTagRegister)); 5638 patchpoint->clobber(RegisterSet::macroScratchRegisters()); 5639 patchpoint->numGPScratchRegisters = JITCode::useDataIC(JITType::FTLJIT) ? 1 : 0; 5640 5641 RefPtr<PatchpointExceptionHandle> exceptionHandle = preparePatchpointForExceptions(patchpoint); 5642 5643 State* state = &m_ftlState; 5644 CodeOrigin nodeSemanticOrigin = node->origin.semantic; 5645 ECMAMode ecmaMode = m_node->ecmaMode(); 5646 bool isDirect = m_node->op() == PutByValDirect; 5647 patchpoint->setGenerator([=] (CCallHelpers& jit, const StackmapGenerationParams& params) { 5648 AllowMacroScratchRegisterUsage allowScratch(jit); 5649 5650 CallSiteIndex callSiteIndex = state->jitCode->common.codeOrigins->addUniqueCallSiteIndex(nodeSemanticOrigin); 5651 5652 // This is the direct exit target for operation calls. 5653 Box<CCallHelpers::JumpList> exceptions = exceptionHandle->scheduleExitCreation(params)->jumps(jit); 5654 5655 // This is the exit for call IC's created by the IC for getters. We don't have 5656 // to do anything weird other than call this, since it will associate the exit with 5657 // the callsite index. 5658 exceptionHandle->scheduleExitCreationForUnwind(params, callSiteIndex); 5659 5660 GPRReg baseGPR = params[0].gpr(); 5661 GPRReg propertyGPR = params[1].gpr(); 5662 GPRReg valueGPR = params[2].gpr(); 5663 GPRReg stubInfoGPR = JITCode::useDataIC(JITType::FTLJIT) ? params.gpScratch(0) : InvalidGPRReg; 5664 5665 auto generator = Box<JITPutByValGenerator>::create( 5666 jit.codeBlock(), JITType::FTLJIT, nodeSemanticOrigin, callSiteIndex, AccessType::PutByVal, 5667 params.unavailableRegisters(), JSValueRegs(baseGPR), JSValueRegs(propertyGPR), JSValueRegs(valueGPR), InvalidGPRReg, stubInfoGPR); 5668 5669 generator->stubInfo()->propertyIsString = propertyIsString; 5670 generator->stubInfo()->propertyIsInt32 = propertyIsInt32; 5671 generator->stubInfo()->propertyIsSymbol = propertyIsSymbol; 5672 5673 generator->generateFastPath(jit); 5674 CCallHelpers::Label done = jit.label(); 5675 5676 params.addLatePath([=] (CCallHelpers& jit) { 5677 AllowMacroScratchRegisterUsage allowScratch(jit); 5678 5679 if (!JITCode::useDataIC(JITType::FTLJIT)) 5680 generator->slowPathJump().link(&jit); 5681 CCallHelpers::Label slowPathBegin = jit.label(); 5682 CCallHelpers::Call slowPathCall; 5683 auto operation = isDirect ? (ecmaMode.isStrict() ? operationDirectPutByValStrictOptimize : operationDirectPutByValNonStrictOptimize) : (ecmaMode.isStrict() ? operationPutByValStrictOptimize : operationPutByValNonStrictOptimize); 5684 if (JITCode::useDataIC(JITType::FTLJIT)) { 5685 jit.move(CCallHelpers::TrustedImmPtr(generator->stubInfo()), stubInfoGPR); 5686 generator->stubInfo()->m_slowOperation = operation; 5687 slowPathCall = callOperation( 5688 *state, params.unavailableRegisters(), jit, nodeSemanticOrigin, 5689 exceptions.get(), CCallHelpers::Address(stubInfoGPR, StructureStubInfo::offsetOfSlowOperation()), InvalidGPRReg, 5690 jit.codeBlock()->globalObjectFor(nodeSemanticOrigin), 5691 baseGPR, propertyGPR, valueGPR, stubInfoGPR, CCallHelpers::TrustedImmPtr(nullptr)).call(); 5567 5692 } else { 5568 if (m_node->ecmaMode().isStrict()) 5569 operation = operationPutByValCellStringStrict; 5570 else 5571 operation = operationPutByValCellStringNonStrict; 5693 slowPathCall = callOperation( 5694 *state, params.unavailableRegisters(), jit, nodeSemanticOrigin, 5695 exceptions.get(), operation, InvalidGPRReg, 5696 jit.codeBlock()->globalObjectFor(nodeSemanticOrigin), 5697 baseGPR, propertyGPR, valueGPR, CCallHelpers::TrustedImmPtr(generator->stubInfo()), CCallHelpers::TrustedImmPtr(nullptr)).call(); 5572 5698 } 5573 vmCall(Void, operation, weakPointer(globalObject), lowCell(child1), lowString(child2), lowJSValue(child3)); 5574 return; 5575 } 5576 5577 if (child2.useKind() == SymbolUse) { 5578 if (m_node->op() == PutByValDirect) { 5579 if (m_node->ecmaMode().isStrict()) 5580 operation = operationPutByValDirectCellSymbolStrict; 5581 else 5582 operation = operationPutByValDirectCellSymbolNonStrict; 5583 } else { 5584 if (m_node->ecmaMode().isStrict()) 5585 operation = operationPutByValCellSymbolStrict; 5586 else 5587 operation = operationPutByValCellSymbolNonStrict; 5588 } 5589 vmCall(Void, operation, weakPointer(globalObject), lowCell(child1), lowSymbol(child2), lowJSValue(child3)); 5590 return; 5591 } 5592 } 5593 5594 V_JITOperation_GJJJ operation; 5595 if (m_node->op() == PutByValDirect) { 5596 if (m_node->ecmaMode().isStrict()) 5597 operation = operationPutByValDirectStrict; 5598 else 5599 operation = operationPutByValDirectNonStrict; 5600 } else { 5601 if (m_node->ecmaMode().isStrict()) 5602 operation = operationPutByValStrict; 5603 else 5604 operation = operationPutByValNonStrict; 5605 } 5606 5607 vmCall( 5608 Void, operation, weakPointer(globalObject), 5609 lowJSValue(child1), lowJSValue(child2), lowJSValue(child3)); 5699 jit.jump().linkTo(done, &jit); 5700 5701 generator->reportSlowPathCall(slowPathBegin, slowPathCall); 5702 5703 jit.addLinkTask([=] (LinkBuffer& linkBuffer) { 5704 generator->finalize(linkBuffer, linkBuffer); 5705 }); 5706 }); 5707 }); 5610 5708 return; 5611 5709 } … … 8952 9050 RegisteredStructureSet baseSet; 8953 9051 for (unsigned i = data.variants.size(); i--;) { 8954 PutBy IdVariant variant = data.variants[i];9052 PutByVariant variant = data.variants[i]; 8955 9053 for (unsigned j = variant.oldStructure().size(); j--;) { 8956 9054 RegisteredStructure structure = m_graph.registerStructure(variant.oldStructure()[j]); … … 8967 9065 m_out.appendTo(blocks[i], i + 1 < data.variants.size() ? blocks[i + 1] : exit); 8968 9066 8969 PutBy IdVariant variant = data.variants[i];9067 PutByVariant variant = data.variants[i]; 8970 9068 8971 9069 LValue storage; 8972 if (variant.kind() == PutBy IdVariant::Replace) {9070 if (variant.kind() == PutByVariant::Replace) { 8973 9071 if (isInlineOffset(variant.offset())) 8974 9072 storage = base; … … 8976 9074 storage = m_out.loadPtr(base, m_heaps.JSObject_butterfly); 8977 9075 } else { 8978 DFG_ASSERT(m_graph, m_node, variant.kind() == PutBy IdVariant::Transition, variant.kind());9076 DFG_ASSERT(m_graph, m_node, variant.kind() == PutByVariant::Transition, variant.kind()); 8979 9077 m_graph.m_plan.transitions().addLazily( 8980 9078 m_origin.semantic.codeOriginOwner(), … … 8988 9086 storeProperty(value, storage, data.identifierNumber, variant.offset()); 8989 9087 8990 if (variant.kind() == PutBy IdVariant::Transition) {9088 if (variant.kind() == PutByVariant::Transition) { 8991 9089 ASSERT(variant.oldStructureForTransition()->indexingType() == variant.newStructure()->indexingType()); 8992 9090 ASSERT(variant.oldStructureForTransition()->typeInfo().inlineTypeFlags() == variant.newStructure()->typeInfo().inlineTypeFlags()); -
trunk/Source/JavaScriptCore/generator/DSL.rb
r280760 r281615 142 142 #include "Opcode.h" 143 143 #include "PrivateFieldPutKind.h" 144 #include "PutBy IdStatus.h"144 #include "PutByStatus.h" 145 145 #include "PutByIdFlags.h" 146 146 #include "ToThisStatus.h" -
trunk/Source/JavaScriptCore/jit/ICStats.h
r278445 r281615 68 68 macro(OperationPutByIdDefinePrivateFieldFieldStrictOptimize) \ 69 69 macro(OperationPutByIdPutPrivateFieldFieldStrictOptimize) \ 70 macro(PutBy IdAddAccessCase) \71 macro(PutBy IdReplaceWithJump) \72 macro(PutBy IdSelfPatch) \73 macro(InBy IdSelfPatch) \70 macro(PutByAddAccessCase) \ 71 macro(PutByReplaceWithJump) \ 72 macro(PutBySelfPatch) \ 73 macro(InBySelfPatch) \ 74 74 macro(DelByReplaceWithJump) \ 75 75 macro(DelByReplaceWithGeneric) \ -
trunk/Source/JavaScriptCore/jit/JIT.cpp
r280760 r281615 511 511 m_getByIdWithThisIndex = 0; 512 512 m_putByIdIndex = 0; 513 m_putByValIndex = 0; 513 514 m_inByIdIndex = 0; 514 515 m_inByValIndex = 0; … … 663 664 RELEASE_ASSERT(m_getByIdWithThisIndex == m_getByIdsWithThis.size()); 664 665 RELEASE_ASSERT(m_putByIdIndex == m_putByIds.size()); 666 RELEASE_ASSERT(m_putByValIndex == m_putByVals.size()); 665 667 RELEASE_ASSERT(m_inByIdIndex == m_inByIds.size()); 666 668 RELEASE_ASSERT(m_instanceOfIndex == m_instanceOfs.size()); … … 910 912 finalizeInlineCaches(m_getByIdsWithThis, patchBuffer); 911 913 finalizeInlineCaches(m_putByIds, patchBuffer); 914 finalizeInlineCaches(m_putByVals, patchBuffer); 912 915 finalizeInlineCaches(m_delByIds, patchBuffer); 913 916 finalizeInlineCaches(m_delByVals, patchBuffer); -
trunk/Source/JavaScriptCore/jit/JIT.h
r281454 r281615 226 226 } 227 227 228 static void compilePutByVal(const ConcurrentJSLocker& locker, VM& vm, CodeBlock* codeBlock, ByValInfo* byValInfo, ReturnAddressPtr returnAddress, JITArrayMode arrayMode)229 {230 JIT jit(vm, codeBlock);231 jit.m_bytecodeIndex = byValInfo->bytecodeIndex;232 jit.privateCompilePutByVal<OpPutByVal>(locker, byValInfo, returnAddress, arrayMode);233 }234 235 static void compileDirectPutByVal(const ConcurrentJSLocker& locker, VM& vm, CodeBlock* codeBlock, ByValInfo* byValInfo, ReturnAddressPtr returnAddress, JITArrayMode arrayMode)236 {237 JIT jit(vm, codeBlock);238 jit.m_bytecodeIndex = byValInfo->bytecodeIndex;239 jit.privateCompilePutByVal<OpPutByValDirect>(locker, byValInfo, returnAddress, arrayMode);240 }241 242 template<typename Op>243 static void compilePutByValWithCachedId(VM& vm, CodeBlock* codeBlock, ByValInfo* byValInfo, ReturnAddressPtr returnAddress, PutKind putKind, CacheableIdentifier propertyName)244 {245 JIT jit(vm, codeBlock);246 jit.m_bytecodeIndex = byValInfo->bytecodeIndex;247 jit.privateCompilePutByValWithCachedId<Op>(byValInfo, returnAddress, putKind, propertyName);248 }249 250 228 static void compilePutPrivateNameWithCachedId(VM& vm, CodeBlock* codeBlock, ByValInfo* byValInfo, ReturnAddressPtr returnAddress, CacheableIdentifier propertyName) 251 229 { … … 268 246 CompilationResult privateCompile(JITCompilationEffort); 269 247 270 void privateCompileGetByVal(const ConcurrentJSLocker&, ByValInfo*, ReturnAddressPtr, JITArrayMode);271 template<typename Op>272 void privateCompilePutByVal(const ConcurrentJSLocker&, ByValInfo*, ReturnAddressPtr, JITArrayMode);273 template<typename Op>274 void privateCompilePutByValWithCachedId(ByValInfo*, ReturnAddressPtr, PutKind, CacheableIdentifier);275 276 248 void privateCompilePutPrivateNameWithCachedId(ByValInfo*, ReturnAddressPtr, CacheableIdentifier); 277 278 void privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress);279 249 280 250 // Add a call out from JIT code, without an exception check. … … 383 353 384 354 void emitArrayProfilingSiteWithCell(RegisterID cellGPR, ArrayProfile*, RegisterID scratchGPR); 355 void emitArrayProfilingSiteWithCell(RegisterID cellGPR, RegisterID arrayProfileGPR, RegisterID scratchGPR); 385 356 void emitArrayProfileStoreToHoleSpecialCase(ArrayProfile*); 386 357 void emitArrayProfileOutOfBoundsSpecialCase(ArrayProfile*); 387 388 JITArrayMode chooseArrayMode(ArrayProfile*);389 390 // Property is in regT1, base is in regT0. regT2 contains indecing type.391 // The value to store is not yet loaded. Property is int-checked and392 // zero-extended. Base is cell checked. Structure is already profiled.393 // returns the slow cases.394 template<typename Op>395 JumpList emitInt32PutByVal(Op bytecode, PatchableJump& badType, ByValInfo* byValInfo)396 {397 return emitGenericContiguousPutByVal(bytecode, badType, byValInfo, Int32Shape);398 }399 template<typename Op>400 JumpList emitDoublePutByVal(Op bytecode, PatchableJump& badType, ByValInfo* byValInfo)401 {402 return emitGenericContiguousPutByVal(bytecode, badType, byValInfo, DoubleShape);403 }404 template<typename Op>405 JumpList emitContiguousPutByVal(Op bytecode, PatchableJump& badType, ByValInfo* byValInfo)406 {407 return emitGenericContiguousPutByVal(bytecode, badType, byValInfo);408 }409 template<typename Op>410 JumpList emitGenericContiguousPutByVal(Op, PatchableJump& badType, ByValInfo*, IndexingType indexingShape = ContiguousShape);411 template<typename Op>412 JumpList emitArrayStoragePutByVal(Op, PatchableJump& badType, ByValInfo*);413 template<typename Op>414 JumpList emitIntTypedArrayPutByVal(Op, PatchableJump& badType, ByValInfo*, TypedArrayType);415 template<typename Op>416 JumpList emitFloatTypedArrayPutByVal(Op, PatchableJump& badType, ByValInfo*, TypedArrayType);417 358 418 359 template<typename Op> … … 1065 1006 Vector<JITGetByIdWithThisGenerator> m_getByIdsWithThis; 1066 1007 Vector<JITPutByIdGenerator> m_putByIds; 1008 Vector<JITPutByValGenerator> m_putByVals; 1067 1009 Vector<JITInByIdGenerator> m_inByIds; 1068 1010 Vector<JITInByValGenerator> m_inByVals; … … 1092 1034 unsigned m_getByIdWithThisIndex { UINT_MAX }; 1093 1035 unsigned m_putByIdIndex { UINT_MAX }; 1036 unsigned m_putByValIndex { UINT_MAX }; 1094 1037 unsigned m_inByIdIndex { UINT_MAX }; 1095 1038 unsigned m_inByValIndex { UINT_MAX }; -
trunk/Source/JavaScriptCore/jit/JITInlineCacheGenerator.cpp
r279105 r281615 143 143 JSValueRegs base, JSValueRegs value, GPRReg stubInfoGPR, GPRReg scratch, 144 144 ECMAMode ecmaMode, PutKind putKind) 145 : JITByIdGenerator(codeBlock, jitType, codeOrigin, callSite, AccessType::Put , usedRegisters, base, value, stubInfoGPR)145 : JITByIdGenerator(codeBlock, jitType, codeOrigin, callSite, AccessType::PutById, usedRegisters, base, value, stubInfoGPR) 146 146 , m_ecmaMode(ecmaMode) 147 147 , m_putKind(putKind) … … 382 382 } 383 383 384 JITPutByValGenerator::JITPutByValGenerator(CodeBlock* codeBlock, JITType jitType, CodeOrigin codeOrigin, CallSiteIndex callSiteIndex, AccessType accessType, const RegisterSet& usedRegisters, JSValueRegs base, JSValueRegs property, JSValueRegs value, GPRReg arrayProfileGPR, GPRReg stubInfoGPR) 385 : Base(codeBlock, jitType, codeOrigin, callSiteIndex, accessType, usedRegisters) 386 , m_base(base) 387 , m_value(value) 388 { 389 m_stubInfo->hasConstantIdentifier = false; 390 391 m_stubInfo->baseGPR = base.payloadGPR(); 392 m_stubInfo->regs.propertyGPR = property.payloadGPR(); 393 m_stubInfo->valueGPR = value.payloadGPR(); 394 m_stubInfo->m_stubInfoGPR = stubInfoGPR; 395 m_stubInfo->m_arrayProfileGPR = arrayProfileGPR; 396 #if USE(JSVALUE32_64) 397 m_stubInfo->baseTagGPR = base.tagGPR(); 398 m_stubInfo->valueTagGPR = value.tagGPR(); 399 m_stubInfo->v.propertyTagGPR = property.tagGPR(); 400 #endif 401 } 402 403 void JITPutByValGenerator::generateFastPath(MacroAssembler& jit) 404 { 405 m_start = jit.label(); 406 if (JITCode::useDataIC(m_jitType)) { 407 jit.move(CCallHelpers::TrustedImmPtr(m_stubInfo), m_stubInfo->m_stubInfoGPR); 408 jit.call(CCallHelpers::Address(m_stubInfo->m_stubInfoGPR, StructureStubInfo::offsetOfCodePtr()), JITStubRoutinePtrTag); 409 } else 410 m_slowPathJump = jit.patchableJump(); 411 m_done = jit.label(); 412 } 413 414 void JITPutByValGenerator::finalize(LinkBuffer& fastPath, LinkBuffer& slowPath) 415 { 416 Base::finalize(fastPath, slowPath, fastPath.locationOf<JITStubRoutinePtrTag>(m_start)); 417 if (JITCode::useDataIC(m_jitType)) 418 m_stubInfo->m_codePtr = m_stubInfo->slowPathStartLocation; 419 } 420 384 421 JITPrivateBrandAccessGenerator::JITPrivateBrandAccessGenerator(CodeBlock* codeBlock, JITType jitType, CodeOrigin codeOrigin, CallSiteIndex callSiteIndex, AccessType accessType, const RegisterSet& usedRegisters, JSValueRegs base, JSValueRegs brand, GPRReg stubInfoGPR) 385 422 : Base(codeBlock, jitType, codeOrigin, callSiteIndex, accessType, usedRegisters) -
trunk/Source/JavaScriptCore/jit/JITInlineCacheGenerator.h
r279105 r281615 130 130 class JITPutByIdGenerator final : public JITByIdGenerator { 131 131 public: 132 JITPutByIdGenerator() 133 : m_ecmaMode(ECMAMode::strict()) 134 { } 132 JITPutByIdGenerator() = default; 135 133 136 134 JITPutByIdGenerator( … … 143 141 144 142 private: 145 ECMAMode m_ecmaMode ;143 ECMAMode m_ecmaMode { ECMAMode::strict() }; 146 144 PutKind m_putKind; 145 }; 146 147 class JITPutByValGenerator final : public JITInlineCacheGenerator { 148 using Base = JITInlineCacheGenerator; 149 public: 150 JITPutByValGenerator() = default; 151 152 JITPutByValGenerator( 153 CodeBlock*, JITType, CodeOrigin, CallSiteIndex, AccessType, const RegisterSet& usedRegisters, 154 JSValueRegs base, JSValueRegs property, JSValueRegs result, GPRReg arrayProfileGPR, GPRReg stubInfoGPR); 155 156 MacroAssembler::Jump slowPathJump() const 157 { 158 ASSERT(m_slowPathJump.m_jump.isSet()); 159 return m_slowPathJump.m_jump; 160 } 161 162 void finalize(LinkBuffer& fastPathLinkBuffer, LinkBuffer& slowPathLinkBuffer); 163 164 void generateFastPath(MacroAssembler&); 165 166 private: 167 JSValueRegs m_base; 168 JSValueRegs m_value; 169 170 MacroAssembler::Label m_start; 171 MacroAssembler::PatchableJump m_slowPathJump; 147 172 }; 148 173 -
trunk/Source/JavaScriptCore/jit/JITInlines.h
r281454 r281615 353 353 } 354 354 355 inline void JIT::emitArrayProfilingSiteWithCell(RegisterID cellGPR, RegisterID arrayProfileGPR, RegisterID scratchGPR) 356 { 357 if (shouldEmitProfiling()) { 358 load32(MacroAssembler::Address(cellGPR, JSCell::structureIDOffset()), scratchGPR); 359 store32(scratchGPR, Address(arrayProfileGPR, ArrayProfile::offsetOfLastSeenStructureID())); 360 } 361 } 362 355 363 inline void JIT::emitArrayProfileStoreToHoleSpecialCase(ArrayProfile* arrayProfile) 356 364 { … … 361 369 { 362 370 store8(TrustedImm32(1), arrayProfile->addressOfOutOfBounds()); 363 }364 365 inline JITArrayMode JIT::chooseArrayMode(ArrayProfile* profile)366 {367 auto arrayProfileSaw = [] (ArrayModes arrayModes, IndexingType capability) {368 return arrayModesIncludeIgnoringTypedArrays(arrayModes, capability);369 };370 371 ConcurrentJSLocker locker(m_codeBlock->m_lock);372 profile->computeUpdatedPrediction(locker, m_codeBlock);373 ArrayModes arrayModes = profile->observedArrayModes(locker);374 if (arrayProfileSaw(arrayModes, DoubleShape))375 return JITDouble;376 if (arrayProfileSaw(arrayModes, Int32Shape))377 return JITInt32;378 if (arrayProfileSaw(arrayModes, ArrayStorageShape))379 return JITArrayStorage;380 return JITContiguous;381 371 } 382 372 -
trunk/Source/JavaScriptCore/jit/JITOperations.cpp
r281222 r281615 720 720 721 721 if (stubInfo->considerCachingBy(vm, codeBlock, structure, identifier)) 722 repatchPutBy ID(globalObject, codeBlock, baseValue, structure, identifier, slot, *stubInfo, PutKind::NotDirect);722 repatchPutBy(globalObject, codeBlock, baseValue, structure, identifier, slot, *stubInfo, PutByKind::ById, PutKind::NotDirect); 723 723 } 724 724 … … 752 752 753 753 if (stubInfo->considerCachingBy(vm, codeBlock, structure, identifier)) 754 repatchPutBy ID(globalObject, codeBlock, baseValue, structure, identifier, slot, *stubInfo, PutKind::NotDirect);754 repatchPutBy(globalObject, codeBlock, baseValue, structure, identifier, slot, *stubInfo, PutByKind::ById, PutKind::NotDirect); 755 755 } 756 756 … … 783 783 784 784 if (stubInfo->considerCachingBy(vm, codeBlock, structure, identifier)) 785 repatchPutBy ID(globalObject, codeBlock, baseObject, structure, identifier, slot, *stubInfo, PutKind::Direct);785 repatchPutBy(globalObject, codeBlock, baseObject, structure, identifier, slot, *stubInfo, PutByKind::ById, PutKind::Direct); 786 786 } 787 787 … … 814 814 815 815 if (stubInfo->considerCachingBy(vm, codeBlock, structure, identifier)) 816 repatchPutBy ID(globalObject, codeBlock, baseObject, structure, identifier, slot, *stubInfo, PutKind::Direct);816 repatchPutBy(globalObject, codeBlock, baseObject, structure, identifier, slot, *stubInfo, PutByKind::ById, PutKind::Direct); 817 817 } 818 818 … … 889 889 890 890 if (stubInfo->considerCachingBy(vm, codeBlock, oldStructure, identifier)) 891 repatchPutBy ID(globalObject, codeBlock, baseObject, oldStructure, identifier, putSlot, *stubInfo, PutKind::DirectPrivateFieldDefine);891 repatchPutBy(globalObject, codeBlock, baseObject, oldStructure, identifier, putSlot, *stubInfo, PutByKind::ById, PutKind::DirectPrivateFieldDefine); 892 892 }); 893 893 } … … 925 925 926 926 if (stubInfo->considerCachingBy(vm, codeBlock, oldStructure, identifier)) 927 repatchPutBy ID(globalObject, codeBlock, baseObject, oldStructure, identifier, putSlot, *stubInfo, PutKind::DirectPrivateFieldSet);927 repatchPutBy(globalObject, codeBlock, baseObject, oldStructure, identifier, putSlot, *stubInfo, PutByKind::ById, PutKind::DirectPrivateFieldSet); 928 928 }); 929 929 } 930 930 931 static void putByVal(JSGlobalObject* globalObject, JSValue baseValue, JSValue subscript, JSValue value, ByValInfo* byValInfo, ECMAMode ecmaMode)931 static void putByVal(JSGlobalObject* globalObject, JSValue baseValue, JSValue subscript, JSValue value, ArrayProfile* arrayProfile, ECMAMode ecmaMode) 932 932 { 933 933 VM& vm = globalObject->vm(); 934 934 auto scope = DECLARE_THROW_SCOPE(vm); 935 935 if (std::optional<uint32_t> index = subscript.tryGetAsUint32Index()) { 936 byValInfo->tookSlowPath = true;937 936 uint32_t i = *index; 938 937 if (baseValue.isObject()) { … … 943 942 } 944 943 945 byValInfo->arrayProfile->setOutOfBounds(); 944 if (arrayProfile) 945 arrayProfile->setOutOfBounds(); 946 946 scope.release(); 947 947 object->methodTable(vm)->putByIndex(object, globalObject, i, value, ecmaMode.isStrict()); … … 952 952 baseValue.putByIndex(globalObject, i, value, ecmaMode.isStrict()); 953 953 return; 954 } 954 } 955 955 956 if (subscript.isNumber()) { 956 byValInfo->tookSlowPath = true; 957 if (baseValue.isObject()) 958 byValInfo->arrayProfile->setOutOfBounds(); 957 if (baseValue.isObject()) { 958 if (arrayProfile) 959 arrayProfile->setOutOfBounds(); 960 } 959 961 } 960 962 … … 963 965 RETURN_IF_EXCEPTION(scope, void()); 964 966 965 if (byValInfo->stubInfo && (!CacheableIdentifier::isCacheableIdentifierCell(subscript) || byValInfo->cachedId.uid() != property))966 byValInfo->tookSlowPath = true;967 968 967 scope.release(); 969 968 PutPropertySlot slot(baseValue, ecmaMode.isStrict()); … … 971 970 } 972 971 973 static void directPutByVal(JSGlobalObject* globalObject, JSObject* baseObject, JSValue subscript, JSValue value, ByValInfo* byValInfo, ECMAMode ecmaMode)972 static void directPutByVal(JSGlobalObject* globalObject, JSObject* baseObject, JSValue subscript, JSValue value, ArrayProfile* arrayProfile, ECMAMode ecmaMode) 974 973 { 975 974 VM& vm = globalObject->vm(); … … 977 976 978 977 if (std::optional<uint32_t> maybeIndex = subscript.tryGetAsUint32Index()) { 979 byValInfo->tookSlowPath = true;980 978 uint32_t index = *maybeIndex; 981 979 … … 989 987 FALLTHROUGH; 990 988 default: 991 byValInfo->arrayProfile->setOutOfBounds(); 989 if (arrayProfile) 990 arrayProfile->setOutOfBounds(); 992 991 break; 993 992 } … … 1003 1002 1004 1003 if (std::optional<uint32_t> index = parseIndex(property)) { 1005 byValInfo->tookSlowPath = true;1006 1004 scope.release(); 1007 1005 baseObject->putDirectIndex(globalObject, index.value(), value, 0, ecmaMode.isStrict() ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow); 1008 1006 return; 1009 1007 } 1010 1011 if (byValInfo->stubInfo && (!CacheableIdentifier::isCacheableIdentifierCell(subscript) || byValInfo->cachedId.uid() != property))1012 byValInfo->tookSlowPath = true;1013 1008 1014 1009 scope.release(); … … 1024 1019 }; 1025 1020 1026 static OptimizationResult tryPutByValOptimize(JSGlobalObject* globalObject, CallFrame* callFrame, CodeBlock* codeBlock, JSValue baseValue, JSValue subscript, ByValInfo* byValInfo, ReturnAddressPtr returnAddress) 1027 { 1028 UNUSED_PARAM(callFrame); 1029 1030 // See if it's worth optimizing at all. 1031 OptimizationResult optimizationResult = OptimizationResult::NotOptimized; 1032 1033 VM& vm = globalObject->vm(); 1034 auto scope = DECLARE_THROW_SCOPE(vm); 1035 1036 if (baseValue.isObject() && isCopyOnWrite(baseValue.getObject()->indexingMode())) 1037 return OptimizationResult::GiveUp; 1038 1039 if (baseValue.isObject() && subscript.isInt32()) { 1040 JSObject* object = asObject(baseValue); 1041 1042 ASSERT(callFrame->bytecodeIndex() != BytecodeIndex(0)); 1043 ASSERT(!byValInfo->stubRoutine); 1044 1045 Structure* structure = object->structure(vm); 1046 if (hasOptimizableIndexing(structure)) { 1047 // Attempt to optimize. 1048 JITArrayMode arrayMode = jitArrayModeForStructure(structure); 1049 if (jitArrayModePermitsPut(arrayMode) && arrayMode != byValInfo->arrayMode) { 1050 ConcurrentJSLocker locker(codeBlock->m_lock); 1051 byValInfo->arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure); 1052 JIT::compilePutByVal(locker, vm, codeBlock, byValInfo, returnAddress, arrayMode); 1053 optimizationResult = OptimizationResult::Optimized; 1021 static ALWAYS_INLINE void putByValOptimize(JSGlobalObject* globalObject, CodeBlock* codeBlock, JSValue baseValue, JSValue subscript, JSValue value, StructureStubInfo* stubInfo, ArrayProfile* profile, ECMAMode ecmaMode) 1022 { 1023 VM& vm = globalObject->vm(); 1024 auto scope = DECLARE_THROW_SCOPE(vm); 1025 1026 if (baseValue.isObject()) { 1027 JSObject* baseObject = asObject(baseValue); 1028 if (!isCopyOnWrite(baseObject->indexingMode()) && subscript.isInt32()) { 1029 Structure* structure = baseObject->structure(vm); 1030 if (stubInfo->considerCachingGeneric(vm, codeBlock, structure)) { 1031 if (profile) { 1032 ConcurrentJSLocker locker(codeBlock->m_lock); 1033 profile->computeUpdatedPrediction(locker, codeBlock, structure); 1034 } 1035 repatchArrayPutByVal(globalObject, codeBlock, baseValue, subscript, *stubInfo, PutKind::NotDirect, ecmaMode); 1054 1036 } 1055 1037 } 1056 1038 1057 // If we failed to patch and we have some object that intercepts indexed get, then don't even wait until 10 times. 1058 if (optimizationResult != OptimizationResult::Optimized && object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) 1059 optimizationResult = OptimizationResult::GiveUp; 1060 } 1061 1062 if (baseValue.isObject() && CacheableIdentifier::isCacheableIdentifierCell(subscript)) { 1063 const Identifier propertyName = subscript.toPropertyKey(globalObject); 1064 RETURN_IF_EXCEPTION(scope, OptimizationResult::GiveUp); 1065 if (subscript.isSymbol() || !parseIndex(propertyName)) { 1066 ASSERT(callFrame->bytecodeIndex() != BytecodeIndex(0)); 1067 ASSERT(!byValInfo->stubRoutine); 1068 if (byValInfo->seen) { 1069 if (byValInfo->cachedId.uid() == propertyName) { 1070 JIT::compilePutByValWithCachedId<OpPutByVal>(vm, codeBlock, byValInfo, returnAddress, PutKind::NotDirect, byValInfo->cachedId); 1071 optimizationResult = OptimizationResult::Optimized; 1072 } else { 1073 // Seem like a generic property access site. 1074 optimizationResult = OptimizationResult::GiveUp; 1075 } 1076 } else { 1077 { 1078 ConcurrentJSLocker locker(codeBlock->m_lock); 1079 byValInfo->seen = true; 1080 byValInfo->cachedId = CacheableIdentifier::createFromCell(subscript.asCell()); 1081 optimizationResult = OptimizationResult::SeenOnce; 1082 } 1083 vm.heap.writeBarrier(codeBlock, subscript.asCell()); 1039 if (CacheableIdentifier::isCacheableIdentifierCell(subscript)) { 1040 const Identifier propertyName = subscript.toPropertyKey(globalObject); 1041 RETURN_IF_EXCEPTION(scope, void()); 1042 if (subscript.isSymbol() || !parseIndex(propertyName)) { 1043 AccessType accessType = static_cast<AccessType>(stubInfo->accessType); 1044 PutPropertySlot slot(baseValue, ecmaMode.isStrict(), codeBlock->putByIdContext()); 1045 1046 Structure* structure = CommonSlowPaths::originalStructureBeforePut(vm, baseValue); 1047 baseObject->putInline(globalObject, propertyName, value, slot); 1048 RETURN_IF_EXCEPTION(scope, void()); 1049 1050 if (accessType != static_cast<AccessType>(stubInfo->accessType)) 1051 return; 1052 1053 CacheableIdentifier identifier = CacheableIdentifier::createFromCell(subscript.asCell()); 1054 if (stubInfo->considerCachingBy(vm, codeBlock, structure, identifier)) 1055 repatchPutBy(globalObject, codeBlock, baseValue, structure, identifier, slot, *stubInfo, PutByKind::ByVal, PutKind::NotDirect); 1056 return; 1084 1057 } 1085 1058 } 1086 1059 } 1087 1060 1088 if (optimizationResult != OptimizationResult::Optimized && optimizationResult != OptimizationResult::SeenOnce) { 1089 // If we take slow path more than 10 times without patching then make sure we 1090 // never make that mistake again. For cases where we see non-index-intercepting 1091 // objects, this gives 10 iterations worth of opportunity for us to observe 1092 // that the put_by_val may be polymorphic. We count up slowPathCount even if 1093 // the result is GiveUp. 1094 if (++byValInfo->slowPathCount >= 10) 1095 optimizationResult = OptimizationResult::GiveUp; 1096 } 1097 1098 return optimizationResult; 1099 } 1100 1101 JSC_DEFINE_JIT_OPERATION(operationPutByValOptimize, void, (JSGlobalObject* globalObject, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ByValInfo* byValInfo, ECMAMode ecmaMode)) 1102 { 1103 VM& vm = globalObject->vm(); 1104 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 1105 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 1106 auto scope = DECLARE_THROW_SCOPE(vm); 1061 RELEASE_AND_RETURN(scope, putByVal(globalObject, baseValue, subscript, value, profile, ecmaMode)); 1062 } 1063 1064 JSC_DEFINE_JIT_OPERATION(operationPutByValStrictOptimize, void, (JSGlobalObject* globalObject, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, StructureStubInfo* stubInfo, ArrayProfile* profile)) 1065 { 1066 VM& vm = globalObject->vm(); 1067 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 1068 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 1107 1069 1108 1070 JSValue baseValue = JSValue::decode(encodedBaseValue); 1109 1071 JSValue subscript = JSValue::decode(encodedSubscript); 1110 1072 JSValue value = JSValue::decode(encodedValue); 1111 CodeBlock* codeBlock = callFrame->codeBlock(); 1112 OptimizationResult result = tryPutByValOptimize(globalObject, callFrame, codeBlock, baseValue, subscript, byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS)); 1113 RETURN_IF_EXCEPTION(scope, void()); 1114 if (result == OptimizationResult::GiveUp) { 1115 // Don't ever try to optimize. 1116 byValInfo->tookSlowPath = true; 1117 if (codeBlock->useDataIC()) 1118 byValInfo->m_slowOperation = operationPutByValGeneric; 1119 else 1120 ctiPatchCallByReturnAddress(ReturnAddressPtr(OUR_RETURN_ADDRESS), operationPutByValGeneric); 1121 } 1122 RELEASE_AND_RETURN(scope, putByVal(globalObject, baseValue, subscript, value, byValInfo, ecmaMode)); 1123 } 1124 1125 static OptimizationResult tryDirectPutByValOptimize(JSGlobalObject* globalObject, CallFrame* callFrame, CodeBlock* codeBlock, JSObject* object, JSValue subscript, ByValInfo* byValInfo, ReturnAddressPtr returnAddress) 1126 { 1127 UNUSED_PARAM(callFrame); 1128 1129 // See if it's worth optimizing at all. 1130 OptimizationResult optimizationResult = OptimizationResult::NotOptimized; 1131 1132 VM& vm = globalObject->vm(); 1133 auto scope = DECLARE_THROW_SCOPE(vm); 1134 1135 if (subscript.isInt32()) { 1136 ASSERT(callFrame->bytecodeIndex() != BytecodeIndex(0)); 1137 ASSERT(!byValInfo->stubRoutine); 1138 1139 Structure* structure = object->structure(vm); 1140 if (hasOptimizableIndexing(structure)) { 1141 // Attempt to optimize. 1142 JITArrayMode arrayMode = jitArrayModeForStructure(structure); 1143 if (jitArrayModePermitsPutDirect(arrayMode) && arrayMode != byValInfo->arrayMode) { 1073 1074 putByValOptimize(globalObject, callFrame->codeBlock(), baseValue, subscript, value, stubInfo, profile, ECMAMode::strict()); 1075 } 1076 1077 JSC_DEFINE_JIT_OPERATION(operationPutByValNonStrictOptimize, void, (JSGlobalObject* globalObject, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, StructureStubInfo* stubInfo, ArrayProfile* profile)) 1078 { 1079 VM& vm = globalObject->vm(); 1080 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 1081 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 1082 1083 JSValue baseValue = JSValue::decode(encodedBaseValue); 1084 JSValue subscript = JSValue::decode(encodedSubscript); 1085 JSValue value = JSValue::decode(encodedValue); 1086 1087 putByValOptimize(globalObject, callFrame->codeBlock(), baseValue, subscript, value, stubInfo, profile, ECMAMode::sloppy()); 1088 } 1089 1090 static ALWAYS_INLINE void directPutByValOptimize(JSGlobalObject* globalObject, CodeBlock* codeBlock, JSValue baseValue, JSValue subscript, JSValue value, StructureStubInfo* stubInfo, ArrayProfile* profile, ECMAMode ecmaMode) 1091 { 1092 VM& vm = globalObject->vm(); 1093 auto scope = DECLARE_THROW_SCOPE(vm); 1094 1095 RELEASE_ASSERT(baseValue.isObject()); 1096 JSObject* baseObject = asObject(baseValue); 1097 1098 if (!isCopyOnWrite(baseObject->indexingMode()) && subscript.isInt32()) { 1099 Structure* structure = baseObject->structure(vm); 1100 if (stubInfo->considerCachingGeneric(vm, codeBlock, structure)) { 1101 if (profile) { 1144 1102 ConcurrentJSLocker locker(codeBlock->m_lock); 1145 byValInfo->arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure); 1146 1147 JIT::compileDirectPutByVal(locker, vm, codeBlock, byValInfo, returnAddress, arrayMode); 1148 optimizationResult = OptimizationResult::Optimized; 1103 profile->computeUpdatedPrediction(locker, codeBlock, structure); 1149 1104 } 1105 repatchArrayPutByVal(globalObject, codeBlock, baseValue, subscript, *stubInfo, PutKind::Direct, ecmaMode); 1150 1106 } 1151 1152 // If we failed to patch and we have some object that intercepts indexed get, then don't even wait until 10 times. 1153 if (optimizationResult != OptimizationResult::Optimized && object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) 1154 optimizationResult = OptimizationResult::GiveUp; 1155 } else if (CacheableIdentifier::isCacheableIdentifierCell(subscript)) { 1107 } 1108 1109 if (CacheableIdentifier::isCacheableIdentifierCell(subscript)) { 1156 1110 const Identifier propertyName = subscript.toPropertyKey(globalObject); 1157 RETURN_IF_EXCEPTION(scope, OptimizationResult::GiveUp);1111 RETURN_IF_EXCEPTION(scope, void()); 1158 1112 if (subscript.isSymbol() || !parseIndex(propertyName)) { 1159 ASSERT(callFrame->bytecodeIndex() != BytecodeIndex(0)); 1160 ASSERT(!byValInfo->stubRoutine); 1161 if (byValInfo->seen) { 1162 if (byValInfo->cachedId.uid() == propertyName) { 1163 JIT::compilePutByValWithCachedId<OpPutByValDirect>(vm, codeBlock, byValInfo, returnAddress, PutKind::Direct, byValInfo->cachedId); 1164 optimizationResult = OptimizationResult::Optimized; 1165 } else { 1166 // Seem like a generic property access site. 1167 optimizationResult = OptimizationResult::GiveUp; 1168 } 1169 } else { 1170 { 1171 ConcurrentJSLocker locker(codeBlock->m_lock); 1172 byValInfo->seen = true; 1173 byValInfo->cachedId = CacheableIdentifier::createFromCell(subscript.asCell()); 1174 optimizationResult = OptimizationResult::SeenOnce; 1175 } 1176 vm.heap.writeBarrier(codeBlock, subscript.asCell()); 1177 } 1113 AccessType accessType = static_cast<AccessType>(stubInfo->accessType); 1114 PutPropertySlot slot(baseValue, ecmaMode.isStrict(), codeBlock->putByIdContext()); 1115 1116 Structure* structure = CommonSlowPaths::originalStructureBeforePut(vm, baseValue); 1117 CommonSlowPaths::putDirectWithReify(vm, globalObject, baseObject, propertyName, value, slot); 1118 1119 RETURN_IF_EXCEPTION(scope, void()); 1120 1121 if (accessType != static_cast<AccessType>(stubInfo->accessType)) 1122 return; 1123 1124 CacheableIdentifier identifier = CacheableIdentifier::createFromCell(subscript.asCell()); 1125 if (stubInfo->considerCachingBy(vm, codeBlock, structure, identifier)) 1126 repatchPutBy(globalObject, codeBlock, baseValue, structure, identifier, slot, *stubInfo, PutByKind::ByVal, PutKind::Direct); 1127 return; 1178 1128 } 1179 1129 } 1180 1130 1181 if (optimizationResult != OptimizationResult::Optimized && optimizationResult != OptimizationResult::SeenOnce) { 1182 // If we take slow path more than 10 times without patching then make sure we 1183 // never make that mistake again. For cases where we see non-index-intercepting 1184 // objects, this gives 10 iterations worth of opportunity for us to observe 1185 // that the get_by_val may be polymorphic. We count up slowPathCount even if 1186 // the result is GiveUp. 1187 if (++byValInfo->slowPathCount >= 10) 1188 optimizationResult = OptimizationResult::GiveUp; 1189 } 1190 1191 return optimizationResult; 1192 } 1193 1194 JSC_DEFINE_JIT_OPERATION(operationDirectPutByValOptimize, void, (JSGlobalObject* globalObject, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ByValInfo* byValInfo, ECMAMode ecmaMode)) 1195 { 1196 VM& vm = globalObject->vm(); 1197 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 1198 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 1199 auto scope = DECLARE_THROW_SCOPE(vm); 1131 RELEASE_AND_RETURN(scope, directPutByVal(globalObject, baseObject, subscript, value, profile, ecmaMode)); 1132 1133 } 1134 1135 JSC_DEFINE_JIT_OPERATION(operationDirectPutByValStrictOptimize, void, (JSGlobalObject* globalObject, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, StructureStubInfo* stubInfo, ArrayProfile* profile)) 1136 { 1137 VM& vm = globalObject->vm(); 1138 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 1139 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 1140 1141 JSValue baseValue = JSValue::decode(encodedBaseValue); 1142 JSValue subscript = JSValue::decode(encodedSubscript); 1143 JSValue value = JSValue::decode(encodedValue); 1144 1145 directPutByValOptimize(globalObject, callFrame->codeBlock(), baseValue, subscript, value, stubInfo, profile, ECMAMode::strict()); 1146 } 1147 1148 JSC_DEFINE_JIT_OPERATION(operationDirectPutByValNonStrictOptimize, void, (JSGlobalObject* globalObject, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, StructureStubInfo* stubInfo, ArrayProfile* profile)) 1149 { 1150 VM& vm = globalObject->vm(); 1151 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 1152 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 1153 1154 JSValue baseValue = JSValue::decode(encodedBaseValue); 1155 JSValue subscript = JSValue::decode(encodedSubscript); 1156 JSValue value = JSValue::decode(encodedValue); 1157 1158 directPutByValOptimize(globalObject, callFrame->codeBlock(), baseValue, subscript, value, stubInfo, profile, ECMAMode::sloppy()); 1159 } 1160 1161 JSC_DEFINE_JIT_OPERATION(operationPutByValStrictGeneric, void, (JSGlobalObject* globalObject, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, StructureStubInfo* stubInfo, ArrayProfile* profile)) 1162 { 1163 VM& vm = globalObject->vm(); 1164 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 1165 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 1166 1167 JSValue baseValue = JSValue::decode(encodedBaseValue); 1168 JSValue subscript = JSValue::decode(encodedSubscript); 1169 JSValue value = JSValue::decode(encodedValue); 1170 1171 stubInfo->tookSlowPath = true; 1172 1173 putByVal(globalObject, baseValue, subscript, value, profile, ECMAMode::strict()); 1174 } 1175 1176 JSC_DEFINE_JIT_OPERATION(operationPutByValNonStrictGeneric, void, (JSGlobalObject* globalObject, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, StructureStubInfo* stubInfo, ArrayProfile* profile)) 1177 { 1178 VM& vm = globalObject->vm(); 1179 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 1180 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 1181 1182 JSValue baseValue = JSValue::decode(encodedBaseValue); 1183 JSValue subscript = JSValue::decode(encodedSubscript); 1184 JSValue value = JSValue::decode(encodedValue); 1185 1186 stubInfo->tookSlowPath = true; 1187 1188 putByVal(globalObject, baseValue, subscript, value, profile, ECMAMode::sloppy()); 1189 } 1190 1191 JSC_DEFINE_JIT_OPERATION(operationDirectPutByValStrictGeneric, void, (JSGlobalObject* globalObject, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, StructureStubInfo* stubInfo, ArrayProfile* profile)) 1192 { 1193 VM& vm = globalObject->vm(); 1194 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 1195 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 1200 1196 1201 1197 JSValue baseValue = JSValue::decode(encodedBaseValue); … … 1203 1199 JSValue value = JSValue::decode(encodedValue); 1204 1200 RELEASE_ASSERT(baseValue.isObject()); 1205 JSObject* object = asObject(baseValue); 1206 CodeBlock* codeBlock = callFrame->codeBlock(); 1207 OptimizationResult result = tryDirectPutByValOptimize(globalObject, callFrame, codeBlock, object, subscript, byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS)); 1208 RETURN_IF_EXCEPTION(scope, void()); 1209 if (result == OptimizationResult::GiveUp) { 1210 // Don't ever try to optimize. 1211 byValInfo->tookSlowPath = true; 1212 if (codeBlock->useDataIC()) 1213 byValInfo->m_slowOperation = operationDirectPutByValGeneric; 1214 else 1215 ctiPatchCallByReturnAddress(ReturnAddressPtr(OUR_RETURN_ADDRESS), operationDirectPutByValGeneric); 1216 } 1217 1218 RELEASE_AND_RETURN(scope, directPutByVal(globalObject, object, subscript, value, byValInfo, ecmaMode)); 1219 } 1220 1221 JSC_DEFINE_JIT_OPERATION(operationPutByValGeneric, void, (JSGlobalObject* globalObject, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ByValInfo* byValInfo, ECMAMode ecmaMode)) 1222 { 1223 VM& vm = globalObject->vm(); 1224 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 1225 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 1226 1227 JSValue baseValue = JSValue::decode(encodedBaseValue); 1228 JSValue subscript = JSValue::decode(encodedSubscript); 1229 JSValue value = JSValue::decode(encodedValue); 1230 1231 putByVal(globalObject, baseValue, subscript, value, byValInfo, ecmaMode); 1232 } 1233 1234 1235 JSC_DEFINE_JIT_OPERATION(operationDirectPutByValGeneric, void, (JSGlobalObject* globalObject, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ByValInfo* byValInfo, ECMAMode ecmaMode)) 1236 { 1237 VM& vm = globalObject->vm(); 1238 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 1239 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 1240 1201 1202 stubInfo->tookSlowPath = true; 1203 1204 directPutByVal(globalObject, asObject(baseValue), subscript, value, profile, ECMAMode::strict()); 1205 } 1206 1207 JSC_DEFINE_JIT_OPERATION(operationDirectPutByValNonStrictGeneric, void, (JSGlobalObject* globalObject, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, StructureStubInfo* stubInfo, ArrayProfile* profile)) 1208 { 1209 VM& vm = globalObject->vm(); 1210 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 1211 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 1212 1241 1213 JSValue baseValue = JSValue::decode(encodedBaseValue); 1242 1214 JSValue subscript = JSValue::decode(encodedSubscript); 1243 1215 JSValue value = JSValue::decode(encodedValue); 1244 1216 RELEASE_ASSERT(baseValue.isObject()); 1245 directPutByVal(globalObject, asObject(baseValue), subscript, value, byValInfo, ecmaMode); 1217 1218 stubInfo->tookSlowPath = true; 1219 1220 directPutByVal(globalObject, asObject(baseValue), subscript, value, profile, ECMAMode::sloppy()); 1246 1221 } 1247 1222 -
trunk/Source/JavaScriptCore/jit/JITOperations.h
r281222 r281615 204 204 JSC_DECLARE_JIT_OPERATION(operationPutPrivateNameOptimize, void, (JSGlobalObject*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ByValInfo*, PrivateFieldPutKind)); 205 205 JSC_DECLARE_JIT_OPERATION(operationPutPrivateNameGeneric, void, (JSGlobalObject*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ByValInfo*, PrivateFieldPutKind)); 206 JSC_DECLARE_JIT_OPERATION(operationPutByValOptimize, void, (JSGlobalObject*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ByValInfo*, ECMAMode)); 207 JSC_DECLARE_JIT_OPERATION(operationDirectPutByValOptimize, void, (JSGlobalObject*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ByValInfo*, ECMAMode)); 208 JSC_DECLARE_JIT_OPERATION(operationPutByValGeneric, void, (JSGlobalObject*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ByValInfo*, ECMAMode)); 209 JSC_DECLARE_JIT_OPERATION(operationDirectPutByValGeneric, void, (JSGlobalObject*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ByValInfo*, ECMAMode)); 206 207 JSC_DECLARE_JIT_OPERATION(operationPutByValNonStrictOptimize, void, (JSGlobalObject*, EncodedJSValue, EncodedJSValue, EncodedJSValue, StructureStubInfo*, ArrayProfile*)); 208 JSC_DECLARE_JIT_OPERATION(operationPutByValStrictOptimize, void, (JSGlobalObject*, EncodedJSValue, EncodedJSValue, EncodedJSValue, StructureStubInfo*, ArrayProfile*)); 209 JSC_DECLARE_JIT_OPERATION(operationDirectPutByValNonStrictOptimize, void, (JSGlobalObject*, EncodedJSValue, EncodedJSValue, EncodedJSValue, StructureStubInfo*, ArrayProfile*)); 210 JSC_DECLARE_JIT_OPERATION(operationDirectPutByValStrictOptimize, void, (JSGlobalObject*, EncodedJSValue, EncodedJSValue, EncodedJSValue, StructureStubInfo*, ArrayProfile*)); 211 JSC_DECLARE_JIT_OPERATION(operationPutByValNonStrictGeneric, void, (JSGlobalObject*, EncodedJSValue, EncodedJSValue, EncodedJSValue, StructureStubInfo*, ArrayProfile*)); 212 JSC_DECLARE_JIT_OPERATION(operationPutByValStrictGeneric, void, (JSGlobalObject*, EncodedJSValue, EncodedJSValue, EncodedJSValue, StructureStubInfo*, ArrayProfile*)); 213 JSC_DECLARE_JIT_OPERATION(operationDirectPutByValStrictGeneric, void, (JSGlobalObject*, EncodedJSValue, EncodedJSValue, EncodedJSValue, StructureStubInfo*, ArrayProfile*)); 214 JSC_DECLARE_JIT_OPERATION(operationDirectPutByValNonStrictGeneric, void, (JSGlobalObject*, EncodedJSValue, EncodedJSValue, EncodedJSValue, StructureStubInfo*, ArrayProfile*)); 210 215 211 216 JSC_DECLARE_JIT_OPERATION(operationCallEval, EncodedJSValue, (JSGlobalObject*, CallFrame*, ECMAMode)); -
trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp
r281565 r281615 439 439 VirtualRegister base = bytecode.m_base; 440 440 VirtualRegister property = bytecode.m_property; 441 ArrayProfile* profile = &metadata.m_arrayProfile;442 ByValInfo* byValInfo = m_codeBlock->addByValInfo(m_bytecodeIndex);443 444 emitGetVirtualRegister(base, regT0);445 bool propertyNameIsIntegerConstant = isOperandConstantInt(property);446 if (propertyNameIsIntegerConstant)447 move(Imm32(getOperandConstantInt(property)), regT1);448 else449 emitGetVirtualRegister(property, regT1);450 451 emitJumpSlowCaseIfNotJSCell(regT0, base);452 PatchableJump notIndex;453 if (!propertyNameIsIntegerConstant) {454 if (JITCode::useDataIC(JITType::BaselineJIT)) {455 auto isInt32 = branchIfInt32(regT1);456 farJump(AbsoluteAddress(&byValInfo->m_notIndexJumpTarget), JITStubRoutinePtrTag);457 isInt32.link(this);458 } else {459 notIndex = emitPatchableJumpIfNotInt(regT1);460 addSlowCase(notIndex);461 }462 // See comment in op_get_by_val.463 zeroExtend32ToWord(regT1, regT1);464 }465 emitArrayProfilingSiteWithCell(regT0, profile, regT2);466 467 PatchableJump badType;468 JumpList slowCases;469 470 // FIXME: Maybe we should do this inline?471 load8(Address(regT0, JSCell::indexingTypeAndMiscOffset()), regT2);472 addSlowCase(branchTest32(NonZero, regT2, TrustedImm32(CopyOnWrite)));473 and32(TrustedImm32(IndexingShapeMask), regT2);474 475 JITArrayMode mode = chooseArrayMode(profile);476 switch (mode) {477 case JITInt32:478 slowCases = emitInt32PutByVal(bytecode, badType, byValInfo);479 break;480 case JITDouble:481 slowCases = emitDoublePutByVal(bytecode, badType, byValInfo);482 break;483 case JITContiguous:484 slowCases = emitContiguousPutByVal(bytecode, badType, byValInfo);485 break;486 case JITArrayStorage:487 slowCases = emitArrayStoragePutByVal(bytecode, badType, byValInfo);488 break;489 default:490 CRASH();491 break;492 }493 494 if (!JITCode::useDataIC(JITType::BaselineJIT))495 addSlowCase(badType);496 addSlowCase(slowCases);497 498 Label done = label();499 500 m_byValCompilationInfo.append(ByValCompilationInfo(byValInfo, m_bytecodeIndex, notIndex, badType, mode, profile, done, done));501 }502 503 template<typename Op>504 JIT::JumpList JIT::emitGenericContiguousPutByVal(Op bytecode, PatchableJump& badType, ByValInfo* byValInfo, IndexingType indexingShape)505 {506 auto& metadata = bytecode.metadata(m_codeBlock);507 441 VirtualRegister value = bytecode.m_value; 508 442 ArrayProfile* profile = &metadata.m_arrayProfile; 509 510 JumpList slowCases; 511 512 if (JITCode::useDataIC(JITType::BaselineJIT)) { 513 if (byValInfo) { 514 auto isCorrectType = branch32(Equal, regT2, TrustedImm32(indexingShape)); 515 farJump(AbsoluteAddress(&byValInfo->m_badTypeJumpTarget), JITStubRoutinePtrTag); 516 isCorrectType.link(this); 517 } else 518 badType = patchableBranch32(NotEqual, regT2, TrustedImm32(indexingShape)); 519 } else 520 badType = patchableBranch32(NotEqual, regT2, TrustedImm32(indexingShape)); 521 522 523 loadPtr(Address(regT0, JSObject::butterflyOffset()), regT2); 524 Jump outOfBounds = branch32(AboveOrEqual, regT1, Address(regT2, Butterfly::offsetOfPublicLength())); 525 526 Label storeResult = label(); 527 emitGetVirtualRegister(value, regT3); 528 switch (indexingShape) { 529 case Int32Shape: 530 slowCases.append(branchIfNotInt32(regT3)); 531 store64(regT3, BaseIndex(regT2, regT1, TimesEight)); 532 break; 533 case DoubleShape: { 534 Jump notInt = branchIfNotInt32(regT3); 535 convertInt32ToDouble(regT3, fpRegT0); 536 Jump ready = jump(); 537 notInt.link(this); 538 add64(numberTagRegister, regT3); 539 move64ToDouble(regT3, fpRegT0); 540 slowCases.append(branchIfNaN(fpRegT0)); 541 ready.link(this); 542 storeDouble(fpRegT0, BaseIndex(regT2, regT1, TimesEight)); 543 break; 544 } 545 case ContiguousShape: 546 store64(regT3, BaseIndex(regT2, regT1, TimesEight)); 547 emitWriteBarrier(bytecode.m_base, value, ShouldFilterValue); 548 break; 549 default: 550 CRASH(); 551 break; 552 } 553 554 Jump done = jump(); 555 outOfBounds.link(this); 556 557 slowCases.append(branch32(AboveOrEqual, regT1, Address(regT2, Butterfly::offsetOfVectorLength()))); 558 559 emitArrayProfileStoreToHoleSpecialCase(profile); 560 561 add32(TrustedImm32(1), regT1, regT3); 562 store32(regT3, Address(regT2, Butterfly::offsetOfPublicLength())); 563 jump().linkTo(storeResult, this); 564 565 done.link(this); 566 567 return slowCases; 568 } 569 570 template<typename Op> 571 JIT::JumpList JIT::emitArrayStoragePutByVal(Op bytecode, PatchableJump& badType, ByValInfo* byValInfo) 572 { 573 auto& metadata = bytecode.metadata(m_codeBlock); 574 VirtualRegister value = bytecode.m_value; 575 ArrayProfile* profile = &metadata.m_arrayProfile; 576 577 JumpList slowCases; 578 579 if (JITCode::useDataIC(JITType::BaselineJIT)) { 580 if (byValInfo) { 581 auto isCorrectType = branch32(Equal, regT2, TrustedImm32(ArrayStorageShape)); 582 farJump(AbsoluteAddress(&byValInfo->m_badTypeJumpTarget), JITStubRoutinePtrTag); 583 isCorrectType.link(this); 584 } else 585 badType = patchableBranch32(NotEqual, regT2, TrustedImm32(ArrayStorageShape)); 586 } else 587 badType = patchableBranch32(NotEqual, regT2, TrustedImm32(ArrayStorageShape)); 588 589 loadPtr(Address(regT0, JSObject::butterflyOffset()), regT2); 590 slowCases.append(branch32(AboveOrEqual, regT1, Address(regT2, ArrayStorage::vectorLengthOffset()))); 591 592 Jump empty = branchTest64(Zero, BaseIndex(regT2, regT1, TimesEight, ArrayStorage::vectorOffset())); 593 594 Label storeResult(this); 595 emitGetVirtualRegister(value, regT3); 596 store64(regT3, BaseIndex(regT2, regT1, TimesEight, ArrayStorage::vectorOffset())); 597 emitWriteBarrier(bytecode.m_base, value, ShouldFilterValue); 598 Jump end = jump(); 599 600 empty.link(this); 601 emitArrayProfileStoreToHoleSpecialCase(profile); 602 add32(TrustedImm32(1), Address(regT2, ArrayStorage::numValuesInVectorOffset())); 603 branch32(Below, regT1, Address(regT2, ArrayStorage::lengthOffset())).linkTo(storeResult, this); 604 605 add32(TrustedImm32(1), regT1); 606 store32(regT1, Address(regT2, ArrayStorage::lengthOffset())); 607 sub32(TrustedImm32(1), regT1); 608 jump().linkTo(storeResult, this); 609 610 end.link(this); 611 612 return slowCases; 443 444 emitGetVirtualRegister(base, regT0); 445 emitGetVirtualRegister(property, regT1); 446 emitGetVirtualRegister(value, regT2); 447 move(TrustedImmPtr(profile), regT3); 448 449 emitJumpSlowCaseIfNotJSCell(regT0, base); 450 emitArrayProfilingSiteWithCell(regT0, regT3, regT4); 451 452 JITPutByValGenerator gen( 453 m_codeBlock, JITType::BaselineJIT, CodeOrigin(m_bytecodeIndex), CallSiteIndex(m_bytecodeIndex), AccessType::PutByVal, RegisterSet::stubUnavailableRegisters(), 454 JSValueRegs(regT0), JSValueRegs(regT1), JSValueRegs(regT2), regT3, regT4); 455 if (isOperandConstantInt(property)) 456 gen.stubInfo()->propertyIsInt32 = true; 457 gen.generateFastPath(*this); 458 if (!JITCode::useDataIC(JITType::BaselineJIT)) 459 addSlowCase(gen.slowPathJump()); 460 else 461 addSlowCase(); 462 m_putByVals.append(gen); 463 464 // IC can write new Structure without write-barrier if a base is cell. 465 // FIXME: Use UnconditionalWriteBarrier in Baseline effectively to reduce code size. 466 // https://bugs.webkit.org/show_bug.cgi?id=209395 467 emitWriteBarrier(base, ShouldFilterBase); 613 468 } 614 469 … … 663 518 VirtualRegister value; 664 519 ECMAMode ecmaMode = ECMAMode::strict(); 520 ArrayProfile* profile = nullptr; 665 521 666 522 auto load = [&](auto bytecode) { … … 669 525 value = bytecode.m_value; 670 526 ecmaMode = bytecode.m_ecmaMode; 527 auto& metadata = bytecode.metadata(m_codeBlock); 528 profile = &metadata.m_arrayProfile; 671 529 }; 672 530 … … 676 534 load(currentInstruction->as<OpPutByVal>()); 677 535 678 ByValInfo* byValInfo = m_byValCompilationInfo[m_byValInstructionIndex].byValInfo;536 JITPutByValGenerator& gen = m_putByVals[m_putByValIndex++]; 679 537 680 538 linkAllSlowCases(iter); 681 Label slowPath = label(); 539 540 Label coldPathBegin = label(); 682 541 683 542 #if !ENABLE(EXTRA_CTI_THUNKS) 684 emitGetVirtualRegister(base, regT0); 685 emitGetVirtualRegister(property, regT1); 686 emitGetVirtualRegister(value, regT2); 687 Call call = callOperation(isDirect ? operationDirectPutByValOptimize : operationPutByValOptimize, TrustedImmPtr(m_codeBlock->globalObject()), regT0, regT1, regT2, byValInfo, TrustedImm32(ecmaMode.value())); 543 // They are configured in the fast path and not clobbered. 544 Call call = callOperation(isDirect ? (ecmaMode.isStrict() ? operationDirectPutByValStrictOptimize : operationDirectPutByValNonStrictOptimize) : (ecmaMode.isStrict() ? operationPutByValStrictOptimize : operationPutByValNonStrictOptimize), TrustedImmPtr(m_codeBlock->globalObject()), regT0, regT1, regT2, gen.stubInfo(), regT3); 688 545 #else 689 546 VM& vm = this->vm(); … … 691 548 ASSERT(BytecodeIndex(bytecodeOffset) == m_bytecodeIndex); 692 549 693 constexpr GPRReg bytecodeOffsetGPR = argumentGPR0; 550 // They are configured in the fast path and not clobbered. 551 // constexpr GPRReg baseGPR = regT0; 552 // constexpr GPRReg propertyGPR = regT1; 553 // constexpr GPRReg valueGPR = regT2; 554 // constexpr GPRReg profileGPR = regT3; 555 constexpr GPRReg stubInfoGPR = regT4; 556 constexpr GPRReg bytecodeOffsetGPR = regT5; 694 557 move(TrustedImm32(bytecodeOffset), bytecodeOffsetGPR); 695 696 constexpr GPRReg baseGPR = argumentGPR1; 697 constexpr GPRReg propertyGPR = argumentGPR2; 698 constexpr GPRReg valuePR = argumentGPR3; 699 constexpr GPRReg byValInfoGPR = argumentGPR4; 700 constexpr GPRReg ecmaModeGPR = argumentGPR5; 701 702 emitGetVirtualRegister(base, baseGPR); 703 emitGetVirtualRegister(property, propertyGPR); 704 emitGetVirtualRegister(value, valuePR); 705 move(TrustedImmPtr(byValInfo), byValInfoGPR); 706 move(TrustedImm32(ecmaMode.value()), ecmaModeGPR); 558 move(TrustedImmPtr(gen.stubInfo()), stubInfoGPR); 707 559 emitNakedNearCall(vm.getCTIStub(slow_op_put_by_val_prepareCallGenerator).retaggedCode<NoPtrTag>()); 708 709 560 Call call; 561 auto operation = isDirect ? (ecmaMode.isStrict() ? operationDirectPutByValStrictOptimize : operationDirectPutByValNonStrictOptimize) : (ecmaMode.isStrict() ? operationPutByValStrictOptimize : operationPutByValNonStrictOptimize); 710 562 if (JITCode::useDataIC(JITType::BaselineJIT)) 711 byValInfo->m_slowOperation = isDirect ? operationDirectPutByValOptimize : operationPutByValOptimize;712 else 713 call = appendCall( isDirect ? operationDirectPutByValOptimize : operationPutByValOptimize);563 gen.stubInfo()->m_slowOperation = operation; 564 else 565 call = appendCall(operation); 714 566 emitNakedNearCall(vm.getCTIStub(checkExceptionGenerator).retaggedCode<NoPtrTag>()); 715 567 #endif // ENABLE(EXTRA_CTI_THUNKS) 716 568 717 m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath; 718 m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call; 719 m_byValInstructionIndex++; 569 gen.reportSlowPathCall(coldPathBegin, call); 720 570 } 721 571 … … 732 582 jit.tagReturnAddress(); 733 583 734 constexpr GPRReg bytecodeOffsetGPR = argumentGPR0; 584 constexpr GPRReg globalObjectGPR = regT5; 585 constexpr GPRReg baseGPR = regT0; 586 constexpr GPRReg propertyGPR = regT1; 587 constexpr GPRReg valueGPR = regT2; 588 constexpr GPRReg stubInfoGPR = regT4; 589 constexpr GPRReg profileGPR = regT3; 590 constexpr GPRReg bytecodeOffsetGPR = regT5; 591 735 592 jit.store32(bytecodeOffsetGPR, tagFor(CallFrameSlot::argumentCountIncludingThis)); 736 737 constexpr GPRReg globalObjectGPR = argumentGPR0;738 constexpr GPRReg baseGPR = argumentGPR1;739 constexpr GPRReg propertyGPR = argumentGPR2;740 constexpr GPRReg valuePR = argumentGPR3;741 constexpr GPRReg byValInfoGPR = argumentGPR4;742 constexpr GPRReg ecmaModeGPR = argumentGPR5;743 744 593 jit.loadPtr(addressFor(CallFrameSlot::codeBlock), globalObjectGPR); 745 594 jit.loadPtr(Address(globalObjectGPR, CodeBlock::offsetOfGlobalObject()), globalObjectGPR); 746 595 747 jit.setupArguments<decltype(operationPutByVal Optimize)>(globalObjectGPR, baseGPR, propertyGPR, valuePR, byValInfoGPR, ecmaModeGPR);596 jit.setupArguments<decltype(operationPutByValStrictOptimize)>(globalObjectGPR, baseGPR, propertyGPR, valueGPR, stubInfoGPR, profileGPR); 748 597 jit.prepareCallOperation(vm); 749 598 750 599 if (JITCode::useDataIC(JITType::BaselineJIT)) 751 jit.farJump(Address(argumentGPR4, ByValInfo::offsetOfSlowOperation()), OperationPtrTag);600 jit.farJump(Address(argumentGPR4, StructureStubInfo::offsetOfSlowOperation()), OperationPtrTag); 752 601 else 753 602 jit.ret(); … … 811 660 constexpr GPRReg baseGPR = argumentGPR1; 812 661 constexpr GPRReg propertyGPR = argumentGPR2; 813 constexpr GPRReg value PR = argumentGPR3;662 constexpr GPRReg valueGPR = argumentGPR3; 814 663 constexpr GPRReg byValInfoGPR = argumentGPR4; 815 664 constexpr GPRReg putKindGPR = argumentGPR5; … … 817 666 emitGetVirtualRegister(bytecode.m_base, baseGPR); 818 667 emitGetVirtualRegister(bytecode.m_property, propertyGPR); 819 emitGetVirtualRegister(bytecode.m_value, value PR);668 emitGetVirtualRegister(bytecode.m_value, valueGPR); 820 669 move(TrustedImmPtr(byValInfo), byValInfoGPR); 821 670 move(TrustedImm32(putKind.value()), putKindGPR); … … 853 702 constexpr GPRReg baseGPR = argumentGPR1; 854 703 constexpr GPRReg propertyGPR = argumentGPR2; 855 constexpr GPRReg value PR = argumentGPR3;704 constexpr GPRReg valueGPR = argumentGPR3; 856 705 constexpr GPRReg byValInfoGPR = argumentGPR4; 857 706 constexpr GPRReg putKindGPR = argumentGPR5; … … 860 709 jit.loadPtr(Address(globalObjectGPR, CodeBlock::offsetOfGlobalObject()), globalObjectGPR); 861 710 862 jit.setupArguments<decltype(operationPutPrivateNameOptimize)>(globalObjectGPR, baseGPR, propertyGPR, value PR, byValInfoGPR, putKindGPR);711 jit.setupArguments<decltype(operationPutPrivateNameOptimize)>(globalObjectGPR, baseGPR, propertyGPR, valueGPR, byValInfoGPR, putKindGPR); 863 712 jit.prepareCallOperation(vm); 864 713 … … 3292 3141 } 3293 3142 3294 template<typename Op>3295 void JIT::privateCompilePutByVal(const ConcurrentJSLocker&, ByValInfo* byValInfo, ReturnAddressPtr returnAddress, JITArrayMode arrayMode)3296 {3297 const Instruction* currentInstruction = m_codeBlock->instructions().at(byValInfo->bytecodeIndex).ptr();3298 auto bytecode = currentInstruction->as<Op>();3299 3300 PatchableJump badType;3301 JumpList slowCases;3302 3303 bool needsLinkForWriteBarrier = false;3304 3305 switch (arrayMode) {3306 case JITInt32:3307 slowCases = emitInt32PutByVal(bytecode, badType, nullptr);3308 break;3309 case JITDouble:3310 slowCases = emitDoublePutByVal(bytecode, badType, nullptr);3311 break;3312 case JITContiguous:3313 slowCases = emitContiguousPutByVal(bytecode, badType, nullptr);3314 needsLinkForWriteBarrier = true;3315 break;3316 case JITArrayStorage:3317 slowCases = emitArrayStoragePutByVal(bytecode, badType, nullptr);3318 needsLinkForWriteBarrier = true;3319 break;3320 default:3321 TypedArrayType type = typedArrayTypeForJITArrayMode(arrayMode);3322 if (isInt(type))3323 slowCases = emitIntTypedArrayPutByVal(bytecode, badType, nullptr, type);3324 else {3325 // FIXME: Optimize BigInt64Array / BigUint64Array in IC3326 // Currently, BigInt64Array / BigUint64Array never comes here.3327 // https://bugs.webkit.org/show_bug.cgi?id=2211833328 ASSERT(isFloat(type));3329 slowCases = emitFloatTypedArrayPutByVal(bytecode, badType, nullptr, type);3330 }3331 break;3332 }3333 3334 Jump done = jump();3335 3336 LinkBuffer patchBuffer(*this, m_codeBlock, LinkBuffer::Profile::InlineCache);3337 patchBuffer.link(badType, byValInfo->slowPathTarget);3338 patchBuffer.link(slowCases, byValInfo->slowPathTarget);3339 patchBuffer.link(done, byValInfo->doneTarget);3340 if (needsLinkForWriteBarrier) {3341 ASSERT(removeCodePtrTag(m_farCalls.last().callee.executableAddress()) == removeCodePtrTag(operationWriteBarrierSlowPath));3342 patchBuffer.link(m_farCalls.last().from, m_farCalls.last().callee);3343 }3344 3345 bool isDirect = currentInstruction->opcodeID() == op_put_by_val_direct;3346 if (!isDirect) {3347 byValInfo->stubRoutine = FINALIZE_CODE_FOR_STUB(3348 m_codeBlock, patchBuffer, JITStubRoutinePtrTag,3349 "Baseline put_by_val stub for %s, return point %p", toCString(*m_codeBlock).data(), returnAddress.untaggedValue());3350 3351 } else {3352 byValInfo->stubRoutine = FINALIZE_CODE_FOR_STUB(3353 m_codeBlock, patchBuffer, JITStubRoutinePtrTag,3354 "Baseline put_by_val_direct stub for %s, return point %p", toCString(*m_codeBlock).data(), returnAddress.untaggedValue());3355 }3356 3357 if (JITCode::useDataIC(JITType::BaselineJIT)) {3358 byValInfo->m_badTypeJumpTarget = CodeLocationLabel<JITStubRoutinePtrTag>(byValInfo->stubRoutine->code().code());3359 byValInfo->m_slowOperation = isDirect ? operationDirectPutByValGeneric : operationPutByValGeneric;3360 } else {3361 MacroAssembler::repatchJump(byValInfo->m_badTypeJump, CodeLocationLabel<JITStubRoutinePtrTag>(byValInfo->stubRoutine->code().code()));3362 MacroAssembler::repatchCall(CodeLocationCall<ReturnAddressPtrTag>(MacroAssemblerCodePtr<ReturnAddressPtrTag>(returnAddress)), FunctionPtr<OperationPtrTag>(isDirect ? operationDirectPutByValGeneric : operationPutByValGeneric));3363 }3364 }3365 // This function is only consumed from another translation unit (JITOperations.cpp),3366 // so we list off the two expected specializations in advance.3367 template void JIT::privateCompilePutByVal<OpPutByVal>(const ConcurrentJSLocker&, ByValInfo*, ReturnAddressPtr, JITArrayMode);3368 template void JIT::privateCompilePutByVal<OpPutByValDirect>(const ConcurrentJSLocker&, ByValInfo*, ReturnAddressPtr, JITArrayMode);3369 3370 3143 void JIT::privateCompilePutPrivateNameWithCachedId(ByValInfo* byValInfo, ReturnAddressPtr returnAddress, CacheableIdentifier propertyName) 3371 3144 { … … 3409 3182 } 3410 3183 3411 template<typename Op>3412 void JIT::privateCompilePutByValWithCachedId(ByValInfo* byValInfo, ReturnAddressPtr returnAddress, PutKind putKind, CacheableIdentifier propertyName)3413 {3414 ASSERT((putKind == PutKind::Direct && Op::opcodeID == op_put_by_val_direct) || (putKind == PutKind::NotDirect && Op::opcodeID == op_put_by_val));3415 const Instruction* currentInstruction = m_codeBlock->instructions().at(byValInfo->bytecodeIndex).ptr();3416 auto bytecode = currentInstruction->as<Op>();3417 3418 JumpList doneCases;3419 JumpList slowCases;3420 3421 JITPutByIdGenerator gen = emitPutByValWithCachedId(bytecode, putKind, propertyName, doneCases, slowCases);3422 3423 ConcurrentJSLocker locker(m_codeBlock->m_lock);3424 LinkBuffer patchBuffer(*this, m_codeBlock, LinkBuffer::Profile::InlineCache);3425 patchBuffer.link(slowCases, byValInfo->slowPathTarget);3426 patchBuffer.link(doneCases, byValInfo->doneTarget);3427 if (!m_exceptionChecks.empty())3428 patchBuffer.link(m_exceptionChecks, byValInfo->exceptionHandler);3429 3430 for (const auto& callSite : m_nearCalls) {3431 if (callSite.callee)3432 patchBuffer.link(callSite.from, callSite.callee);3433 }3434 for (const auto& callSite : m_farCalls) {3435 if (callSite.callee)3436 patchBuffer.link(callSite.from, callSite.callee);3437 }3438 gen.finalize(patchBuffer, patchBuffer);3439 3440 byValInfo->stubRoutine = FINALIZE_CODE_FOR_STUB(3441 m_codeBlock, patchBuffer, JITStubRoutinePtrTag,3442 "Baseline put_by_val%s with cached property name '%s' stub for %s, return point %p", (putKind == PutKind::Direct) ? "_direct" : "", propertyName.uid()->utf8().data(), toCString(*m_codeBlock).data(), returnAddress.untaggedValue());3443 byValInfo->stubInfo = gen.stubInfo();3444 3445 if (JITCode::useDataIC(JITType::BaselineJIT)) {3446 byValInfo->m_notIndexJumpTarget = CodeLocationLabel<JITStubRoutinePtrTag>(byValInfo->stubRoutine->code().code());3447 byValInfo->m_slowOperation = putKind == PutKind::Direct ? operationDirectPutByValGeneric : operationPutByValGeneric;3448 } else {3449 MacroAssembler::repatchJump(byValInfo->m_notIndexJump, CodeLocationLabel<JITStubRoutinePtrTag>(byValInfo->stubRoutine->code().code()));3450 MacroAssembler::repatchCall(CodeLocationCall<ReturnAddressPtrTag>(MacroAssemblerCodePtr<ReturnAddressPtrTag>(returnAddress)), FunctionPtr<OperationPtrTag>(putKind == PutKind::Direct ? operationDirectPutByValGeneric : operationPutByValGeneric));3451 }3452 }3453 // This function is only consumed from another translation unit (JITOperations.cpp),3454 // so we list off the two expected specializations in advance.3455 template void JIT::privateCompilePutByValWithCachedId<OpPutByVal>(ByValInfo*, ReturnAddressPtr, PutKind, CacheableIdentifier);3456 template void JIT::privateCompilePutByValWithCachedId<OpPutByValDirect>(ByValInfo*, ReturnAddressPtr, PutKind, CacheableIdentifier);3457 3458 template<typename Op>3459 JIT::JumpList JIT::emitIntTypedArrayPutByVal(Op bytecode, PatchableJump& badType, ByValInfo* byValInfo, TypedArrayType type)3460 {3461 auto& metadata = bytecode.metadata(m_codeBlock);3462 ArrayProfile* profile = &metadata.m_arrayProfile;3463 ASSERT(isInt(type));3464 3465 VirtualRegister value = bytecode.m_value;3466 3467 #if USE(JSVALUE64)3468 RegisterID base = regT0;3469 RegisterID property = regT1;3470 RegisterID earlyScratch = regT3;3471 RegisterID lateScratch = regT2;3472 RegisterID lateScratch2 = regT4;3473 #else3474 RegisterID base = regT0;3475 RegisterID property = regT2;3476 RegisterID earlyScratch = regT3;3477 RegisterID lateScratch = regT1;3478 RegisterID lateScratch2 = regT4;3479 #endif3480 3481 JumpList slowCases;3482 3483 load8(Address(base, JSCell::typeInfoTypeOffset()), earlyScratch);3484 3485 if (JITCode::useDataIC(JITType::BaselineJIT)) {3486 if (byValInfo) {3487 auto isCorrectType = branch32(Equal, earlyScratch, TrustedImm32(typeForTypedArrayType(type)));3488 farJump(AbsoluteAddress(&byValInfo->m_badTypeJumpTarget), JITStubRoutinePtrTag);3489 isCorrectType.link(this);3490 } else3491 badType = patchableBranch32(NotEqual, earlyScratch, TrustedImm32(typeForTypedArrayType(type)));3492 } else3493 badType = patchableBranch32(NotEqual, earlyScratch, TrustedImm32(typeForTypedArrayType(type)));3494 3495 load32(Address(base, JSArrayBufferView::offsetOfLength()), lateScratch2);3496 Jump inBounds = branch32(Below, property, lateScratch2);3497 emitArrayProfileOutOfBoundsSpecialCase(profile);3498 slowCases.append(jump());3499 inBounds.link(this);3500 3501 #if USE(JSVALUE64)3502 emitGetVirtualRegister(value, earlyScratch);3503 slowCases.append(branchIfNotInt32(earlyScratch));3504 #else3505 emitLoad(value, lateScratch, earlyScratch);3506 slowCases.append(branchIfNotInt32(lateScratch));3507 #endif3508 3509 // We would be loading this into base as in get_by_val, except that the slow3510 // path expects the base to be unclobbered.3511 loadPtr(Address(base, JSArrayBufferView::offsetOfVector()), lateScratch);3512 cageConditionallyAndUntag(Gigacage::Primitive, lateScratch, lateScratch2, lateScratch2, false);3513 3514 if (isClamped(type)) {3515 ASSERT(elementSize(type) == 1);3516 ASSERT(!JSC::isSigned(type));3517 Jump inBounds = branch32(BelowOrEqual, earlyScratch, TrustedImm32(0xff));3518 Jump tooBig = branch32(GreaterThan, earlyScratch, TrustedImm32(0xff));3519 xor32(earlyScratch, earlyScratch);3520 Jump clamped = jump();3521 tooBig.link(this);3522 move(TrustedImm32(0xff), earlyScratch);3523 clamped.link(this);3524 inBounds.link(this);3525 }3526 3527 switch (elementSize(type)) {3528 case 1:3529 store8(earlyScratch, BaseIndex(lateScratch, property, TimesOne));3530 break;3531 case 2:3532 store16(earlyScratch, BaseIndex(lateScratch, property, TimesTwo));3533 break;3534 case 4:3535 store32(earlyScratch, BaseIndex(lateScratch, property, TimesFour));3536 break;3537 default:3538 CRASH();3539 }3540 3541 return slowCases;3542 }3543 3544 template<typename Op>3545 JIT::JumpList JIT::emitFloatTypedArrayPutByVal(Op bytecode, PatchableJump& badType, ByValInfo* byValInfo, TypedArrayType type)3546 {3547 auto& metadata = bytecode.metadata(m_codeBlock);3548 ArrayProfile* profile = &metadata.m_arrayProfile;3549 ASSERT(isFloat(type));3550 3551 VirtualRegister value = bytecode.m_value;3552 3553 #if USE(JSVALUE64)3554 RegisterID base = regT0;3555 RegisterID property = regT1;3556 RegisterID earlyScratch = regT3;3557 RegisterID lateScratch = regT2;3558 RegisterID lateScratch2 = regT4;3559 #else3560 RegisterID base = regT0;3561 RegisterID property = regT2;3562 RegisterID earlyScratch = regT3;3563 RegisterID lateScratch = regT1;3564 RegisterID lateScratch2 = regT4;3565 #endif3566 3567 JumpList slowCases;3568 3569 load8(Address(base, JSCell::typeInfoTypeOffset()), earlyScratch);3570 3571 if (JITCode::useDataIC(JITType::BaselineJIT)) {3572 if (byValInfo) {3573 auto isCorrectType = branch32(Equal, earlyScratch, TrustedImm32(typeForTypedArrayType(type)));3574 farJump(AbsoluteAddress(&byValInfo->m_badTypeJumpTarget), JITStubRoutinePtrTag);3575 isCorrectType.link(this);3576 } else3577 badType = patchableBranch32(NotEqual, earlyScratch, TrustedImm32(typeForTypedArrayType(type)));3578 } else3579 badType = patchableBranch32(NotEqual, earlyScratch, TrustedImm32(typeForTypedArrayType(type)));3580 3581 load32(Address(base, JSArrayBufferView::offsetOfLength()), lateScratch2);3582 Jump inBounds = branch32(Below, property, lateScratch2);3583 emitArrayProfileOutOfBoundsSpecialCase(profile);3584 slowCases.append(jump());3585 inBounds.link(this);3586 3587 #if USE(JSVALUE64)3588 emitGetVirtualRegister(value, earlyScratch);3589 Jump doubleCase = branchIfNotInt32(earlyScratch);3590 convertInt32ToDouble(earlyScratch, fpRegT0);3591 Jump ready = jump();3592 doubleCase.link(this);3593 slowCases.append(branchIfNotNumber(earlyScratch));3594 add64(numberTagRegister, earlyScratch);3595 move64ToDouble(earlyScratch, fpRegT0);3596 ready.link(this);3597 #else3598 emitLoad(value, lateScratch, earlyScratch);3599 Jump doubleCase = branchIfNotInt32(lateScratch);3600 convertInt32ToDouble(earlyScratch, fpRegT0);3601 Jump ready = jump();3602 doubleCase.link(this);3603 slowCases.append(branch32(Above, lateScratch, TrustedImm32(JSValue::LowestTag)));3604 moveIntsToDouble(earlyScratch, lateScratch, fpRegT0);3605 ready.link(this);3606 #endif3607 3608 // We would be loading this into base as in get_by_val, except that the slow3609 // path expects the base to be unclobbered.3610 loadPtr(Address(base, JSArrayBufferView::offsetOfVector()), lateScratch);3611 cageConditionallyAndUntag(Gigacage::Primitive, lateScratch, lateScratch2, lateScratch2, false);3612 3613 switch (elementSize(type)) {3614 case 4:3615 convertDoubleToFloat(fpRegT0, fpRegT0);3616 storeFloat(fpRegT0, BaseIndex(lateScratch, property, TimesFour));3617 break;3618 case 8:3619 storeDouble(fpRegT0, BaseIndex(lateScratch, property, TimesEight));3620 break;3621 default:3622 CRASH();3623 }3624 3625 return slowCases;3626 }3627 3628 3184 } // namespace JSC 3629 3185 -
trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
r281454 r281615 467 467 VirtualRegister base = bytecode.m_base; 468 468 VirtualRegister property = bytecode.m_property; 469 ArrayProfile* profile = &metadata.m_arrayProfile;470 ByValInfo* byValInfo = m_codeBlock->addByValInfo(m_bytecodeIndex);471 472 emitLoad2(base, regT1, regT0, property, regT3, regT2);473 474 emitJumpSlowCaseIfNotJSCell(base, regT1);475 PatchableJump notIndex = patchableBranch32(NotEqual, regT3, TrustedImm32(JSValue::Int32Tag));476 addSlowCase(notIndex);477 emitArrayProfilingSiteWithCell(regT0, profile, regT1);478 479 PatchableJump badType;480 JumpList slowCases;481 482 // FIXME: Maybe we should do this inline?483 load8(Address(regT0, JSCell::indexingTypeAndMiscOffset()), regT1);484 addSlowCase(branchTest32(NonZero, regT1, TrustedImm32(CopyOnWrite)));485 and32(TrustedImm32(IndexingShapeMask), regT1);486 487 JITArrayMode mode = chooseArrayMode(profile);488 switch (mode) {489 case JITInt32:490 slowCases = emitInt32PutByVal(bytecode, badType, byValInfo);491 break;492 case JITDouble:493 slowCases = emitDoublePutByVal(bytecode, badType, byValInfo);494 break;495 case JITContiguous:496 slowCases = emitContiguousPutByVal(bytecode, badType, byValInfo);497 break;498 case JITArrayStorage:499 slowCases = emitArrayStoragePutByVal(bytecode, badType, byValInfo);500 break;501 default:502 CRASH();503 break;504 }505 506 addSlowCase(badType);507 addSlowCase(slowCases);508 509 Label done = label();510 511 m_byValCompilationInfo.append(ByValCompilationInfo(byValInfo, m_bytecodeIndex, notIndex, badType, mode, profile, done, done));512 }513 514 template <typename Op>515 JIT::JumpList JIT::emitGenericContiguousPutByVal(Op bytecode, PatchableJump& badType, ByValInfo* byValInfo, IndexingType indexingShape)516 {517 auto& metadata = bytecode.metadata(m_codeBlock);518 VirtualRegister base = bytecode.m_base;519 469 VirtualRegister value = bytecode.m_value; 520 470 ArrayProfile* profile = &metadata.m_arrayProfile; 521 471 522 JumpList slowCases; 523 524 UNUSED_PARAM(byValInfo); 525 badType = patchableBranch32(NotEqual, regT1, TrustedImm32(ContiguousShape)); 526 527 loadPtr(Address(regT0, JSObject::butterflyOffset()), regT3); 528 Jump outOfBounds = branch32(AboveOrEqual, regT2, Address(regT3, Butterfly::offsetOfPublicLength())); 529 530 Label storeResult = label(); 531 emitLoad(value, regT1, regT0); 532 switch (indexingShape) { 533 case Int32Shape: 534 slowCases.append(branchIfNotInt32(regT1)); 535 store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload))); 536 store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag))); 537 break; 538 case ContiguousShape: 539 store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload))); 540 store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag))); 541 emitLoad(base, regT2, regT3); 542 emitWriteBarrier(base, value, ShouldFilterValue); 543 break; 544 case DoubleShape: { 545 Jump notInt = branchIfNotInt32(regT1); 546 convertInt32ToDouble(regT0, fpRegT0); 547 Jump ready = jump(); 548 notInt.link(this); 549 moveIntsToDouble(regT0, regT1, fpRegT0); 550 slowCases.append(branchIfNaN(fpRegT0)); 551 ready.link(this); 552 storeDouble(fpRegT0, BaseIndex(regT3, regT2, TimesEight)); 553 break; 554 } 555 default: 556 CRASH(); 557 break; 558 } 559 560 Jump done = jump(); 561 562 outOfBounds.link(this); 563 slowCases.append(branch32(AboveOrEqual, regT2, Address(regT3, Butterfly::offsetOfVectorLength()))); 564 565 emitArrayProfileStoreToHoleSpecialCase(profile); 566 567 add32(TrustedImm32(1), regT2, regT1); 568 store32(regT1, Address(regT3, Butterfly::offsetOfPublicLength())); 569 jump().linkTo(storeResult, this); 570 571 done.link(this); 572 573 return slowCases; 574 } 575 576 template <typename Op> 577 JIT::JumpList JIT::emitArrayStoragePutByVal(Op bytecode, PatchableJump& badType, ByValInfo* byValInfo) 578 { 579 auto& metadata = bytecode.metadata(m_codeBlock); 580 VirtualRegister base = bytecode.m_base; 581 VirtualRegister value = bytecode.m_value; 582 ArrayProfile* profile = &metadata.m_arrayProfile; 583 584 JumpList slowCases; 585 586 UNUSED_PARAM(byValInfo); 587 badType = patchableBranch32(NotEqual, regT1, TrustedImm32(ArrayStorageShape)); 588 589 loadPtr(Address(regT0, JSObject::butterflyOffset()), regT3); 590 slowCases.append(branch32(AboveOrEqual, regT2, Address(regT3, ArrayStorage::vectorLengthOffset()))); 591 592 Jump empty = branch32(Equal, BaseIndex(regT3, regT2, TimesEight, ArrayStorage::vectorOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag)); 593 594 Label storeResult(this); 595 emitLoad(value, regT1, regT0); 596 store32(regT0, BaseIndex(regT3, regT2, TimesEight, ArrayStorage::vectorOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); // payload 597 store32(regT1, BaseIndex(regT3, regT2, TimesEight, ArrayStorage::vectorOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); // tag 598 Jump end = jump(); 599 600 empty.link(this); 601 emitArrayProfileStoreToHoleSpecialCase(profile); 602 add32(TrustedImm32(1), Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector))); 603 branch32(Below, regT2, Address(regT3, ArrayStorage::lengthOffset())).linkTo(storeResult, this); 604 605 add32(TrustedImm32(1), regT2, regT0); 606 store32(regT0, Address(regT3, ArrayStorage::lengthOffset())); 607 jump().linkTo(storeResult, this); 608 609 end.link(this); 610 611 emitWriteBarrier(base, value, ShouldFilterValue); 612 613 return slowCases; 472 emitLoad2(base, regT1, regT0, property, regT3, regT2); 473 emitLoad(value, regT5, regT4); 474 move(TrustedImmPtr(profile), regT6); 475 emitJumpSlowCaseIfNotJSCell(base, regT1); 476 emitArrayProfilingSiteWithCell(regT0, regT6, regT7); 477 478 JITPutByValGenerator gen( 479 m_codeBlock, JITType::BaselineJIT, CodeOrigin(m_bytecodeIndex), CallSiteIndex(m_bytecodeIndex), AccessType::PutByVal, RegisterSet::stubUnavailableRegisters(), 480 JSValueRegs(regT1, regT0), JSValueRegs(regT3, regT2), JSValueRegs(regT5, regT4), regT6, InvalidGPRReg); 481 gen.generateFastPath(*this); 482 addSlowCase(gen.slowPathJump()); 483 m_putByVals.append(gen); 484 485 // IC can write new Structure without write-barrier if a base is cell. 486 // FIXME: Use UnconditionalWriteBarrier in Baseline effectively to reduce code size. 487 // https://bugs.webkit.org/show_bug.cgi?id=209395 488 emitWriteBarrier(base, ShouldFilterBase); 614 489 } 615 490 … … 621 496 VirtualRegister value; 622 497 ECMAMode ecmaMode = ECMAMode::strict(); 498 ArrayProfile* profile = nullptr; 623 499 624 500 auto load = [&](auto bytecode) { … … 627 503 value = bytecode.m_value; 628 504 ecmaMode = JIT::ecmaMode(bytecode); 505 auto& metadata = bytecode.metadata(m_codeBlock); 506 profile = &metadata.m_arrayProfile; 629 507 }; 630 508 … … 634 512 load(currentInstruction->as<OpPutByVal>()); 635 513 636 ByValInfo* byValInfo = m_byValCompilationInfo[m_byValInstructionIndex].byValInfo; 637 638 linkAllSlowCases(iter); 639 Label slowPath = label(); 640 514 JITPutByValGenerator& gen = m_putByVals[m_putByValIndex++]; 515 516 linkAllSlowCases(iter); 517 518 Label coldPathBegin = label(); 519 641 520 // The register selection below is chosen to reduce register swapping on ARM. 642 521 // Swapping shouldn't happen on other platforms. 643 emitLoad(base, regT2, regT1); 644 emitLoad(property, regT3, regT0); 522 emitLoad2(base, regT2, regT1, property, regT3, regT0); 645 523 emitLoad(value, regT5, regT4); 646 Call call = callOperation(isDirect ? operationDirectPutByValOptimize : operationPutByValOptimize, m_codeBlock->globalObject(), JSValueRegs(regT2, regT1), JSValueRegs(regT3, regT0), JSValueRegs(regT5, regT4), byValInfo, TrustedImm32(ecmaMode.value())); 647 648 m_byValCompilationInfo[m_byValInstructionIndex].slowPathTarget = slowPath; 649 m_byValCompilationInfo[m_byValInstructionIndex].returnAddress = call; 650 m_byValInstructionIndex++; 524 525 Call call = callOperation(isDirect ? (ecmaMode.isStrict() ? operationDirectPutByValStrictOptimize : operationDirectPutByValNonStrictOptimize) : (ecmaMode.isStrict() ? operationPutByValStrictOptimize : operationPutByValNonStrictOptimize), TrustedImmPtr(m_codeBlock->globalObject()), JSValueRegs(regT2, regT1), JSValueRegs(regT3, regT0), JSValueRegs(regT5, regT4), gen.stubInfo(), profile); 526 527 gen.reportSlowPathCall(coldPathBegin, call); 651 528 } 652 529 -
trunk/Source/JavaScriptCore/jit/Repatch.cpp
r279635 r281615 569 569 } 570 570 571 static auto appropriateGenericPutByIdFunction(const PutPropertySlot &slot, PutKind putKind) -> decltype(&operationPutByIdDirectStrict) 572 { 573 switch (putKind) { 574 case PutKind::NotDirect: 575 if (slot.isStrictMode()) 576 return operationPutByIdStrict; 577 return operationPutByIdNonStrict; 578 case PutKind::Direct: 579 if (slot.isStrictMode()) 580 return operationPutByIdDirectStrict; 581 return operationPutByIdDirectNonStrict; 582 case PutKind::DirectPrivateFieldDefine: 583 ASSERT(slot.isStrictMode()); 584 return operationPutByIdDefinePrivateFieldStrict; 585 case PutKind::DirectPrivateFieldSet: 586 ASSERT(slot.isStrictMode()); 587 return operationPutByIdSetPrivateFieldStrict; 571 static FunctionPtr<CFunctionPtrTag> appropriateGenericPutByFunction(const PutPropertySlot &slot, PutByKind putByKind, PutKind putKind) 572 { 573 switch (putByKind) { 574 case PutByKind::ById: { 575 switch (putKind) { 576 case PutKind::NotDirect: 577 if (slot.isStrictMode()) 578 return operationPutByIdStrict; 579 return operationPutByIdNonStrict; 580 case PutKind::Direct: 581 if (slot.isStrictMode()) 582 return operationPutByIdDirectStrict; 583 return operationPutByIdDirectNonStrict; 584 case PutKind::DirectPrivateFieldDefine: 585 ASSERT(slot.isStrictMode()); 586 return operationPutByIdDefinePrivateFieldStrict; 587 case PutKind::DirectPrivateFieldSet: 588 ASSERT(slot.isStrictMode()); 589 return operationPutByIdSetPrivateFieldStrict; 590 } 591 break; 592 } 593 case PutByKind::ByVal: { 594 switch (putKind) { 595 case PutKind::NotDirect: 596 if (slot.isStrictMode()) 597 return operationPutByValStrictGeneric; 598 return operationPutByValNonStrictGeneric; 599 case PutKind::Direct: 600 if (slot.isStrictMode()) 601 return operationDirectPutByValStrictGeneric; 602 return operationDirectPutByValNonStrictGeneric; 603 default: 604 RELEASE_ASSERT_NOT_REACHED(); 605 break; 606 } 607 break; 608 } 588 609 } 589 610 // Make win port compiler happy … … 592 613 } 593 614 594 static auto appropriateOptimizingPutByIdFunction(const PutPropertySlot &slot, PutKind putKind) -> decltype(&operationPutByIdDirectStrictOptimize) 595 { 596 switch (putKind) { 597 case PutKind::NotDirect: 598 if (slot.isStrictMode()) 599 return operationPutByIdStrictOptimize; 600 return operationPutByIdNonStrictOptimize; 601 case PutKind::Direct: 602 if (slot.isStrictMode()) 603 return operationPutByIdDirectStrictOptimize; 604 return operationPutByIdDirectNonStrictOptimize; 605 case PutKind::DirectPrivateFieldDefine: 606 ASSERT(slot.isStrictMode()); 607 return operationPutByIdDefinePrivateFieldStrictOptimize; 608 case PutKind::DirectPrivateFieldSet: 609 ASSERT(slot.isStrictMode()); 610 return operationPutByIdSetPrivateFieldStrictOptimize; 615 static FunctionPtr<CFunctionPtrTag> appropriateOptimizingPutByFunction(const PutPropertySlot &slot, PutByKind putByKind, PutKind putKind) 616 { 617 switch (putByKind) { 618 case PutByKind::ById: 619 switch (putKind) { 620 case PutKind::NotDirect: 621 if (slot.isStrictMode()) 622 return operationPutByIdStrictOptimize; 623 return operationPutByIdNonStrictOptimize; 624 case PutKind::Direct: 625 if (slot.isStrictMode()) 626 return operationPutByIdDirectStrictOptimize; 627 return operationPutByIdDirectNonStrictOptimize; 628 case PutKind::DirectPrivateFieldDefine: 629 ASSERT(slot.isStrictMode()); 630 return operationPutByIdDefinePrivateFieldStrictOptimize; 631 case PutKind::DirectPrivateFieldSet: 632 ASSERT(slot.isStrictMode()); 633 return operationPutByIdSetPrivateFieldStrictOptimize; 634 } 635 break; 636 case PutByKind::ByVal: { 637 switch (putKind) { 638 case PutKind::NotDirect: 639 if (slot.isStrictMode()) 640 return operationPutByValStrictOptimize; 641 return operationPutByValNonStrictOptimize; 642 case PutKind::Direct: 643 if (slot.isStrictMode()) 644 return operationDirectPutByValStrictOptimize; 645 return operationDirectPutByValNonStrictOptimize; 646 default: 647 RELEASE_ASSERT_NOT_REACHED(); 648 break; 649 } 650 break; 651 } 611 652 } 612 653 // Make win port compiler happy … … 615 656 } 616 657 617 static InlineCacheAction tryCachePutBy ID(JSGlobalObject* globalObject, CodeBlock* codeBlock, JSValue baseValue, Structure* oldStructure, CacheableIdentifier propertyName, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)658 static InlineCacheAction tryCachePutBy(JSGlobalObject* globalObject, CodeBlock* codeBlock, JSValue baseValue, Structure* oldStructure, CacheableIdentifier propertyName, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutByKind putByKind, PutKind putKind) 618 659 { 619 660 VM& vm = globalObject->vm(); … … 683 724 bool generatedCodeInline = InlineAccess::generateSelfPropertyReplace(stubInfo, oldStructure, slot.cachedOffset()); 684 725 if (generatedCodeInline) { 685 LOG_IC((ICEvent::PutBy IdSelfPatch, oldStructure->classInfo(), ident, slot.base() == baseValue));686 repatchSlowPathCall(codeBlock, stubInfo, appropriateOptimizingPutBy IdFunction(slot, putKind));726 LOG_IC((ICEvent::PutBySelfPatch, oldStructure->classInfo(), ident, slot.base() == baseValue)); 727 repatchSlowPathCall(codeBlock, stubInfo, appropriateOptimizingPutByFunction(slot, putByKind, putKind)); 687 728 stubInfo.initPutByIdReplace(locker, codeBlock, oldStructure, slot.cachedOffset(), propertyName); 688 729 return RetryCacheLater; … … 818 859 } 819 860 820 LOG_IC((ICEvent::PutBy IdAddAccessCase, oldStructure->classInfo(), ident, slot.base() == baseValue));861 LOG_IC((ICEvent::PutByAddAccessCase, oldStructure->classInfo(), ident, slot.base() == baseValue)); 821 862 822 863 result = stubInfo.addAccessCase(locker, globalObject, codeBlock, slot.isStrictMode() ? ECMAMode::strict() : ECMAMode::sloppy(), propertyName, WTFMove(newCase)); 823 864 824 865 if (result.generatedSomeCode()) { 825 LOG_IC((ICEvent::PutBy IdReplaceWithJump, oldStructure->classInfo(), ident, slot.base() == baseValue));866 LOG_IC((ICEvent::PutByReplaceWithJump, oldStructure->classInfo(), ident, slot.base() == baseValue)); 826 867 827 868 RELEASE_ASSERT(result.code()); … … 836 877 } 837 878 838 void repatchPutBy ID(JSGlobalObject* globalObject, CodeBlock* codeBlock, JSValue baseValue, Structure* oldStructure, CacheableIdentifier propertyName, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)879 void repatchPutBy(JSGlobalObject* globalObject, CodeBlock* codeBlock, JSValue baseValue, Structure* oldStructure, CacheableIdentifier propertyName, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutByKind putByKind, PutKind putKind) 839 880 { 840 881 SuperSamplerScope superSamplerScope(false); 841 882 842 if (tryCachePutByID(globalObject, codeBlock, baseValue, oldStructure, propertyName, slot, stubInfo, putKind) == GiveUpOnCache) 843 repatchSlowPathCall(codeBlock, stubInfo, appropriateGenericPutByIdFunction(slot, putKind)); 883 if (tryCachePutBy(globalObject, codeBlock, baseValue, oldStructure, propertyName, slot, stubInfo, putByKind, putKind) == GiveUpOnCache) 884 repatchSlowPathCall(codeBlock, stubInfo, appropriateGenericPutByFunction(slot, putByKind, putKind)); 885 } 886 887 static InlineCacheAction tryCacheArrayPutByVal(JSGlobalObject* globalObject, CodeBlock* codeBlock, JSValue baseValue, JSValue index, StructureStubInfo& stubInfo, PutKind) 888 { 889 if (!baseValue.isCell()) 890 return GiveUpOnCache; 891 892 if (!index.isInt32()) 893 return RetryCacheLater; 894 895 VM& vm = globalObject->vm(); 896 AccessGenerationResult result; 897 898 { 899 JSCell* base = baseValue.asCell(); 900 901 AccessCase::AccessType accessType; 902 if (isTypedView(base->classInfo(vm)->typedArrayStorageType)) { 903 switch (base->classInfo(vm)->typedArrayStorageType) { 904 case TypeInt8: 905 accessType = AccessCase::IndexedTypedArrayInt8Store; 906 break; 907 case TypeUint8: 908 accessType = AccessCase::IndexedTypedArrayUint8Store; 909 break; 910 case TypeUint8Clamped: 911 accessType = AccessCase::IndexedTypedArrayUint8ClampedStore; 912 break; 913 case TypeInt16: 914 accessType = AccessCase::IndexedTypedArrayInt16Store; 915 break; 916 case TypeUint16: 917 accessType = AccessCase::IndexedTypedArrayUint16Store; 918 break; 919 case TypeInt32: 920 accessType = AccessCase::IndexedTypedArrayInt32Store; 921 break; 922 case TypeUint32: 923 accessType = AccessCase::IndexedTypedArrayUint32Store; 924 break; 925 case TypeFloat32: 926 accessType = AccessCase::IndexedTypedArrayFloat32Store; 927 break; 928 case TypeFloat64: 929 accessType = AccessCase::IndexedTypedArrayFloat64Store; 930 break; 931 // FIXME: Optimize BigInt64Array / BigUint64Array in IC 932 // https://bugs.webkit.org/show_bug.cgi?id=221183 933 case TypeBigInt64: 934 case TypeBigUint64: 935 return GiveUpOnCache; 936 default: 937 RELEASE_ASSERT_NOT_REACHED(); 938 } 939 } else { 940 IndexingType indexingShape = base->indexingType() & IndexingShapeMask; 941 switch (indexingShape) { 942 case Int32Shape: 943 accessType = AccessCase::IndexedInt32Store; 944 break; 945 case DoubleShape: 946 accessType = AccessCase::IndexedDoubleStore; 947 break; 948 case ContiguousShape: 949 accessType = AccessCase::IndexedContiguousStore; 950 break; 951 case ArrayStorageShape: 952 accessType = AccessCase::IndexedArrayStorageStore; 953 break; 954 default: 955 return GiveUpOnCache; 956 } 957 } 958 959 GCSafeConcurrentJSLocker locker(codeBlock->m_lock, globalObject->vm().heap); 960 result = stubInfo.addAccessCase(locker, globalObject, codeBlock, ECMAMode::strict(), nullptr, AccessCase::create(vm, codeBlock, accessType, nullptr)); 961 962 if (result.generatedSomeCode()) { 963 LOG_IC((ICEvent::PutByReplaceWithJump, baseValue.classInfoOrNull(vm), Identifier())); 964 965 RELEASE_ASSERT(result.code()); 966 InlineAccess::rewireStubAsJumpInAccessNotUsingInlineAccess(codeBlock, stubInfo, CodeLocationLabel<JITStubRoutinePtrTag>(result.code())); 967 } 968 } 969 970 fireWatchpointsAndClearStubIfNeeded(vm, stubInfo, codeBlock, result); 971 return result.shouldGiveUpNow() ? GiveUpOnCache : RetryCacheLater; 972 } 973 974 void repatchArrayPutByVal(JSGlobalObject* globalObject, CodeBlock* codeBlock, JSValue base, JSValue index, StructureStubInfo& stubInfo, PutKind putKind, ECMAMode ecmaMode) 975 { 976 if (tryCacheArrayPutByVal(globalObject, codeBlock, base, index, stubInfo, putKind) == GiveUpOnCache) 977 repatchSlowPathCall(codeBlock, stubInfo, putKind == PutKind::Direct ? (ecmaMode.isStrict() ? operationDirectPutByValStrictGeneric : operationDirectPutByValNonStrictGeneric) : (ecmaMode.isStrict() ? operationPutByValStrictGeneric : operationPutByValNonStrictGeneric)); 844 978 } 845 979 … … 987 1121 bool generatedCodeInline = InlineAccess::generateSelfInAccess(stubInfo, structure); 988 1122 if (generatedCodeInline) { 989 LOG_IC((ICEvent::InBy IdSelfPatch, structure->classInfo(), ident, slot.slotBase() == base));1123 LOG_IC((ICEvent::InBySelfPatch, structure->classInfo(), ident, slot.slotBase() == base)); 990 1124 structure->startWatchingPropertyForReplacements(vm, slot.cachedOffset()); 991 1125 repatchSlowPathCall(codeBlock, stubInfo, operationInByIdOptimize); … … 1757 1891 } 1758 1892 1759 void resetPutByID(CodeBlock* codeBlock, StructureStubInfo& stubInfo) 1760 { 1761 using FunctionType = decltype(&operationPutByIdDirectStrictOptimize); 1762 FunctionType unoptimizedFunction = reinterpret_cast<FunctionType>(readPutICCallTarget(codeBlock, stubInfo).executableAddress()); 1763 FunctionType optimizedFunction; 1764 if (unoptimizedFunction == operationPutByIdStrict || unoptimizedFunction == operationPutByIdStrictOptimize) 1765 optimizedFunction = operationPutByIdStrictOptimize; 1766 else if (unoptimizedFunction == operationPutByIdNonStrict || unoptimizedFunction == operationPutByIdNonStrictOptimize) 1767 optimizedFunction = operationPutByIdNonStrictOptimize; 1768 else if (unoptimizedFunction == operationPutByIdDirectStrict || unoptimizedFunction == operationPutByIdDirectStrictOptimize) 1769 optimizedFunction = operationPutByIdDirectStrictOptimize; 1770 else if (unoptimizedFunction == operationPutByIdSetPrivateFieldStrict || unoptimizedFunction == operationPutByIdSetPrivateFieldStrictOptimize) 1771 optimizedFunction = operationPutByIdSetPrivateFieldStrictOptimize; 1772 else if (unoptimizedFunction == operationPutByIdDefinePrivateFieldStrict || unoptimizedFunction == operationPutByIdDefinePrivateFieldStrictOptimize) 1773 optimizedFunction = operationPutByIdDefinePrivateFieldStrictOptimize; 1774 else { 1775 ASSERT(unoptimizedFunction == operationPutByIdDirectNonStrict || unoptimizedFunction == operationPutByIdDirectNonStrictOptimize); 1776 optimizedFunction = operationPutByIdDirectNonStrictOptimize; 1893 void resetPutBy(CodeBlock* codeBlock, StructureStubInfo& stubInfo, PutByKind kind) 1894 { 1895 FunctionPtr<CFunctionPtrTag> optimizedFunction; 1896 switch (kind) { 1897 case PutByKind::ById: { 1898 using FunctionType = decltype(&operationPutByIdDirectStrictOptimize); 1899 FunctionType unoptimizedFunction = reinterpret_cast<FunctionType>(readPutICCallTarget(codeBlock, stubInfo).executableAddress()); 1900 if (unoptimizedFunction == operationPutByIdStrict || unoptimizedFunction == operationPutByIdStrictOptimize) 1901 optimizedFunction = operationPutByIdStrictOptimize; 1902 else if (unoptimizedFunction == operationPutByIdNonStrict || unoptimizedFunction == operationPutByIdNonStrictOptimize) 1903 optimizedFunction = operationPutByIdNonStrictOptimize; 1904 else if (unoptimizedFunction == operationPutByIdDirectStrict || unoptimizedFunction == operationPutByIdDirectStrictOptimize) 1905 optimizedFunction = operationPutByIdDirectStrictOptimize; 1906 else if (unoptimizedFunction == operationPutByIdSetPrivateFieldStrict || unoptimizedFunction == operationPutByIdSetPrivateFieldStrictOptimize) 1907 optimizedFunction = operationPutByIdSetPrivateFieldStrictOptimize; 1908 else if (unoptimizedFunction == operationPutByIdDefinePrivateFieldStrict || unoptimizedFunction == operationPutByIdDefinePrivateFieldStrictOptimize) 1909 optimizedFunction = operationPutByIdDefinePrivateFieldStrictOptimize; 1910 else { 1911 ASSERT(unoptimizedFunction == operationPutByIdDirectNonStrict || unoptimizedFunction == operationPutByIdDirectNonStrictOptimize); 1912 optimizedFunction = operationPutByIdDirectNonStrictOptimize; 1913 } 1914 break; 1915 } 1916 case PutByKind::ByVal: { 1917 using FunctionType = decltype(&operationPutByValStrictOptimize); 1918 FunctionType unoptimizedFunction = reinterpret_cast<FunctionType>(readPutICCallTarget(codeBlock, stubInfo).executableAddress()); 1919 if (unoptimizedFunction == operationPutByValStrictGeneric || unoptimizedFunction == operationPutByValStrictOptimize) 1920 optimizedFunction = operationPutByValStrictOptimize; 1921 else if (unoptimizedFunction == operationPutByValNonStrictGeneric || unoptimizedFunction == operationPutByValNonStrictOptimize) 1922 optimizedFunction = operationPutByValNonStrictOptimize; 1923 else if (unoptimizedFunction == operationDirectPutByValStrictGeneric || unoptimizedFunction == operationDirectPutByValStrictOptimize) 1924 optimizedFunction = operationDirectPutByValStrictOptimize; 1925 else { 1926 ASSERT(unoptimizedFunction == operationDirectPutByValNonStrictGeneric || unoptimizedFunction == operationDirectPutByValNonStrictOptimize); 1927 optimizedFunction = operationDirectPutByValNonStrictOptimize; 1928 } 1929 break; 1930 } 1777 1931 } 1778 1932 1779 1933 repatchSlowPathCall(codeBlock, stubInfo, optimizedFunction); 1780 InlineAccess::resetStubAsJumpInAccess(codeBlock, stubInfo); 1934 switch (kind) { 1935 case PutByKind::ById: 1936 InlineAccess::resetStubAsJumpInAccess(codeBlock, stubInfo); 1937 break; 1938 case PutByKind::ByVal: 1939 InlineAccess::resetStubAsJumpInAccessNotUsingInlineAccess(codeBlock, stubInfo); 1940 break; 1941 } 1781 1942 } 1782 1943 -
trunk/Source/JavaScriptCore/jit/Repatch.h
r279105 r281615 44 44 }; 45 45 46 enum class PutByKind { 47 ById, 48 ByVal, 49 }; 50 46 51 enum class DelByKind { 47 52 ById, … … 57 62 void repatchArrayGetByVal(JSGlobalObject*, CodeBlock*, JSValue base, JSValue index, StructureStubInfo&); 58 63 void repatchGetBy(JSGlobalObject*, CodeBlock*, JSValue, CacheableIdentifier, const PropertySlot&, StructureStubInfo&, GetByKind); 59 void repatchPutByID(JSGlobalObject*, CodeBlock*, JSValue, Structure*, CacheableIdentifier, const PutPropertySlot&, StructureStubInfo&, PutKind); 64 void repatchArrayPutByVal(JSGlobalObject*, CodeBlock*, JSValue base, JSValue index, StructureStubInfo&, PutKind, ECMAMode); 65 void repatchPutBy(JSGlobalObject*, CodeBlock*, JSValue, Structure*, CacheableIdentifier, const PutPropertySlot&, StructureStubInfo&, PutByKind, PutKind); 60 66 void repatchDeleteBy(JSGlobalObject*, CodeBlock*, DeletePropertySlot&, JSValue, Structure*, CacheableIdentifier, StructureStubInfo&, DelByKind, ECMAMode); 61 67 void repatchInBy(JSGlobalObject*, CodeBlock*, JSObject*, CacheableIdentifier, bool wasFound, const PropertySlot&, StructureStubInfo&, InByKind); … … 70 76 void linkPolymorphicCall(JSGlobalObject*, CallFrame*, CallLinkInfo&, CallVariant); 71 77 void resetGetBy(CodeBlock*, StructureStubInfo&, GetByKind); 72 void resetPutBy ID(CodeBlock*, StructureStubInfo&);78 void resetPutBy(CodeBlock*, StructureStubInfo&, PutByKind); 73 79 void resetDelBy(CodeBlock*, StructureStubInfo&, DelByKind); 74 80 void resetInBy(CodeBlock*, StructureStubInfo&, InByKind); -
trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.h
r252684 r281615 33 33 34 34 // The following is a set of alias for the opcode names. This is needed 35 // because there is code (e.g. in GetByStatus.cpp and PutBy IdStatus.cpp)35 // because there is code (e.g. in GetByStatus.cpp and PutByStatus.cpp) 36 36 // which refers to the opcodes expecting them to be prefixed with "llint_". 37 37 // In the CLoop implementation, the 2 are equivalent. Hence, we set up this
Note: See TracChangeset
for help on using the changeset viewer.