Changeset 239153 in webkit
- Timestamp:
- Dec 12, 2018 11:13:38 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 6 added
- 34 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r239142 r239153 1 2018-12-10 Yusuke Suzuki <yusukesuzuki@slowstart.org> 2 3 [JSC] Optimize Object.keys by caching own keys results in StructureRareData 4 https://bugs.webkit.org/show_bug.cgi?id=190047 5 6 Reviewed by Keith Miller. 7 8 * stress/object-keys-cached-zero.js: Added. 9 (shouldBe): 10 (test): 11 * stress/object-keys-changed-attribute.js: Added. 12 (shouldBe): 13 (test): 14 * stress/object-keys-changed-index.js: Added. 15 (shouldBe): 16 (test): 17 * stress/object-keys-changed.js: Added. 18 (shouldBe): 19 (test): 20 * stress/object-keys-indexed-non-cache.js: Added. 21 (shouldBe): 22 (test): 23 * stress/object-keys-overrides-get-property-names.js: Added. 24 (shouldBe): 25 (test): 26 (noInline): 27 1 28 2018-12-12 Yusuke Suzuki <yusukesuzuki@slowstart.org> 2 29 -
trunk/Source/JavaScriptCore/ChangeLog
r239142 r239153 1 2018-12-10 Yusuke Suzuki <yusukesuzuki@slowstart.org> 2 3 [JSC] Optimize Object.keys by caching own keys results in StructureRareData 4 https://bugs.webkit.org/show_bug.cgi?id=190047 5 6 Reviewed by Keith Miller. 7 8 Object.keys is one of the most frequently used function in web-tooling-benchmarks (WTB). 9 Object.keys is dominant in lebab of WTB, and frequently called in babel and others. 10 Since our Structure knows the shape of JSObject, we can cache the result of Object.keys 11 in Structure (StructureRareData) as we cache JSPropertyNameEnumerator in StructureRareData. 12 13 This patch caches the result of Object.keys in StructureRareData. The cached array is created 14 as JSImmutableButterfly. And Object.keys creates CoW from this data. Currently, the lifetime 15 strategy of this JSImmutableButterfly is the same to cached JSPropertyNameEnumerator. It is 16 referenced from Structure, and collected when Structure is collected. 17 18 This improves several benchmarks in SixSpeed. 19 20 baseline patched 21 22 object-assign.es5 350.1710+-3.6303 ^ 226.0368+-4.7558 ^ definitely 1.5492x faster 23 for-of-object.es6 269.1941+-3.3430 ^ 127.9317+-2.3875 ^ definitely 2.1042x faster 24 25 And it improves WTB lebab by 11.8%. 26 27 Before: lebab: 6.10 runs/s 28 After: lebab: 6.82 runs/s 29 30 * dfg/DFGAbstractInterpreterInlines.h: 31 (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects): 32 * dfg/DFGByteCodeParser.cpp: 33 (JSC::DFG::ByteCodeParser::handleIntrinsicCall): 34 * dfg/DFGClobberize.h: 35 (JSC::DFG::clobberize): 36 * dfg/DFGConstantFoldingPhase.cpp: 37 (JSC::DFG::ConstantFoldingPhase::foldConstants): 38 * dfg/DFGDoesGC.cpp: 39 (JSC::DFG::doesGC): 40 * dfg/DFGFixupPhase.cpp: 41 (JSC::DFG::FixupPhase::fixupNode): 42 * dfg/DFGNode.cpp: 43 (JSC::DFG::Node::convertToNewArrayBuffer): 44 * dfg/DFGNode.h: 45 * dfg/DFGNodeType.h: 46 * dfg/DFGOperations.cpp: 47 * dfg/DFGOperations.h: 48 * dfg/DFGPredictionPropagationPhase.cpp: 49 * dfg/DFGSafeToExecute.h: 50 (JSC::DFG::safeToExecute): 51 * dfg/DFGSpeculativeJIT.cpp: 52 (JSC::DFG::SpeculativeJIT::compileObjectKeys): 53 * dfg/DFGSpeculativeJIT.h: 54 * dfg/DFGSpeculativeJIT32_64.cpp: 55 (JSC::DFG::SpeculativeJIT::compile): 56 * dfg/DFGSpeculativeJIT64.cpp: 57 (JSC::DFG::SpeculativeJIT::compile): 58 * ftl/FTLAbstractHeapRepository.h: 59 * ftl/FTLCapabilities.cpp: 60 (JSC::FTL::canCompile): 61 * ftl/FTLLowerDFGToB3.cpp: 62 (JSC::FTL::DFG::LowerDFGToB3::compileNode): 63 (JSC::FTL::DFG::LowerDFGToB3::compileObjectKeys): 64 * runtime/Intrinsic.cpp: 65 (JSC::intrinsicName): 66 * runtime/Intrinsic.h: 67 * runtime/JSImmutableButterfly.h: 68 (JSC::JSImmutableButterfly::createSentinel): 69 * runtime/ObjectConstructor.cpp: 70 (JSC::ownPropertyKeys): 71 * runtime/Structure.cpp: 72 (JSC::Structure::canCachePropertyNameEnumerator const): 73 * runtime/Structure.h: 74 * runtime/StructureInlines.h: 75 (JSC::Structure::setCachedOwnKeys): 76 (JSC::Structure::cachedOwnKeys const): 77 (JSC::Structure::canCacheOwnKeys const): 78 * runtime/StructureRareData.cpp: 79 (JSC::StructureRareData::visitChildren): 80 (JSC::StructureRareData::cachedPropertyNameEnumerator const): Deleted. 81 (JSC::StructureRareData::setCachedPropertyNameEnumerator): Deleted. 82 * runtime/StructureRareData.h: 83 * runtime/StructureRareDataInlines.h: 84 (JSC::StructureRareData::cachedPropertyNameEnumerator const): 85 (JSC::StructureRareData::setCachedPropertyNameEnumerator): 86 (JSC::StructureRareData::cachedOwnKeys const): 87 (JSC::StructureRareData::cachedOwnKeysConcurrently const): 88 (JSC::StructureRareData::setCachedOwnKeys): 89 (JSC::StructureRareData::previousID const): Deleted. 90 * runtime/VM.cpp: 91 (JSC::VM::VM): 92 * runtime/VM.h: 93 1 94 2018-12-12 Yusuke Suzuki <yusukesuzuki@slowstart.org> 2 95 -
trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
r239142 r239153 44 44 #include "PutByIdStatus.h" 45 45 #include "StringObject.h" 46 #include "StructureRareDataInlines.h" 46 47 #include <wtf/BooleanLattice.h> 47 48 #include <wtf/CheckedArithmetic.h> … … 2573 2574 clobberWorld(); 2574 2575 setTypeForNode(node, SpecFinalObject); 2576 break; 2577 } 2578 2579 case ObjectKeys: { 2580 if (node->child1().useKind() == ObjectUse) { 2581 auto& structureSet = forNode(node->child1()).m_structure; 2582 if (structureSet.isFinite() && structureSet.size() == 1) { 2583 RegisteredStructure structure = structureSet.onlyStructure(); 2584 if (auto* rareData = structure->rareDataConcurrently()) { 2585 auto* immutableButterfly = rareData->cachedOwnKeysConcurrently(); 2586 if (immutableButterfly && immutableButterfly != m_vm.sentinelImmutableButterfly.get()) { 2587 if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) { 2588 m_state.setFoundConstants(true); 2589 didFoldClobberWorld(); 2590 setTypeForNode(node, SpecArray); 2591 break; 2592 } 2593 } 2594 } 2595 } 2596 } 2597 2598 clobberWorld(); 2599 setTypeForNode(node, SpecArray); 2575 2600 break; 2576 2601 } -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r239142 r239153 2686 2686 insertChecks(); 2687 2687 set(result, addToGraph(SameValue, get(virtualRegisterForArgument(1, registerOffset)), get(virtualRegisterForArgument(2, registerOffset)))); 2688 return true; 2689 } 2690 2691 case ObjectKeysIntrinsic: { 2692 if (argumentCountIncludingThis < 2) 2693 return false; 2694 2695 insertChecks(); 2696 set(result, addToGraph(ObjectKeys, get(virtualRegisterForArgument(1, registerOffset)))); 2688 2697 return true; 2689 2698 } -
trunk/Source/JavaScriptCore/dfg/DFGClobberize.h
r239142 r239153 668 668 case InstanceOf: 669 669 case StringValueOf: 670 case ObjectKeys: 670 671 read(World); 671 672 write(Heap); … … 1528 1529 } 1529 1530 } 1530 1531 1531 1532 1532 case NewObject: -
trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
r234178 r239153 767 767 } 768 768 769 case ObjectKeys: { 770 if (node->child1().useKind() == ObjectUse) { 771 auto& structureSet = m_state.forNode(node->child1()).m_structure; 772 if (structureSet.isFinite() && structureSet.size() == 1) { 773 RegisteredStructure structure = structureSet.onlyStructure(); 774 if (auto* rareData = structure->rareDataConcurrently()) { 775 auto* immutableButterfly = rareData->cachedOwnKeysConcurrently(); 776 if (immutableButterfly && immutableButterfly != m_graph.m_vm.sentinelImmutableButterfly.get()) { 777 if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) { 778 node->convertToNewArrayBuffer(m_graph.freeze(immutableButterfly)); 779 changed = true; 780 break; 781 } 782 } 783 } 784 } 785 } 786 break; 787 } 788 769 789 case ToNumber: { 770 790 if (m_state.forNode(node->child1()).m_type & ~SpecBytecodeNumber) -
trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
r239142 r239153 339 339 case CreateThis: 340 340 case ObjectCreate: 341 case ObjectKeys: 341 342 case AllocatePropertyStorage: 342 343 case ReallocatePropertyStorage: -
trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
r239142 r239153 1572 1572 node->clearFlags(NodeMustGenerate); 1573 1573 break; 1574 } 1575 break; 1576 } 1577 1578 case ObjectKeys: { 1579 if (node->child1()->shouldSpeculateObject()) { 1580 watchHavingABadTime(node); 1581 fixEdge<ObjectUse>(node->child1()); 1574 1582 } 1575 1583 break; -
trunk/Source/JavaScriptCore/dfg/DFGNode.cpp
r235538 r239153 32 32 #include "DFGPromotedHeapLocation.h" 33 33 #include "JSCInlines.h" 34 #include "JSImmutableButterfly.h" 34 35 35 36 namespace JSC { namespace DFG { … … 224 225 } 225 226 227 void Node::convertToNewArrayBuffer(FrozenValue* immutableButterfly) 228 { 229 setOpAndDefaultFlags(NewArrayBuffer); 230 NewArrayBufferData data { }; 231 data.indexingMode = immutableButterfly->cast<JSImmutableButterfly*>()->indexingMode(); 232 data.vectorLengthHint = immutableButterfly->cast<JSImmutableButterfly*>()->toButterfly()->vectorLength(); 233 children.reset(); 234 m_opInfo = immutableButterfly; 235 m_opInfo2 = data.asQuadWord; 236 } 237 226 238 void Node::convertToDirectCall(FrozenValue* executable) 227 239 { -
trunk/Source/JavaScriptCore/dfg/DFGNode.h
r239045 r239153 762 762 m_opInfo2 = OpInfoWrapper(); 763 763 } 764 765 void convertToNewArrayBuffer(FrozenValue* immutableButterfly); 764 766 765 767 void convertToDirectCall(FrozenValue*); -
trunk/Source/JavaScriptCore/dfg/DFGNodeType.h
r239142 r239153 265 265 macro(GetPrototypeOf, NodeMustGenerate | NodeResultJS) \ 266 266 macro(ObjectCreate, NodeMustGenerate | NodeResultJS) \ 267 macro(ObjectKeys, NodeMustGenerate | NodeResultJS) \ 267 268 \ 268 269 /* Atomics object functions. */\ -
trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp
r239142 r239153 249 249 } 250 250 251 JSArray* JIT_OPERATION operationObjectKeys(ExecState* exec, EncodedJSValue encodedObject) 252 { 253 VM& vm = exec->vm(); 254 NativeCallFrameTracer tracer(&vm, exec); 255 auto scope = DECLARE_THROW_SCOPE(vm); 256 257 JSObject* object = JSValue::decode(encodedObject).toObject(exec); 258 RETURN_IF_EXCEPTION(scope, nullptr); 259 scope.release(); 260 return ownPropertyKeys(exec, object, PropertyNameMode::Strings, DontEnumPropertiesMode::Exclude); 261 } 262 263 JSArray* JIT_OPERATION operationObjectKeysObject(ExecState* exec, JSObject* object) 264 { 265 VM& vm = exec->vm(); 266 NativeCallFrameTracer tracer(&vm, exec); 267 return ownPropertyKeys(exec, object, PropertyNameMode::Strings, DontEnumPropertiesMode::Exclude); 268 } 269 251 270 JSCell* JIT_OPERATION operationObjectCreate(ExecState* exec, EncodedJSValue encodedPrototype) 252 271 { -
trunk/Source/JavaScriptCore/dfg/DFGOperations.h
r239142 r239153 44 44 JSCell* JIT_OPERATION operationCallObjectConstructor(ExecState*, JSGlobalObject*, EncodedJSValue encodedTarget) WTF_INTERNAL; 45 45 JSCell* JIT_OPERATION operationToObject(ExecState*, JSGlobalObject*, EncodedJSValue encodedTarget, UniquedStringImpl*) WTF_INTERNAL; 46 JSArray* JIT_OPERATION operationObjectKeys(ExecState*, EncodedJSValue) WTF_INTERNAL; 47 JSArray* JIT_OPERATION operationObjectKeysObject(ExecState*, JSObject*) WTF_INTERNAL; 46 48 JSCell* JIT_OPERATION operationObjectCreate(ExecState*, EncodedJSValue) WTF_INTERNAL; 47 49 JSCell* JIT_OPERATION operationObjectCreateObject(ExecState*, JSObject*) WTF_INTERNAL; -
trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
r239142 r239153 976 976 case NewArrayWithSize: 977 977 case CreateRest: 978 case NewArrayBuffer: { 978 case NewArrayBuffer: 979 case ObjectKeys: { 979 980 setPrediction(SpecArray); 980 981 break; -
trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
r239142 r239153 179 179 case CreateThis: 180 180 case ObjectCreate: 181 case ObjectKeys: 181 182 case GetCallee: 182 183 case SetCallee: -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
r239142 r239153 12346 12346 } 12347 12347 12348 void SpeculativeJIT::compileObjectKeys(Node* node) 12349 { 12350 switch (node->child1().useKind()) { 12351 case ObjectUse: { 12352 if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) { 12353 SpeculateCellOperand object(this, node->child1()); 12354 GPRTemporary structure(this); 12355 GPRTemporary scratch(this); 12356 GPRTemporary scratch2(this); 12357 GPRTemporary scratch3(this); 12358 GPRTemporary result(this); 12359 12360 GPRReg objectGPR = object.gpr(); 12361 GPRReg structureGPR = structure.gpr(); 12362 GPRReg scratchGPR = scratch.gpr(); 12363 GPRReg scratch2GPR = scratch2.gpr(); 12364 GPRReg scratch3GPR = scratch3.gpr(); 12365 GPRReg resultGPR = result.gpr(); 12366 12367 speculateObject(node->child1(), objectGPR); 12368 12369 CCallHelpers::JumpList slowCases; 12370 m_jit.emitLoadStructure(*m_jit.vm(), objectGPR, structureGPR, scratchGPR); 12371 m_jit.loadPtr(CCallHelpers::Address(structureGPR, Structure::previousOrRareDataOffset()), scratchGPR); 12372 12373 slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, scratchGPR)); 12374 slowCases.append(m_jit.branch32(CCallHelpers::Equal, CCallHelpers::Address(scratchGPR, JSCell::structureIDOffset()), TrustedImm32(bitwise_cast<int32_t>(m_jit.vm()->structureStructure->structureID())))); 12375 12376 m_jit.loadPtr(CCallHelpers::Address(scratchGPR, StructureRareData::offsetOfCachedOwnKeys()), scratchGPR); 12377 12378 slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, scratchGPR)); 12379 slowCases.append(m_jit.branchPtr(CCallHelpers::Equal, scratchGPR, TrustedImmPtr::weakPointer(m_jit.graph(), m_jit.vm()->sentinelImmutableButterfly.get()))); 12380 12381 MacroAssembler::JumpList slowButArrayBufferCases; 12382 12383 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic); 12384 RegisteredStructure arrayStructure = m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(CopyOnWriteArrayWithContiguous)); 12385 12386 m_jit.move(scratchGPR, scratch3GPR); 12387 m_jit.addPtr(TrustedImmPtr(JSImmutableButterfly::offsetOfData()), scratchGPR); 12388 12389 emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(arrayStructure), scratchGPR, structureGPR, scratch2GPR, slowButArrayBufferCases); 12390 12391 addSlowPathGenerator(slowPathCall(slowButArrayBufferCases, this, operationNewArrayBuffer, resultGPR, arrayStructure, scratch3GPR)); 12392 12393 addSlowPathGenerator(slowPathCall(slowCases, this, operationObjectKeysObject, resultGPR, objectGPR)); 12394 12395 cellResult(resultGPR, node); 12396 break; 12397 } 12398 12399 SpeculateCellOperand object(this, node->child1()); 12400 12401 GPRReg objectGPR = object.gpr(); 12402 12403 speculateObject(node->child1(), objectGPR); 12404 12405 flushRegisters(); 12406 GPRFlushedCallResult result(this); 12407 GPRReg resultGPR = result.gpr(); 12408 callOperation(operationObjectKeysObject, resultGPR, objectGPR); 12409 m_jit.exceptionCheck(); 12410 12411 cellResult(resultGPR, node); 12412 break; 12413 } 12414 12415 case UntypedUse: { 12416 JSValueOperand object(this, node->child1()); 12417 12418 JSValueRegs objectRegs = object.jsValueRegs(); 12419 12420 flushRegisters(); 12421 GPRFlushedCallResult result(this); 12422 GPRReg resultGPR = result.gpr(); 12423 callOperation(operationObjectKeys, resultGPR, objectRegs); 12424 m_jit.exceptionCheck(); 12425 12426 cellResult(resultGPR, node); 12427 break; 12428 } 12429 12430 default: 12431 RELEASE_ASSERT_NOT_REACHED(); 12432 break; 12433 } 12434 } 12435 12348 12436 void SpeculativeJIT::compileObjectCreate(Node* node) 12349 12437 { -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
r239142 r239153 1479 1479 void compileNewTypedArray(Node*); 1480 1480 void compileToThis(Node*); 1481 void compileObjectKeys(Node*); 1481 1482 void compileObjectCreate(Node*); 1482 1483 void compileCreateThis(Node*); -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
r239142 r239153 3160 3160 case ObjectCreate: { 3161 3161 compileObjectCreate(node); 3162 break; 3163 } 3164 3165 case ObjectKeys: { 3166 compileObjectKeys(node); 3162 3167 break; 3163 3168 } -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r239142 r239153 3402 3402 case ObjectCreate: { 3403 3403 compileObjectCreate(node); 3404 break; 3405 } 3406 3407 case ObjectKeys: { 3408 compileObjectKeys(node); 3404 3409 break; 3405 3410 } -
trunk/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h
r239099 r239153 117 117 macro(Structure_indexingModeIncludingHistory, Structure::indexingModeIncludingHistoryOffset()) \ 118 118 macro(Structure_inlineCapacity, Structure::inlineCapacityOffset()) \ 119 macro(Structure_previousOrRareData, Structure::previousOrRareDataOffset()) \ 119 120 macro(Structure_prototype, Structure::prototypeOffset()) \ 120 121 macro(Structure_structureID, Structure::structureIDOffset()) \ 122 macro(StructureRareData_cachedOwnKeys, StructureRareData::offsetOfCachedOwnKeys()) \ 121 123 macro(HashMapImpl_capacity, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfCapacity()) \ 122 124 macro(HashMapImpl_buffer, HashMapImpl<HashMapBucket<HashMapBucketDataKey>>::offsetOfBuffer()) \ -
trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
r239142 r239153 201 201 case CallStringConstructor: 202 202 case ObjectCreate: 203 case ObjectKeys: 203 204 case MakeRope: 204 205 case NewArrayWithSize: -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r239142 r239153 864 864 compileObjectCreate(); 865 865 break; 866 case ObjectKeys: 867 compileObjectKeys(); 868 break; 866 869 case NewObject: 867 870 compileNewObject(); … … 5484 5487 m_out.appendTo(continuation, lastNext); 5485 5488 setInt32(m_out.phi(Int32, zeroLengthResult, nonZeroLengthResult)); 5489 } 5490 5491 void compileObjectKeys() 5492 { 5493 switch (m_node->child1().useKind()) { 5494 case ObjectUse: { 5495 if (m_graph.isWatchingHavingABadTimeWatchpoint(m_node)) { 5496 LBasicBlock notNullCase = m_out.newBlock(); 5497 LBasicBlock rareDataCase = m_out.newBlock(); 5498 LBasicBlock notNullCacheCase = m_out.newBlock(); 5499 LBasicBlock useCacheCase = m_out.newBlock(); 5500 LBasicBlock slowButArrayBufferCase = m_out.newBlock(); 5501 LBasicBlock slowCase = m_out.newBlock(); 5502 LBasicBlock continuation = m_out.newBlock(); 5503 5504 LValue object = lowObject(m_node->child1()); 5505 LValue structure = loadStructure(object); 5506 LValue previousOrRareData = m_out.loadPtr(structure, m_heaps.Structure_previousOrRareData); 5507 m_out.branch(m_out.notNull(previousOrRareData), unsure(notNullCase), unsure(slowCase)); 5508 5509 LBasicBlock lastNext = m_out.appendTo(notNullCase, rareDataCase); 5510 m_out.branch( 5511 m_out.notEqual(m_out.load32(previousOrRareData, m_heaps.JSCell_structureID), m_out.constInt32(m_graph.m_vm.structureStructure->structureID())), 5512 unsure(rareDataCase), unsure(slowCase)); 5513 5514 m_out.appendTo(rareDataCase, notNullCacheCase); 5515 LValue cachedOwnKeys = m_out.loadPtr(previousOrRareData, m_heaps.StructureRareData_cachedOwnKeys); 5516 m_out.branch(m_out.notNull(cachedOwnKeys), unsure(notNullCacheCase), unsure(slowCase)); 5517 5518 m_out.appendTo(notNullCacheCase, useCacheCase); 5519 m_out.branch(m_out.notEqual(cachedOwnKeys, weakPointer(m_graph.m_vm.sentinelImmutableButterfly.get())), unsure(useCacheCase), unsure(slowCase)); 5520 5521 m_out.appendTo(useCacheCase, slowButArrayBufferCase); 5522 JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic); 5523 RegisteredStructure arrayStructure = m_graph.registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(CopyOnWriteArrayWithContiguous)); 5524 LValue fastArray = allocateObject<JSArray>(arrayStructure, m_out.addPtr(cachedOwnKeys, JSImmutableButterfly::offsetOfData()), slowButArrayBufferCase); 5525 ValueFromBlock fastResult = m_out.anchor(fastArray); 5526 m_out.jump(continuation); 5527 5528 m_out.appendTo(slowButArrayBufferCase, slowCase); 5529 LValue slowArray = vmCall(Int64, m_out.operation(operationNewArrayBuffer), m_callFrame, weakStructure(arrayStructure), cachedOwnKeys); 5530 ValueFromBlock slowButArrayBufferResult = m_out.anchor(slowArray); 5531 m_out.jump(continuation); 5532 5533 m_out.appendTo(slowCase, continuation); 5534 VM& vm = this->vm(); 5535 LValue slowResultValue = lazySlowPath( 5536 [=, &vm] (const Vector<Location>& locations) -> RefPtr<LazySlowPath::Generator> { 5537 return createLazyCallGenerator(vm, 5538 operationObjectKeysObject, locations[0].directGPR(), locations[1].directGPR()); 5539 }, 5540 object); 5541 ValueFromBlock slowResult = m_out.anchor(slowResultValue); 5542 m_out.jump(continuation); 5543 5544 m_out.appendTo(continuation, lastNext); 5545 setJSValue(m_out.phi(pointerType(), fastResult, slowButArrayBufferResult, slowResult)); 5546 break; 5547 } 5548 setJSValue(vmCall(Int64, m_out.operation(operationObjectKeysObject), m_callFrame, lowObject(m_node->child1()))); 5549 break; 5550 } 5551 case UntypedUse: 5552 setJSValue(vmCall(Int64, m_out.operation(operationObjectKeys), m_callFrame, lowJSValue(m_node->child1()))); 5553 break; 5554 default: 5555 RELEASE_ASSERT_NOT_REACHED(); 5556 break; 5557 } 5486 5558 } 5487 5559 -
trunk/Source/JavaScriptCore/runtime/Intrinsic.cpp
r235106 r239153 120 120 case ObjectIsIntrinsic: 121 121 return "ObjectIsIntrinsic"; 122 case ObjectKeysIntrinsic: 123 return "ObjectKeysIntrinsic"; 122 124 case ReflectGetPrototypeOfIntrinsic: 123 125 return "ReflectGetPrototypeOfIntrinsic"; -
trunk/Source/JavaScriptCore/runtime/Intrinsic.h
r235106 r239153 73 73 ObjectGetPrototypeOfIntrinsic, 74 74 ObjectIsIntrinsic, 75 ObjectKeysIntrinsic, 75 76 ReflectGetPrototypeOfIntrinsic, 76 77 StringPrototypeValueOfIntrinsic, -
trunk/Source/JavaScriptCore/runtime/JSImmutableButterfly.h
r235972 r239153 68 68 } 69 69 70 static JSImmutableButterfly* createSentinel(VM& vm) 71 { 72 return create(vm, CopyOnWriteArrayWithContiguous, 0); 73 } 74 70 75 unsigned publicLength() const { return m_header.publicLength(); } 71 76 unsigned vectorLength() const { return m_header.vectorLength(); } -
trunk/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
r236791 r239153 31 31 #include "JSGlobalObject.h" 32 32 #include "JSGlobalObjectFunctions.h" 33 #include "JSImmutableButterfly.h" 33 34 #include "Lookup.h" 34 35 #include "ObjectPrototype.h" … … 74 75 getOwnPropertyNames objectConstructorGetOwnPropertyNames DontEnum|Function 1 75 76 getOwnPropertySymbols objectConstructorGetOwnPropertySymbols DontEnum|Function 1 76 keys objectConstructorKeys DontEnum|Function 1 77 keys objectConstructorKeys DontEnum|Function 1 ObjectKeysIntrinsic 77 78 defineProperty objectConstructorDefineProperty DontEnum|Function 3 78 79 defineProperties objectConstructorDefineProperties DontEnum|Function 2 … … 272 273 } 273 274 274 // FIXME: Use the enumeration cache.275 275 EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec) 276 276 { … … 893 893 } 894 894 895 // FIXME: Use the enumeration cache.896 895 JSArray* ownPropertyKeys(ExecState* exec, JSObject* object, PropertyNameMode propertyNameMode, DontEnumPropertiesMode dontEnumPropertiesMode) 897 896 { 898 897 VM& vm = exec->vm(); 899 898 auto scope = DECLARE_THROW_SCOPE(vm); 899 900 auto* globalObject = exec->lexicalGlobalObject(); 901 bool isObjectKeys = propertyNameMode == PropertyNameMode::Strings && dontEnumPropertiesMode == DontEnumPropertiesMode::Exclude; 902 // We attempt to look up own property keys cache in Object.keys case. 903 if (isObjectKeys) { 904 if (LIKELY(!globalObject->isHavingABadTime())) { 905 if (auto* immutableButterfly = object->structure(vm)->cachedOwnKeys()) { 906 if (immutableButterfly != vm.sentinelImmutableButterfly.get()) { 907 Structure* arrayStructure = globalObject->originalArrayStructureForIndexingType(immutableButterfly->indexingMode()); 908 return JSArray::createWithButterfly(vm, nullptr, arrayStructure, immutableButterfly->toButterfly()); 909 } 910 } 911 } 912 } 913 900 914 PropertyNameArray properties(&vm, propertyNameMode, PrivateSymbolMode::Exclude); 901 915 object->methodTable(vm)->getOwnPropertyNames(object, exec, properties, EnumerationMode(dontEnumPropertiesMode)); … … 919 933 ASSERT(propertyNameMode == PropertyNameMode::Strings || propertyNameMode == PropertyNameMode::Symbols); 920 934 if (!mustFilterProperty && properties.size() < MIN_SPARSE_ARRAY_INDEX) { 921 auto* globalObject = exec->lexicalGlobalObject();922 935 if (LIKELY(!globalObject->isHavingABadTime())) { 936 if (isObjectKeys) { 937 Structure* structure = object->structure(vm); 938 if (structure->canCacheOwnKeys()) { 939 auto* cachedButterfly = structure->cachedOwnKeys(); 940 if (cachedButterfly == vm.sentinelImmutableButterfly.get()) { 941 // Cache the immutable butterfly! 942 size_t numProperties = properties.size(); 943 auto* newButterfly = JSImmutableButterfly::create(vm, CopyOnWriteArrayWithContiguous, numProperties); 944 for (size_t i = 0; i < numProperties; i++) { 945 const auto& identifier = properties[i]; 946 ASSERT(!identifier.isSymbol()); 947 newButterfly->setIndex(vm, i, jsOwnedString(&vm, identifier.string())); 948 } 949 950 structure->setCachedOwnKeys(vm, newButterfly); 951 Structure* arrayStructure = globalObject->originalArrayStructureForIndexingType(newButterfly->indexingMode()); 952 return JSArray::createWithButterfly(vm, nullptr, arrayStructure, newButterfly->toButterfly()); 953 } 954 955 if (cachedButterfly == nullptr) 956 structure->setCachedOwnKeys(vm, jsCast<JSImmutableButterfly*>(vm.sentinelImmutableButterfly.get())); 957 } 958 } 959 923 960 size_t numProperties = properties.size(); 924 961 JSArray* keys = JSArray::create(vm, globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous), numProperties); -
trunk/Source/JavaScriptCore/runtime/Structure.cpp
r234284 r239153 1253 1253 bool Structure::canCachePropertyNameEnumerator() const 1254 1254 { 1255 auto canCache = [] (const Structure* structure) { 1256 if (structure->isDictionary()) 1257 return false; 1258 if (hasIndexedProperties(structure->indexingType())) 1259 return false; 1260 if (structure->typeInfo().overridesGetPropertyNames()) 1261 return false; 1262 return true; 1263 }; 1264 1265 if (!canCache(this)) 1255 if (!this->canCacheOwnKeys()) 1266 1256 return false; 1267 1257 … … 1272 1262 if (!structure->get()) 1273 1263 return true; 1274 if (! canCache(structure->get()))1264 if (!structure->get()->canCacheOwnKeys()) 1275 1265 return false; 1276 1266 structure++; -
trunk/Source/JavaScriptCore/runtime/Structure.h
r238392 r239153 39 39 #include "StructureIDBlob.h" 40 40 #include "StructureRareData.h" 41 #include "StructureRareDataInlines.h"42 41 #include "StructureTransitionTable.h" 43 42 #include "JSTypeInfo.h" … … 327 326 } 328 327 328 const StructureRareData* rareDataConcurrently() const 329 { 330 JSCell* cell = m_previousOrRareData.get(); 331 WTF::loadLoadFence(); 332 if (isRareData(cell)) 333 return static_cast<StructureRareData*>(cell); 334 return nullptr; 335 } 336 329 337 StructureRareData* ensureRareData(VM& vm) 330 338 { … … 473 481 bool canAccessPropertiesQuicklyForEnumeration() const; 474 482 483 void setCachedOwnKeys(VM&, JSImmutableButterfly*); 484 JSImmutableButterfly* cachedOwnKeys() const; 485 bool canCacheOwnKeys() const; 486 475 487 void getPropertyNamesFromStructure(VM&, PropertyNameArray&, EnumerationMode); 476 488 … … 519 531 { 520 532 return OBJECT_OFFSETOF(Structure, m_inlineCapacity); 533 } 534 535 static ptrdiff_t previousOrRareDataOffset() 536 { 537 return OBJECT_OFFSETOF(Structure, m_previousOrRareData); 521 538 } 522 539 -
trunk/Source/JavaScriptCore/runtime/StructureInlines.h
r238366 r239153 220 220 } 221 221 222 inline void Structure::setCachedOwnKeys(VM& vm, JSImmutableButterfly* ownKeys) 223 { 224 ensureRareData(vm)->setCachedOwnKeys(vm, ownKeys); 225 } 226 227 inline JSImmutableButterfly* Structure::cachedOwnKeys() const 228 { 229 if (!hasRareData()) 230 return nullptr; 231 return rareData()->cachedOwnKeys(); 232 } 233 234 inline bool Structure::canCacheOwnKeys() const 235 { 236 if (isDictionary()) 237 return false; 238 if (hasIndexedProperties(indexingType())) 239 return false; 240 if (typeInfo().overridesGetPropertyNames()) 241 return false; 242 return true; 243 } 244 222 245 ALWAYS_INLINE JSValue prototypeForLookupPrimitiveImpl(JSGlobalObject* globalObject, const Structure* structure) 223 246 { -
trunk/Source/JavaScriptCore/runtime/StructureRareData.cpp
r233245 r239153 28 28 29 29 #include "AdaptiveInferredPropertyValueWatchpointBase.h" 30 #include "JSImmutableButterfly.h" 30 31 #include "JSPropertyNameEnumerator.h" 31 32 #include "JSString.h" … … 71 72 visitor.append(thisObject->m_objectToStringValue); 72 73 visitor.append(thisObject->m_cachedPropertyNameEnumerator); 73 } 74 75 JSPropertyNameEnumerator* StructureRareData::cachedPropertyNameEnumerator() const 76 { 77 return m_cachedPropertyNameEnumerator.get(); 78 } 79 80 void StructureRareData::setCachedPropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator) 81 { 82 m_cachedPropertyNameEnumerator.set(vm, this, enumerator); 74 visitor.append(thisObject->m_cachedOwnKeys); 83 75 } 84 76 -
trunk/Source/JavaScriptCore/runtime/StructureRareData.h
r228500 r239153 59 59 static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype); 60 60 61 Structure* previousID() const; 61 Structure* previousID() const 62 { 63 return m_previous.get(); 64 } 62 65 void setPreviousID(VM&, Structure*); 63 66 void clearPreviousID(); … … 69 72 void setCachedPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*); 70 73 74 JSImmutableButterfly* cachedOwnKeys() const; 75 JSImmutableButterfly* cachedOwnKeysConcurrently() const; 76 void setCachedOwnKeys(VM&, JSImmutableButterfly*); 77 71 78 Box<InlineWatchpointSet> copySharedPolyProtoWatchpoint() const { return m_polyProtoWatchpoint; } 72 79 const Box<InlineWatchpointSet>& sharedPolyProtoWatchpoint() const { return m_polyProtoWatchpoint; } 73 80 void setSharedPolyProtoWatchpoint(Box<InlineWatchpointSet>&& sharedPolyProtoWatchpoint) { m_polyProtoWatchpoint = WTFMove(sharedPolyProtoWatchpoint); } 74 81 bool hasSharedPolyProtoWatchpoint() const { return static_cast<bool>(m_polyProtoWatchpoint); } 82 83 static ptrdiff_t offsetOfCachedOwnKeys() 84 { 85 return OBJECT_OFFSETOF(StructureRareData, m_cachedOwnKeys); 86 } 75 87 76 88 DECLARE_EXPORT_INFO; … … 87 99 WriteBarrier<Structure> m_previous; 88 100 WriteBarrier<JSString> m_objectToStringValue; 101 // FIXME: We should have some story for clearing these property names caches in GC. 102 // https://bugs.webkit.org/show_bug.cgi?id=192659 89 103 WriteBarrier<JSPropertyNameEnumerator> m_cachedPropertyNameEnumerator; 104 WriteBarrier<JSImmutableButterfly> m_cachedOwnKeys; 90 105 91 106 typedef HashMap<PropertyOffset, RefPtr<WatchpointSet>, WTF::IntHash<PropertyOffset>, WTF::UnsignedWithZeroKeyHashTraits<PropertyOffset>> PropertyWatchpointMap; -
trunk/Source/JavaScriptCore/runtime/StructureRareDataInlines.h
r206525 r239153 26 26 #pragma once 27 27 28 #include "JSImmutableButterfly.h" 29 #include "JSPropertyNameEnumerator.h" 28 30 #include "JSString.h" 29 31 #include "StructureRareData.h" 30 32 31 33 namespace JSC { 32 33 inline Structure* StructureRareData::previousID() const34 {35 return m_previous.get();36 }37 34 38 35 inline void StructureRareData::setPreviousID(VM& vm, Structure* structure) … … 51 48 } 52 49 50 inline JSPropertyNameEnumerator* StructureRareData::cachedPropertyNameEnumerator() const 51 { 52 return m_cachedPropertyNameEnumerator.get(); 53 } 54 55 inline void StructureRareData::setCachedPropertyNameEnumerator(VM& vm, JSPropertyNameEnumerator* enumerator) 56 { 57 m_cachedPropertyNameEnumerator.set(vm, this, enumerator); 58 } 59 60 inline JSImmutableButterfly* StructureRareData::cachedOwnKeys() const 61 { 62 ASSERT(!compilationOrGCThread()) 63 return m_cachedOwnKeys.get(); 64 } 65 66 inline JSImmutableButterfly* StructureRareData::cachedOwnKeysConcurrently() const 67 { 68 auto* result = m_cachedOwnKeys.get(); 69 WTF::loadLoadFence(); 70 return result; 71 } 72 73 inline void StructureRareData::setCachedOwnKeys(VM& vm, JSImmutableButterfly* butterfly) 74 { 75 WTF::storeStoreFence(); 76 m_cachedOwnKeys.set(vm, this, butterfly); 77 } 78 53 79 } // namespace JSC -
trunk/Source/JavaScriptCore/runtime/VM.cpp
r238162 r239153 435 435 promiseDeferredStructure.set(*this, JSPromiseDeferred::createStructure(*this, 0, jsNull())); 436 436 internalPromiseDeferredStructure.set(*this, JSInternalPromiseDeferred::createStructure(*this, 0, jsNull())); 437 nativeStdFunctionCellStructure.set(*this, NativeStdFunctionCell::createStructure(*this, 0, jsNull())); 437 438 programCodeBlockStructure.set(*this, ProgramCodeBlock::createStructure(*this, 0, jsNull())); 438 439 moduleProgramCodeBlockStructure.set(*this, ModuleProgramCodeBlock::createStructure(*this, 0, jsNull())); … … 448 449 sentinelSetBucket.set(*this, JSSet::BucketType::createSentinel(*this)); 449 450 sentinelMapBucket.set(*this, JSMap::BucketType::createSentinel(*this)); 450 451 nativeStdFunctionCellStructure.set(*this, NativeStdFunctionCell::createStructure(*this, 0, jsNull())); 451 sentinelImmutableButterfly.set(*this, JSImmutableButterfly::createSentinel(*this)); 452 452 453 smallStrings.initializeCommonStrings(*this); 453 454 -
trunk/Source/JavaScriptCore/runtime/VM.h
r238162 r239153 572 572 Strong<JSCell> sentinelSetBucket; 573 573 Strong<JSCell> sentinelMapBucket; 574 Strong<JSCell> sentinelImmutableButterfly; 574 575 575 576 std::unique_ptr<PromiseDeferredTimer> promiseDeferredTimer;
Note: See TracChangeset
for help on using the changeset viewer.