Changeset 208117 in webkit
- Timestamp:
- Oct 29, 2016 6:38:22 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 4 added
- 29 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r208053 r208117 1 2016-10-29 Saam Barati <sbarati@apple.com> 2 3 We should have a way of profiling when a get_by_id is pure and to emit a PureGetById in the DFG/FTL 4 https://bugs.webkit.org/show_bug.cgi?id=163305 5 6 Reviewed by Keith Miller. 7 8 * microbenchmarks/pure-get-by-id-cse-2.js: Added. 9 (foo): 10 * microbenchmarks/pure-get-by-id-cse.js: Added. 11 (foo): 12 * stress/pure-get-by-id-cse-correctness.js: Added. 13 (assert): 14 (foo): 15 * stress/pure-get-by-id-on-non-object.js: Added. 16 (assert): 17 (foo): 18 1 19 2016-10-28 Csaba Osztrogonác <ossy@webkit.org> 2 20 -
trunk/Source/JavaScriptCore/ChangeLog
r208097 r208117 1 2016-10-29 Saam Barati <sbarati@apple.com> 2 3 We should have a way of profiling when a get_by_id is pure and to emit a PureGetById in the DFG/FTL 4 https://bugs.webkit.org/show_bug.cgi?id=163305 5 6 Reviewed by Keith Miller. 7 8 This creates a new GetById node in the DFG called PureGetById. We emit a 9 PureGetById when we profile that a get_by_id in the baseline never does 10 side effects. PureGetById speculates on the fact that it won't do side 11 effects. If it realizes that it must perform side effects, it will perform 12 the side effect, but also invalidate the CodeBlock that compiled it, 13 which will cause us to exit once we return back to the compiled code. 14 This allows us to have stricter clobberize rules for PureGetById which 15 model how getOwnPropertySlot(VMInquiry) behaves. This means that PureGetByIds 16 can be CSEd with each other, and that other things are more likely to 17 be CSEd around a PureGetById. To profile if a get_by_id does side 18 effects, I've added an extra bit into StructureStubInfo that we write 19 to when performing a get_by_id slow path call. If we notice that we 20 never do effects, inside the ByteCodeParser, we will emit a PureGetById 21 instead of a GetById. 22 23 To justify the performance benefit of this patch, I ran the suite of 24 benchmarks with useAccessInlining=false. This meant that we don't compile 25 any (Multi)GetByOffset/(Multi)PutByOffset. This was just to try to see if 26 this patch is worth anything at all in a world where we emit many 27 PureGetByIds. Running the benchmarks under this mode showed a 3.5% octane 28 improvement and a 15% kraken improvement. However, when running benchmarks 29 with useAccessInlining=true (the default JSC state), this patch is neutral. 30 I think the main reason for this is that the DFG is good at knowing when to 31 emit (Multi)GetByOffset, and most benchmarks that would benefit from 32 PureGetById are already emitting (Multi)GetByOffset. However, PureGetById can be 33 profitable when we encounter code that is too polymorphic for (Multi)GetByOffset. 34 It's reasonable to expect that JS code in the wild will fall into this use 35 case even though it might not be represented in some of the major JS benchmarks. 36 I wrote some microbenchmarks to demonstrate the benefits of PureGetById CSE, 37 and they were 30% (eliminating a few PureGetById from an add expression) 38 to 10x faster (eliminating a PureGetById in a loop). 39 40 * bytecode/StructureStubInfo.cpp: 41 (JSC::StructureStubInfo::StructureStubInfo): 42 (JSC::StructureStubInfo::reset): 43 * bytecode/StructureStubInfo.h: 44 * dfg/DFGAbstractInterpreterInlines.h: 45 (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): 46 * dfg/DFGArrayMode.cpp: 47 (JSC::DFG::canBecomeGetArrayLength): 48 * dfg/DFGByteCodeParser.cpp: 49 (JSC::DFG::ByteCodeParser::handleGetById): 50 (JSC::DFG::ByteCodeParser::parseBlock): 51 * dfg/DFGClobberize.h: 52 (JSC::DFG::clobberize): 53 * dfg/DFGConstantFoldingPhase.cpp: 54 (JSC::DFG::ConstantFoldingPhase::foldConstants): 55 * dfg/DFGDoesGC.cpp: 56 (JSC::DFG::doesGC): 57 * dfg/DFGFixupPhase.cpp: 58 (JSC::DFG::FixupPhase::fixupNode): 59 * dfg/DFGNode.h: 60 (JSC::DFG::Node::convertToGetByOffset): 61 (JSC::DFG::Node::convertToMultiGetByOffset): 62 (JSC::DFG::Node::hasIdentifier): 63 (JSC::DFG::Node::hasHeapPrediction): 64 * dfg/DFGNodeType.h: 65 * dfg/DFGPredictionPropagationPhase.cpp: 66 * dfg/DFGSafeToExecute.h: 67 (JSC::DFG::safeToExecute): 68 * dfg/DFGSpeculativeJIT.cpp: 69 (JSC::DFG::SpeculativeJIT::compileTryGetById): 70 (JSC::DFG::SpeculativeJIT::compilePureGetById): 71 * dfg/DFGSpeculativeJIT.h: 72 * dfg/DFGSpeculativeJIT32_64.cpp: 73 (JSC::DFG::SpeculativeJIT::cachedGetById): 74 (JSC::DFG::SpeculativeJIT::compile): 75 * dfg/DFGSpeculativeJIT64.cpp: 76 (JSC::DFG::SpeculativeJIT::cachedGetById): 77 (JSC::DFG::SpeculativeJIT::compile): 78 * ftl/FTLCapabilities.cpp: 79 (JSC::FTL::canCompile): 80 * ftl/FTLLowerDFGToB3.cpp: 81 (JSC::FTL::DFG::LowerDFGToB3::compileNode): 82 (JSC::FTL::DFG::LowerDFGToB3::compileGetById): 83 (JSC::FTL::DFG::LowerDFGToB3::getById): 84 * jit/JITOperations.cpp: 85 (JSC::pureGetByIdCommon): 86 * jit/JITOperations.h: 87 * jit/JITPropertyAccess.cpp: 88 (JSC::JIT::emit_op_try_get_by_id): 89 * jit/JITPropertyAccess32_64.cpp: 90 (JSC::JIT::emit_op_try_get_by_id): 91 * jit/Repatch.cpp: 92 (JSC::appropriateOptimizingGetByIdFunction): 93 (JSC::appropriateGenericGetByIdFunction): 94 (JSC::tryCacheGetByID): 95 * jit/Repatch.h: 96 * profiler/ProfilerJettisonReason.cpp: 97 (WTF::printInternal): 98 * profiler/ProfilerJettisonReason.h: 99 1 100 2016-10-28 Joseph Pecoraro <pecoraro@apple.com> 2 101 -
trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp
r205462 r208117 49 49 , tookSlowPath(false) 50 50 , everConsidered(false) 51 , didSideEffects(false) 51 52 { 52 53 } … … 217 218 218 219 switch (accessType) { 219 case AccessType::GetPure: 220 case AccessType::TryGet: 221 resetGetByID(codeBlock, *this, GetByIDKind::Try); 222 break; 223 case AccessType::PureGet: 220 224 resetGetByID(codeBlock, *this, GetByIDKind::Pure); 221 225 break; -
trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.h
r206525 r208117 47 47 enum class AccessType : int8_t { 48 48 Get, 49 GetPure, 49 TryGet, 50 PureGet, 50 51 Put, 51 52 In … … 206 207 bool tookSlowPath : 1; 207 208 bool everConsidered : 1; 209 bool didSideEffects : 1; 208 210 }; 209 211 -
trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
r208077 r208117 2120 2120 break; 2121 2121 2122 case PureGetById: 2122 2123 case GetById: 2123 2124 case GetByIdFlush: { … … 2151 2152 } 2152 2153 2153 clobberWorld(node->origin.semantic, clobberLimit); 2154 if (node->op() == PureGetById) 2155 clobberStructures(clobberLimit); 2156 else 2157 clobberWorld(node->origin.semantic, clobberLimit); 2154 2158 forNode(node).makeHeapTop(); 2155 2159 break; -
trunk/Source/JavaScriptCore/dfg/DFGArrayMode.cpp
r205830 r208117 153 153 static bool canBecomeGetArrayLength(Graph& graph, Node* node) 154 154 { 155 if (node->op() != GetById) 156 return false; 157 auto uid = graph.identifiers()[node->identifierNumber()]; 158 return uid == graph.m_vm.propertyNames->length.impl(); 155 if (node->op() == GetById || node->op() == PureGetById) { 156 auto uid = graph.identifiers()[node->identifierNumber()]; 157 return uid == graph.m_vm.propertyNames->length.impl(); 158 } 159 return false; 159 160 } 160 161 -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r208078 r208117 3308 3308 3309 3309 NodeType getById; 3310 if (type == AccessType::Get) 3310 switch (type) { 3311 case AccessType::Get: 3311 3312 getById = getByIdStatus.makesCalls() ? GetByIdFlush : GetById; 3312 else 3313 break; 3314 case AccessType::TryGet: 3313 3315 getById = TryGetById; 3316 break; 3317 case AccessType::PureGet: 3318 getById = PureGetById; 3319 break; 3320 default: 3321 RELEASE_ASSERT_NOT_REACHED(); 3322 } 3314 3323 3315 3324 // Special path for custom accessors since custom's offset does not have any meanings. … … 4199 4208 Node* base = get(VirtualRegister(currentInstruction[2].u.operand)); 4200 4209 Node* property = get(VirtualRegister(currentInstruction[3].u.operand)); 4201 bool compiledAsGetById = false; 4210 bool compileAsGetById = false; 4211 bool compileAsPureGetById = false; 4202 4212 GetByIdStatus getByIdStatus; 4203 4213 unsigned identifierNumber = 0; … … 4208 4218 // At that time, there is no information. 4209 4219 if (byValInfo && byValInfo->stubInfo && !byValInfo->tookSlowPath && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIdent) && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCell)) { 4210 compiledAsGetById = true; 4220 compileAsGetById = true; 4221 compileAsPureGetById = !byValInfo->stubInfo->didSideEffects; 4211 4222 identifierNumber = m_graph.identifiers().ensure(byValInfo->cachedId.impl()); 4212 4223 UniquedStringImpl* uid = m_graph.identifiers()[identifierNumber]; … … 4226 4237 } 4227 4238 4228 if (compiledAsGetById) 4229 handleGetById(currentInstruction[1].u.operand, prediction, base, identifierNumber, getByIdStatus, AccessType::Get, OPCODE_LENGTH(op_get_by_val)); 4230 else { 4239 if (compileAsGetById) { 4240 AccessType type = compileAsPureGetById ? AccessType::PureGet : AccessType::Get; 4241 handleGetById(currentInstruction[1].u.operand, prediction, base, identifierNumber, getByIdStatus, type, OPCODE_LENGTH(op_get_by_val)); 4242 } else { 4231 4243 ArrayMode arrayMode = getArrayMode(currentInstruction[4].u.arrayProfile, Array::Read); 4232 4244 Node* getByVal = addToGraph(GetByVal, OpInfo(arrayMode.asWord()), OpInfo(prediction), base, property); … … 4364 4376 m_inlineStackTop->m_stubInfos, m_dfgStubInfos, 4365 4377 currentCodeOrigin(), uid); 4366 AccessType type = op_try_get_by_id == opcodeID ? AccessType::GetPure : AccessType::Get; 4378 AccessType type; 4379 if (opcodeID == op_try_get_by_id) 4380 type = AccessType::TryGet; 4381 else { 4382 ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock); 4383 unsigned bytecodeIndex = currentCodeOrigin().bytecodeIndex; 4384 StructureStubInfo* info = m_inlineStackTop->m_stubInfos.get(CodeOrigin(bytecodeIndex)); 4385 if (info && info->everConsidered && !info->didSideEffects) 4386 type = AccessType::PureGet; 4387 else 4388 type = AccessType::Get; 4389 } 4367 4390 4368 4391 unsigned opcodeLength = opcodeID == op_try_get_by_id ? OPCODE_LENGTH(op_try_get_by_id) : OPCODE_LENGTH(op_get_by_id); -
trunk/Source/JavaScriptCore/dfg/DFGClobberize.h
r208077 r208117 496 496 return; 497 497 498 case PureGetById: { 499 // We model what is allowed inside a getOwnPropertySlot(VMInquiry) here. 500 // Some getOwnPropertySlot implementations will lazily inject properties, which 501 // may change the object's structure. 502 503 read(JSCell_structureID); 504 read(JSCell_typeInfoFlags); 505 read(JSCell_typeInfoType); 506 read(JSCell_indexingType); 507 read(JSObject_butterfly); 508 read(MiscFields); 509 510 AbstractHeap propertyNameHeap(NamedProperties, node->identifierNumber()); 511 read(propertyNameHeap); 512 513 write(JSCell_structureID); 514 write(JSCell_typeInfoFlags); 515 516 write(Watchpoint_fire); 517 write(MiscFields); 518 519 // This can happen if lazily adding fields to an object happens in getOwnPropertySlot 520 // and we need to allocate out of line storage. 521 write(JSObject_butterfly); 522 523 def(HeapLocation(NamedPropertyLoc, propertyNameHeap, node->child1()), LazyNode(node)); 524 return; 525 } 526 498 527 case GetById: 499 528 case GetByIdFlush: -
trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
r206846 r208117 449 449 } 450 450 451 case PureGetById: 451 452 case GetById: 452 453 case GetByIdFlush: { … … 459 460 m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before. 460 461 alreadyHandled = true; // Don't allow the default constant folder to do things to this. 462 463 if (!Options::useAccessInlining()) 464 break; 461 465 462 466 if (baseValue.m_structure.isTop() || baseValue.m_structure.isClobbered() … … 514 518 m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before. 515 519 alreadyHandled = true; // Don't allow the default constant folder to do things to this. 520 521 if (!Options::useAccessInlining()) 522 break; 516 523 517 524 if (baseValue.m_structure.isTop() || baseValue.m_structure.isClobbered()) -
trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
r208077 r208117 265 265 return false; 266 266 267 case PureGetById: // We are modeling getOwnPropertySlot here, which may GC because it is allowed to allocate things. 267 268 case CreateActivation: 268 269 case CreateDirectArguments: -
trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
r208077 r208117 1168 1168 } 1169 1169 1170 case PureGetById: 1170 1171 case GetById: 1171 1172 case GetByIdFlush: { -
trunk/Source/JavaScriptCore/dfg/DFGNode.h
r208078 r208117 533 533 void convertToGetByOffset(StorageAccessData& data, Edge storage, Edge base) 534 534 { 535 ASSERT(m_op == GetById || m_op == GetByIdFlush || m_op == MultiGetByOffset);535 ASSERT(m_op == GetById || m_op == GetByIdFlush || m_op == PureGetById || m_op == MultiGetByOffset); 536 536 m_opInfo = &data; 537 537 children.setChild1(storage); … … 543 543 void convertToMultiGetByOffset(MultiGetByOffsetData* data) 544 544 { 545 ASSERT(m_op == GetById || m_op == GetByIdFlush );545 ASSERT(m_op == GetById || m_op == GetByIdFlush || m_op == PureGetById); 546 546 m_opInfo = data; 547 547 child1().setUseKind(CellUse); … … 919 919 case TryGetById: 920 920 case GetById: 921 case PureGetById: 921 922 case GetByIdFlush: 922 923 case GetByIdWithThis: … … 1429 1430 case ArithTrunc: 1430 1431 case GetDirectPname: 1432 case PureGetById: 1431 1433 case GetById: 1432 1434 case GetByIdFlush: -
trunk/Source/JavaScriptCore/dfg/DFGNodeType.h
r208077 r208117 186 186 macro(PutByValAlias, NodeMustGenerate | NodeHasVarArgs) \ 187 187 macro(TryGetById, NodeResultJS) \ 188 macro(PureGetById, NodeResultJS | NodeMustGenerate) \ 188 189 macro(GetById, NodeResultJS | NodeMustGenerate) \ 189 190 macro(GetByIdFlush, NodeResultJS | NodeMustGenerate) \ -
trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
r208077 r208117 683 683 case StringReplace: 684 684 case StringReplaceRegExp: 685 case PureGetById: 685 686 case GetById: 686 687 case GetByIdFlush: -
trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
r208077 r208117 200 200 case DeleteById: 201 201 case DeleteByVal: 202 case PureGetById: 202 203 case GetById: 203 204 case GetByIdWithThis: -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r208077 r208117 1004 1004 base.use(); 1005 1005 1006 cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), JITCompiler::Jump(), NeedToSpill, AccessType:: GetPure);1006 cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), JITCompiler::Jump(), NeedToSpill, AccessType::TryGet); 1007 1007 1008 1008 jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly); … … 1021 1021 JITCompiler::Jump notCell = m_jit.branchIfNotCell(baseRegs); 1022 1022 1023 cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), notCell, NeedToSpill, AccessType:: GetPure);1023 cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), notCell, NeedToSpill, AccessType::TryGet); 1024 1024 1025 1025 jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly); … … 1031 1031 break; 1032 1032 } 1033 } 1034 1035 void SpeculativeJIT::compilePureGetById(Node* node) 1036 { 1037 ASSERT(node->op() == PureGetById); 1038 1039 switch (node->child1().useKind()) { 1040 case CellUse: { 1041 SpeculateCellOperand base(this, node->child1()); 1042 JSValueRegsTemporary result(this, Reuse, base); 1043 1044 JSValueRegs baseRegs = JSValueRegs::payloadOnly(base.gpr()); 1045 JSValueRegs resultRegs = result.regs(); 1046 1047 cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), JITCompiler::Jump(), NeedToSpill, AccessType::PureGet); 1048 1049 jsValueResult(resultRegs, node); 1050 break; 1051 } 1052 case UntypedUse: { 1053 JSValueOperand base(this, node->child1()); 1054 JSValueRegsTemporary result(this, Reuse, base); 1055 1056 JSValueRegs baseRegs = base.jsValueRegs(); 1057 JSValueRegs resultRegs = result.regs(); 1058 1059 JITCompiler::Jump notCell = m_jit.branchIfNotCell(baseRegs); 1060 1061 cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), notCell, NeedToSpill, AccessType::PureGet); 1062 1063 jsValueResult(resultRegs, node); 1064 break; 1065 } 1066 default: 1067 RELEASE_ASSERT_NOT_REACHED(); 1068 } 1033 1069 } 1034 1070 -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
r208077 r208117 722 722 void compileDeleteByVal(Node*); 723 723 void compileTryGetById(Node*); 724 void compilePureGetById(Node*); 724 725 void compileIn(Node*); 725 726 -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
r208077 r208117 211 211 if (type == AccessType::Get) 212 212 getByIdFunction = operationGetByIdOptimize; 213 else if (type == AccessType::PureGet) 214 getByIdFunction = operationPureGetByIdOptimize; 213 215 else 214 216 getByIdFunction = operationTryGetByIdOptimize; … … 4270 4272 } 4271 4273 4274 case PureGetById: { 4275 compilePureGetById(node); 4276 break; 4277 } 4278 4272 4279 case GetByIdWithThis: { 4273 4280 JSValueOperand base(this, node->child1()); -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r208077 r208117 180 180 slowCases.append(gen.slowPathJump()); 181 181 182 auto slowPathFunction = type == AccessType::Get ? operationGetByIdOptimize : 183 type == AccessType::PureGet ? operationPureGetByIdOptimize : operationTryGetByIdOptimize; 184 182 185 auto slowPath = slowPathCall( 183 slowCases, this, type == AccessType::Get ? operationGetByIdOptimize : operationTryGetByIdOptimize,186 slowCases, this, slowPathFunction, 184 187 spillMode, ExceptionCheckRequirement::CheckNeeded, 185 188 resultGPR, gen.stubInfo(), baseGPR, identifierUID(identifierNumber)); … … 4236 4239 } 4237 4240 4241 case PureGetById: { 4242 compilePureGetById(node); 4243 break; 4244 } 4245 4238 4246 case GetByIdFlush: { 4239 4247 if (!node->prediction()) { -
trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
r208077 r208117 177 177 case TryGetById: 178 178 case GetById: 179 case PureGetById: 179 180 case GetByIdFlush: 180 181 case GetByIdWithThis: -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r208077 r208117 624 624 break; 625 625 case TryGetById: 626 compileGetById(AccessType::GetPure); 626 compileGetById(AccessType::TryGet); 627 break; 628 case PureGetById: 629 compileGetById(AccessType::PureGet); 627 630 break; 628 631 case GetById: … … 2789 2792 void compileGetById(AccessType type) 2790 2793 { 2791 ASSERT(type == AccessType::Get || type == AccessType:: GetPure);2794 ASSERT(type == AccessType::Get || type == AccessType::TryGet || type == AccessType::PureGet); 2792 2795 switch (m_node->child1().useKind()) { 2793 2796 case CellUse: { … … 2816 2819 if (type == AccessType::Get) 2817 2820 getByIdFunction = operationGetByIdGeneric; 2821 else if (type == AccessType::PureGet) 2822 getByIdFunction = operationPureGetByIdGeneric; 2818 2823 else 2819 2824 getByIdFunction = operationTryGetByIdGeneric; … … 8839 8844 if (type == AccessType::Get) 8840 8845 optimizationFunction = operationGetByIdOptimize; 8846 else if (type == AccessType::PureGet) 8847 optimizationFunction = operationPureGetByIdOptimize; 8841 8848 else 8842 8849 optimizationFunction = operationTryGetByIdOptimize; -
trunk/Source/JavaScriptCore/jit/JITOperations.cpp
r208052 r208117 71 71 namespace JSC { 72 72 73 ALWAYS_INLINE static EncodedJSValue pureGetByIdCommon(VM& vm, ExecState* exec, EncodedJSValue base, UniquedStringImpl* uid, const std::function<void (const PropertySlot&, const Identifier&)>& function = [] (const PropertySlot&, const Identifier&) { }) 74 { 75 Identifier ident = Identifier::fromUid(&vm, uid); 76 JSValue baseValue = JSValue::decode(base); 77 78 ASSERT(JITCode::isOptimizingJIT(exec->codeBlock()->jitType())); 79 80 PropertySlot slot(baseValue, PropertySlot::InternalMethodType::VMInquiry); 81 return JSValue::encode(baseValue.getPropertySlot(exec, ident, slot, [&] (bool, PropertySlot&) -> JSValue { 82 bool willDoSideEffects = !(slot.isValue() || slot.isUnset()) || slot.isTaintedByOpaqueObject(); 83 if (UNLIKELY(willDoSideEffects)) { 84 { 85 CodeOrigin codeOrigin = exec->codeOrigin(); 86 CodeBlock* currentBaseline = baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, exec->codeBlock()->alternative()); 87 CodeOrigin originBytecodeIndex = CodeOrigin(codeOrigin.bytecodeIndex); // Since we're searching in the baseline, we just care about bytecode index. 88 ConcurrentJITLocker locker(currentBaseline->m_lock); 89 if (StructureStubInfo* stub = currentBaseline->findStubInfo(originBytecodeIndex)) 90 stub->didSideEffects = true; 91 } 92 93 exec->codeBlock()->jettison(Profiler::JettisonDueToPureGetByIdEffects); 94 return baseValue.get(exec, uid); 95 } 96 97 function(slot, ident); 98 return slot.isValue() ? slot.getValue(exec, ident) : jsUndefined(); 99 })); 100 } 101 73 102 extern "C" { 74 103 … … 166 195 } 167 196 197 EncodedJSValue JIT_OPERATION operationPureGetByIdGeneric(ExecState* exec, EncodedJSValue base, UniquedStringImpl* uid) 198 { 199 VM* vm = &exec->vm(); 200 NativeCallFrameTracer tracer(vm, exec); 201 202 return pureGetByIdCommon(*vm, exec, base, uid); 203 } 204 205 EncodedJSValue JIT_OPERATION operationPureGetById(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid) 206 { 207 VM* vm = &exec->vm(); 208 NativeCallFrameTracer tracer(vm, exec); 209 210 stubInfo->tookSlowPath = true; 211 212 return pureGetByIdCommon(*vm, exec, base, uid); 213 } 214 215 EncodedJSValue JIT_OPERATION operationPureGetByIdOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid) 216 { 217 VM* vm = &exec->vm(); 218 NativeCallFrameTracer tracer(vm, exec); 219 220 return pureGetByIdCommon(*vm, exec, base, uid, 221 [&] (const PropertySlot& slot, const Identifier& ident) { 222 ASSERT((slot.isValue() || slot.isUnset()) && !slot.isTaintedByOpaqueObject()); 223 JSValue baseValue = JSValue::decode(base); 224 if (stubInfo->considerCaching(baseValue.structureOrNull())) 225 repatchGetByID(exec, baseValue, ident, slot, *stubInfo, GetByIDKind::Pure); 226 }); 227 } 228 168 229 EncodedJSValue JIT_OPERATION operationTryGetById(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid) 169 230 { … … 180 241 } 181 242 182 183 243 EncodedJSValue JIT_OPERATION operationTryGetByIdGeneric(ExecState* exec, EncodedJSValue base, UniquedStringImpl* uid) 184 244 { … … 208 268 209 269 if (stubInfo->considerCaching(baseValue.structureOrNull()) && !slot.isTaintedByOpaqueObject() && (slot.isCacheableValue() || slot.isCacheableGetter() || slot.isUnset())) 210 repatchGetByID(exec, baseValue, ident, slot, *stubInfo, GetByIDKind:: Pure);270 repatchGetByID(exec, baseValue, ident, slot, *stubInfo, GetByIDKind::Try); 211 271 212 272 return JSValue::encode(slot.getPureResult()); … … 227 287 228 288 LOG_IC((ICEvent::OperationGetById, baseValue.classInfoOrNull(), ident)); 229 return JSValue::encode(baseValue.get(exec, ident, slot)); 289 JSValue result = baseValue.get(exec, ident, slot); 290 bool willDoSideEffects = !(slot.isValue() || slot.isUnset()) || slot.isTaintedByOpaqueObject(); 291 stubInfo->didSideEffects |= willDoSideEffects; 292 return JSValue::encode(result); 230 293 } 231 294 … … 256 319 257 320 return JSValue::encode(baseValue.getPropertySlot(exec, ident, [&] (bool found, PropertySlot& slot) -> JSValue { 321 bool willDoSideEffects = !(slot.isValue() || slot.isUnset()) || slot.isTaintedByOpaqueObject(); 322 stubInfo->didSideEffects |= willDoSideEffects; 323 258 324 if (stubInfo->considerCaching(baseValue.structureOrNull())) 259 325 repatchGetByID(exec, baseValue, ident, slot, *stubInfo, GetByIDKind::Normal); -
trunk/Source/JavaScriptCore/jit/JITOperations.h
r208052 r208117 331 331 EncodedJSValue JIT_OPERATION operationTryGetByIdGeneric(ExecState*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL; 332 332 EncodedJSValue JIT_OPERATION operationTryGetByIdOptimize(ExecState*, StructureStubInfo*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL; 333 EncodedJSValue JIT_OPERATION operationPureGetById(ExecState*, StructureStubInfo*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL; 334 EncodedJSValue JIT_OPERATION operationPureGetByIdGeneric(ExecState*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL; 335 EncodedJSValue JIT_OPERATION operationPureGetByIdOptimize(ExecState*, StructureStubInfo*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL; 333 336 EncodedJSValue JIT_OPERATION operationGetById(ExecState*, StructureStubInfo*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL; 334 337 EncodedJSValue JIT_OPERATION operationGetByIdGeneric(ExecState*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL; -
trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp
r206778 r208117 580 580 JITGetByIdGenerator gen( 581 581 m_codeBlock, CodeOrigin(m_bytecodeOffset), CallSiteIndex(m_bytecodeOffset), RegisterSet::stubUnavailableRegisters(), 582 ident->impl(), JSValueRegs(regT0), JSValueRegs(regT0), AccessType:: GetPure);582 ident->impl(), JSValueRegs(regT0), JSValueRegs(regT0), AccessType::TryGet); 583 583 gen.generateFastPath(*this); 584 584 addSlowCase(gen.slowPathJump()); -
trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp
r206555 r208117 595 595 JITGetByIdGenerator gen( 596 596 m_codeBlock, CodeOrigin(m_bytecodeOffset), CallSiteIndex(currentInstruction), RegisterSet::stubUnavailableRegisters(), 597 ident->impl(), JSValueRegs::payloadOnly(regT0), JSValueRegs(regT1, regT0), AccessType:: GetPure);597 ident->impl(), JSValueRegs::payloadOnly(regT0), JSValueRegs(regT1, regT0), AccessType::TryGet); 598 598 gen.generateFastPath(*this); 599 599 addSlowCase(gen.slowPathJump()); -
trunk/Source/JavaScriptCore/jit/Repatch.cpp
r207475 r208117 135 135 inline J_JITOperation_ESsiJI appropriateOptimizingGetByIdFunction(GetByIDKind kind) 136 136 { 137 if (kind == GetByIDKind::Normal) 137 switch (kind) { 138 case GetByIDKind::Normal: 138 139 return operationGetByIdOptimize; 139 return operationTryGetByIdOptimize; 140 case GetByIDKind::Try: 141 return operationTryGetByIdOptimize; 142 case GetByIDKind::Pure: 143 return operationPureGetByIdOptimize; 144 default: 145 break; 146 } 147 ASSERT_NOT_REACHED(); 148 return operationGetByIdOptimize; 140 149 } 141 150 142 151 inline J_JITOperation_ESsiJI appropriateGenericGetByIdFunction(GetByIDKind kind) 143 152 { 144 if (kind == GetByIDKind::Normal) 153 switch (kind) { 154 case GetByIDKind::Normal: 145 155 return operationGetById; 146 return operationTryGetById; 156 case GetByIDKind::Try: 157 return operationTryGetById; 158 case GetByIDKind::Pure: 159 return operationPureGetById; 160 default: 161 break; 162 } 163 ASSERT_NOT_REACHED(); 164 return operationGetById; 147 165 } 148 166 … … 267 285 268 286 if (kind == GetByIDKind::Pure) { 287 AccessCase::AccessType type; 288 if (slot.isCacheableValue()) 289 type = AccessCase::Load; 290 else if (slot.isUnset()) 291 type = AccessCase::Miss; 292 else 293 RELEASE_ASSERT_NOT_REACHED(); 294 295 newCase = AccessCase::tryGet(vm, codeBlock, type, offset, structure, conditionSet, loadTargetFromProxy, slot.watchpointSet()); 296 } else if (kind == GetByIDKind::Try) { 269 297 AccessCase::AccessType type; 270 298 if (slot.isCacheableValue()) -
trunk/Source/JavaScriptCore/jit/Repatch.h
r207475 r208117 37 37 enum class GetByIDKind { 38 38 Normal, 39 Try, 39 40 Pure 40 41 }; -
trunk/Source/JavaScriptCore/profiler/ProfilerJettisonReason.cpp
r201239 r208117 57 57 out.print("OSRExit"); 58 58 return; 59 case JettisonDueToPureGetByIdEffects: 60 out.print("PureGetByIdEffects"); 61 return; 59 62 case JettisonDueToProfiledWatchpoint: 60 63 out.print("ProfiledWatchpoint"); -
trunk/Source/JavaScriptCore/profiler/ProfilerJettisonReason.h
r206525 r208117 36 36 JettisonDueToBaselineLoopReoptimizationTriggerOnOSREntryFail, 37 37 JettisonDueToOSRExit, 38 JettisonDueToPureGetByIdEffects, 38 39 JettisonDueToProfiledWatchpoint, 39 40 JettisonDueToUnprofiledWatchpoint,
Note: See TracChangeset
for help on using the changeset viewer.