Changeset 239324 in webkit
- Timestamp:
- Dec 17, 2018 10:54:49 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 6 added
- 34 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r239304 r239324 1 2018-12-16 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 Saam Barati. 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-17 Mark Lam <mark.lam@apple.com> 2 29 -
trunk/Source/JavaScriptCore/ChangeLog
r239304 r239324 1 2018-12-16 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 Saam Barati. 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/Butterfly.h: 65 (JSC::ContiguousData::Data::setStartingValue): 66 * runtime/Intrinsic.cpp: 67 (JSC::intrinsicName): 68 * runtime/Intrinsic.h: 69 * runtime/JSImmutableButterfly.h: 70 (JSC::JSImmutableButterfly::JSImmutableButterfly): 71 We set JSEmpty to the underlying butterfly storage if indexing type is Contiguous. 72 Otherwise, JSImmutableButterfly is half-baked one until all the storage is filled with some meaningful values, it leads to crash 73 if half-baked JSImmutableButterfly is exposed to GC. 74 * runtime/ObjectConstructor.cpp: 75 (JSC::ownPropertyKeys): 76 * runtime/Structure.cpp: 77 (JSC::Structure::canCachePropertyNameEnumerator const): 78 * runtime/Structure.h: 79 * runtime/StructureInlines.h: 80 (JSC::Structure::setCachedOwnKeys): 81 (JSC::Structure::cachedOwnKeys const): 82 (JSC::Structure::cachedOwnKeysIgnoringSentinel const): 83 (JSC::Structure::canCacheOwnKeys const): 84 * runtime/StructureRareData.cpp: 85 (JSC::StructureRareData::visitChildren): 86 (JSC::StructureRareData::cachedPropertyNameEnumerator const): Deleted. 87 (JSC::StructureRareData::setCachedPropertyNameEnumerator): Deleted. 88 * runtime/StructureRareData.h: 89 * runtime/StructureRareDataInlines.h: 90 (JSC::StructureRareData::cachedPropertyNameEnumerator const): 91 (JSC::StructureRareData::setCachedPropertyNameEnumerator): 92 (JSC::StructureRareData::cachedOwnKeys const): 93 (JSC::StructureRareData::cachedOwnKeysIgnoringSentinel const): 94 (JSC::StructureRareData::cachedOwnKeysConcurrently const): 95 (JSC::StructureRareData::setCachedOwnKeys): 96 (JSC::StructureRareData::previousID const): Deleted. 97 * runtime/VM.cpp: 98 (JSC::VM::VM): 99 1 100 2018-12-17 Mark Lam <mark.lam@apple.com> 2 101 -
trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
r239231 r239324 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> … … 2578 2579 clobberWorld(); 2579 2580 setTypeForNode(node, SpecFinalObject); 2581 break; 2582 } 2583 2584 case ObjectKeys: { 2585 if (node->child1().useKind() == ObjectUse) { 2586 auto& structureSet = forNode(node->child1()).m_structure; 2587 if (structureSet.isFinite() && structureSet.size() == 1) { 2588 RegisteredStructure structure = structureSet.onlyStructure(); 2589 if (auto* rareData = structure->rareDataConcurrently()) { 2590 if (auto* immutableButterfly = rareData->cachedOwnKeysConcurrently()) { 2591 if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) { 2592 m_state.setFoundConstants(true); 2593 didFoldClobberWorld(); 2594 setTypeForNode(node, SpecArray); 2595 break; 2596 } 2597 } 2598 } 2599 } 2600 } 2601 2602 clobberWorld(); 2603 setTypeForNode(node, SpecArray); 2580 2604 break; 2581 2605 } -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r239231 r239324 2690 2690 insertChecks(); 2691 2691 set(result, addToGraph(SameValue, get(virtualRegisterForArgument(1, registerOffset)), get(virtualRegisterForArgument(2, registerOffset)))); 2692 return true; 2693 } 2694 2695 case ObjectKeysIntrinsic: { 2696 if (argumentCountIncludingThis < 2) 2697 return false; 2698 2699 insertChecks(); 2700 set(result, addToGraph(ObjectKeys, get(virtualRegisterForArgument(1, registerOffset)))); 2692 2701 return true; 2693 2702 } -
trunk/Source/JavaScriptCore/dfg/DFGClobberize.h
r239231 r239324 669 669 case InstanceOf: 670 670 case StringValueOf: 671 case ObjectKeys: 671 672 read(World); 672 673 write(Heap); … … 1529 1530 } 1530 1531 } 1531 1532 1532 1533 1533 case NewObject: -
trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
r239231 r239324 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 if (auto* immutableButterfly = rareData->cachedOwnKeysConcurrently()) { 776 if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) { 777 node->convertToNewArrayBuffer(m_graph.freeze(immutableButterfly)); 778 changed = true; 779 break; 780 } 781 } 782 } 783 } 784 } 785 break; 786 } 787 769 788 case ToNumber: { 770 789 if (m_state.forNode(node->child1()).m_type & ~SpecBytecodeNumber) -
trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp
r239231 r239324 340 340 case CreateThis: 341 341 case ObjectCreate: 342 case ObjectKeys: 342 343 case AllocatePropertyStorage: 343 344 case ReallocatePropertyStorage: -
trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
r239287 r239324 1592 1592 node->clearFlags(NodeMustGenerate); 1593 1593 break; 1594 } 1595 break; 1596 } 1597 1598 case ObjectKeys: { 1599 if (node->child1()->shouldSpeculateObject()) { 1600 watchHavingABadTime(node); 1601 fixEdge<ObjectUse>(node->child1()); 1594 1602 } 1595 1603 break; -
trunk/Source/JavaScriptCore/dfg/DFGNode.cpp
r239231 r239324 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
r239231 r239324 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
r239231 r239324 266 266 macro(GetPrototypeOf, NodeMustGenerate | NodeResultJS) \ 267 267 macro(ObjectCreate, NodeMustGenerate | NodeResultJS) \ 268 macro(ObjectKeys, NodeMustGenerate | NodeResultJS) \ 268 269 \ 269 270 /* Atomics object functions. */\ -
trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp
r239231 r239324 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
r239231 r239324 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
r239231 r239324 985 985 case NewArrayWithSize: 986 986 case CreateRest: 987 case NewArrayBuffer: { 987 case NewArrayBuffer: 988 case ObjectKeys: { 988 989 setPrediction(SpecArray); 989 990 break; -
trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
r239231 r239324 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
r239231 r239324 12366 12366 } 12367 12367 12368 void SpeculativeJIT::compileObjectKeys(Node* node) 12369 { 12370 switch (node->child1().useKind()) { 12371 case ObjectUse: { 12372 if (m_graph.isWatchingHavingABadTimeWatchpoint(node)) { 12373 SpeculateCellOperand object(this, node->child1()); 12374 GPRTemporary structure(this); 12375 GPRTemporary scratch(this); 12376 GPRTemporary scratch2(this); 12377 GPRTemporary scratch3(this); 12378 GPRTemporary result(this); 12379 12380 GPRReg objectGPR = object.gpr(); 12381 GPRReg structureGPR = structure.gpr(); 12382 GPRReg scratchGPR = scratch.gpr(); 12383 GPRReg scratch2GPR = scratch2.gpr(); 12384 GPRReg scratch3GPR = scratch3.gpr(); 12385 GPRReg resultGPR = result.gpr(); 12386 12387 speculateObject(node->child1(), objectGPR); 12388 12389 CCallHelpers::JumpList slowCases; 12390 m_jit.emitLoadStructure(*m_jit.vm(), objectGPR, structureGPR, scratchGPR); 12391 m_jit.loadPtr(CCallHelpers::Address(structureGPR, Structure::previousOrRareDataOffset()), scratchGPR); 12392 12393 slowCases.append(m_jit.branchTestPtr(CCallHelpers::Zero, scratchGPR)); 12394 slowCases.append(m_jit.branch32(CCallHelpers::Equal, CCallHelpers::Address(scratchGPR, JSCell::structureIDOffset()), TrustedImm32(bitwise_cast<int32_t>(m_jit.vm()->structureStructure->structureID())))); 12395 12396 m_jit.loadPtr(CCallHelpers::Address(scratchGPR, StructureRareData::offsetOfCachedOwnKeys()), scratchGPR); 12397 12398 ASSERT(bitwise_cast<uintptr_t>(StructureRareData::cachedOwnKeysSentinel()) == 1); 12399 slowCases.append(m_jit.branchPtr(CCallHelpers::BelowOrEqual, scratchGPR, TrustedImmPtr(bitwise_cast<void*>(StructureRareData::cachedOwnKeysSentinel())))); 12400 12401 MacroAssembler::JumpList slowButArrayBufferCases; 12402 12403 JSGlobalObject* globalObject = m_jit.graph().globalObjectFor(node->origin.semantic); 12404 RegisteredStructure arrayStructure = m_jit.graph().registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(CopyOnWriteArrayWithContiguous)); 12405 12406 m_jit.move(scratchGPR, scratch3GPR); 12407 m_jit.addPtr(TrustedImmPtr(JSImmutableButterfly::offsetOfData()), scratchGPR); 12408 12409 emitAllocateJSObject<JSArray>(resultGPR, TrustedImmPtr(arrayStructure), scratchGPR, structureGPR, scratch2GPR, slowButArrayBufferCases); 12410 12411 addSlowPathGenerator(slowPathCall(slowButArrayBufferCases, this, operationNewArrayBuffer, resultGPR, arrayStructure, scratch3GPR)); 12412 12413 addSlowPathGenerator(slowPathCall(slowCases, this, operationObjectKeysObject, resultGPR, objectGPR)); 12414 12415 cellResult(resultGPR, node); 12416 break; 12417 } 12418 12419 SpeculateCellOperand object(this, node->child1()); 12420 12421 GPRReg objectGPR = object.gpr(); 12422 12423 speculateObject(node->child1(), objectGPR); 12424 12425 flushRegisters(); 12426 GPRFlushedCallResult result(this); 12427 GPRReg resultGPR = result.gpr(); 12428 callOperation(operationObjectKeysObject, resultGPR, objectGPR); 12429 m_jit.exceptionCheck(); 12430 12431 cellResult(resultGPR, node); 12432 break; 12433 } 12434 12435 case UntypedUse: { 12436 JSValueOperand object(this, node->child1()); 12437 12438 JSValueRegs objectRegs = object.jsValueRegs(); 12439 12440 flushRegisters(); 12441 GPRFlushedCallResult result(this); 12442 GPRReg resultGPR = result.gpr(); 12443 callOperation(operationObjectKeys, resultGPR, objectRegs); 12444 m_jit.exceptionCheck(); 12445 12446 cellResult(resultGPR, node); 12447 break; 12448 } 12449 12450 default: 12451 RELEASE_ASSERT_NOT_REACHED(); 12452 break; 12453 } 12454 } 12455 12368 12456 void SpeculativeJIT::compileObjectCreate(Node* node) 12369 12457 { -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
r239231 r239324 1480 1480 void compileNewTypedArray(Node*); 1481 1481 void compileToThis(Node*); 1482 void compileObjectKeys(Node*); 1482 1483 void compileObjectCreate(Node*); 1483 1484 void compileCreateThis(Node*); -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
r239231 r239324 3165 3165 case ObjectCreate: { 3166 3166 compileObjectCreate(node); 3167 break; 3168 } 3169 3170 case ObjectKeys: { 3171 compileObjectKeys(node); 3167 3172 break; 3168 3173 } -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r239255 r239324 3407 3407 case ObjectCreate: { 3408 3408 compileObjectCreate(node); 3409 break; 3410 } 3411 3412 case ObjectKeys: { 3413 compileObjectKeys(node); 3409 3414 break; 3410 3415 } -
trunk/Source/JavaScriptCore/ftl/FTLAbstractHeapRepository.h
r239231 r239324 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
r239231 r239324 202 202 case CallStringConstructor: 203 203 case ObjectCreate: 204 case ObjectKeys: 204 205 case MakeRope: 205 206 case NewArrayWithSize: -
trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
r239231 r239324 867 867 compileObjectCreate(); 868 868 break; 869 case ObjectKeys: 870 compileObjectKeys(); 871 break; 869 872 case NewObject: 870 873 compileNewObject(); … … 5496 5499 m_out.appendTo(continuation, lastNext); 5497 5500 setInt32(m_out.phi(Int32, zeroLengthResult, nonZeroLengthResult)); 5501 } 5502 5503 void compileObjectKeys() 5504 { 5505 switch (m_node->child1().useKind()) { 5506 case ObjectUse: { 5507 if (m_graph.isWatchingHavingABadTimeWatchpoint(m_node)) { 5508 LBasicBlock notNullCase = m_out.newBlock(); 5509 LBasicBlock rareDataCase = m_out.newBlock(); 5510 LBasicBlock useCacheCase = m_out.newBlock(); 5511 LBasicBlock slowButArrayBufferCase = m_out.newBlock(); 5512 LBasicBlock slowCase = m_out.newBlock(); 5513 LBasicBlock continuation = m_out.newBlock(); 5514 5515 LValue object = lowObject(m_node->child1()); 5516 LValue structure = loadStructure(object); 5517 LValue previousOrRareData = m_out.loadPtr(structure, m_heaps.Structure_previousOrRareData); 5518 m_out.branch(m_out.notNull(previousOrRareData), unsure(notNullCase), unsure(slowCase)); 5519 5520 LBasicBlock lastNext = m_out.appendTo(notNullCase, rareDataCase); 5521 m_out.branch( 5522 m_out.notEqual(m_out.load32(previousOrRareData, m_heaps.JSCell_structureID), m_out.constInt32(m_graph.m_vm.structureStructure->structureID())), 5523 unsure(rareDataCase), unsure(slowCase)); 5524 5525 m_out.appendTo(rareDataCase, useCacheCase); 5526 ASSERT(bitwise_cast<uintptr_t>(StructureRareData::cachedOwnKeysSentinel()) == 1); 5527 LValue cachedOwnKeys = m_out.loadPtr(previousOrRareData, m_heaps.StructureRareData_cachedOwnKeys); 5528 m_out.branch(m_out.belowOrEqual(cachedOwnKeys, m_out.constIntPtr(bitwise_cast<void*>(StructureRareData::cachedOwnKeysSentinel()))), unsure(slowCase), unsure(useCacheCase)); 5529 5530 m_out.appendTo(useCacheCase, slowButArrayBufferCase); 5531 JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic); 5532 RegisteredStructure arrayStructure = m_graph.registerStructure(globalObject->arrayStructureForIndexingTypeDuringAllocation(CopyOnWriteArrayWithContiguous)); 5533 LValue fastArray = allocateObject<JSArray>(arrayStructure, m_out.addPtr(cachedOwnKeys, JSImmutableButterfly::offsetOfData()), slowButArrayBufferCase); 5534 ValueFromBlock fastResult = m_out.anchor(fastArray); 5535 m_out.jump(continuation); 5536 5537 m_out.appendTo(slowButArrayBufferCase, slowCase); 5538 LValue slowArray = vmCall(Int64, m_out.operation(operationNewArrayBuffer), m_callFrame, weakStructure(arrayStructure), cachedOwnKeys); 5539 ValueFromBlock slowButArrayBufferResult = m_out.anchor(slowArray); 5540 m_out.jump(continuation); 5541 5542 m_out.appendTo(slowCase, continuation); 5543 VM& vm = this->vm(); 5544 LValue slowResultValue = lazySlowPath( 5545 [=, &vm] (const Vector<Location>& locations) -> RefPtr<LazySlowPath::Generator> { 5546 return createLazyCallGenerator(vm, 5547 operationObjectKeysObject, locations[0].directGPR(), locations[1].directGPR()); 5548 }, 5549 object); 5550 ValueFromBlock slowResult = m_out.anchor(slowResultValue); 5551 m_out.jump(continuation); 5552 5553 m_out.appendTo(continuation, lastNext); 5554 setJSValue(m_out.phi(pointerType(), fastResult, slowButArrayBufferResult, slowResult)); 5555 break; 5556 } 5557 setJSValue(vmCall(Int64, m_out.operation(operationObjectKeysObject), m_callFrame, lowObject(m_node->child1()))); 5558 break; 5559 } 5560 case UntypedUse: 5561 setJSValue(vmCall(Int64, m_out.operation(operationObjectKeys), m_callFrame, lowJSValue(m_node->child1()))); 5562 break; 5563 default: 5564 RELEASE_ASSERT_NOT_REACHED(); 5565 break; 5566 } 5498 5567 } 5499 5568 -
trunk/Source/JavaScriptCore/runtime/Butterfly.h
r232951 r239324 86 86 } 87 87 88 void setStartingValue(JSValue value) 89 { 90 m_data.setStartingValue(value); 91 } 92 88 93 void clear() 89 94 { -
trunk/Source/JavaScriptCore/runtime/Intrinsic.cpp
r239231 r239324 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
r239231 r239324 73 73 ObjectGetPrototypeOfIntrinsic, 74 74 ObjectIsIntrinsic, 75 ObjectKeysIntrinsic, 75 76 ReflectGetPrototypeOfIntrinsic, 76 77 StringPrototypeValueOfIntrinsic, -
trunk/Source/JavaScriptCore/runtime/JSImmutableButterfly.h
r239231 r239324 121 121 m_header.setVectorLength(length); 122 122 m_header.setPublicLength(length); 123 if (hasContiguous(indexingType())) { 124 for (unsigned index = 0; index < length; ++index) 125 toButterfly()->contiguous().at(this, index).setStartingValue(JSValue()); 126 } 123 127 } 124 128 -
trunk/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
r239231 r239324 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 Structure* arrayStructure = globalObject->originalArrayStructureForIndexingType(immutableButterfly->indexingMode()); 907 return JSArray::createWithButterfly(vm, nullptr, arrayStructure, immutableButterfly->toButterfly()); 908 } 909 } 910 } 911 900 912 PropertyNameArray properties(&vm, propertyNameMode, PrivateSymbolMode::Exclude); 901 913 object->methodTable(vm)->getOwnPropertyNames(object, exec, properties, EnumerationMode(dontEnumPropertiesMode)); … … 919 931 ASSERT(propertyNameMode == PropertyNameMode::Strings || propertyNameMode == PropertyNameMode::Symbols); 920 932 if (!mustFilterProperty && properties.size() < MIN_SPARSE_ARRAY_INDEX) { 921 auto* globalObject = exec->lexicalGlobalObject();922 933 if (LIKELY(!globalObject->isHavingABadTime())) { 934 if (isObjectKeys) { 935 Structure* structure = object->structure(vm); 936 if (structure->canCacheOwnKeys()) { 937 auto* cachedButterfly = structure->cachedOwnKeysIgnoringSentinel(); 938 if (cachedButterfly == StructureRareData::cachedOwnKeysSentinel()) { 939 size_t numProperties = properties.size(); 940 auto* newButterfly = JSImmutableButterfly::create(vm, CopyOnWriteArrayWithContiguous, numProperties); 941 for (size_t i = 0; i < numProperties; i++) { 942 const auto& identifier = properties[i]; 943 ASSERT(!identifier.isSymbol()); 944 newButterfly->setIndex(vm, i, jsOwnedString(&vm, identifier.string())); 945 } 946 947 structure->setCachedOwnKeys(vm, newButterfly); 948 Structure* arrayStructure = globalObject->originalArrayStructureForIndexingType(newButterfly->indexingMode()); 949 return JSArray::createWithButterfly(vm, nullptr, arrayStructure, newButterfly->toButterfly()); 950 } 951 952 if (cachedButterfly == nullptr) 953 structure->setCachedOwnKeys(vm, StructureRareData::cachedOwnKeysSentinel()); 954 } 955 } 956 923 957 size_t numProperties = properties.size(); 924 958 JSArray* keys = JSArray::create(vm, globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous), numProperties); -
trunk/Source/JavaScriptCore/runtime/Structure.cpp
r239231 r239324 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
r239231 r239324 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 if (isRareData(cell)) 332 return static_cast<StructureRareData*>(cell); 333 return nullptr; 334 } 335 329 336 StructureRareData* ensureRareData(VM& vm) 330 337 { … … 473 480 bool canAccessPropertiesQuicklyForEnumeration() const; 474 481 482 void setCachedOwnKeys(VM&, JSImmutableButterfly*); 483 JSImmutableButterfly* cachedOwnKeys() const; 484 JSImmutableButterfly* cachedOwnKeysIgnoringSentinel() 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
r239231 r239324 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 JSImmutableButterfly* Structure::cachedOwnKeysIgnoringSentinel() const 235 { 236 if (!hasRareData()) 237 return nullptr; 238 return rareData()->cachedOwnKeysIgnoringSentinel(); 239 } 240 241 inline bool Structure::canCacheOwnKeys() const 242 { 243 if (isDictionary()) 244 return false; 245 if (hasIndexedProperties(indexingType())) 246 return false; 247 if (typeInfo().overridesGetPropertyNames()) 248 return false; 249 return true; 250 } 251 222 252 ALWAYS_INLINE JSValue prototypeForLookupPrimitiveImpl(JSGlobalObject* globalObject, const Structure* structure) 223 253 { -
trunk/Source/JavaScriptCore/runtime/StructureRareData.cpp
r239231 r239324 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 if (thisObject->m_cachedOwnKeys.unvalidatedGet() != cachedOwnKeysSentinel()) 75 visitor.append(thisObject->m_cachedOwnKeys); 83 76 } 84 77 -
trunk/Source/JavaScriptCore/runtime/StructureRareData.h
r239231 r239324 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* cachedOwnKeysIgnoringSentinel() const; 76 JSImmutableButterfly* cachedOwnKeysConcurrently() const; 77 void setCachedOwnKeys(VM&, JSImmutableButterfly*); 78 71 79 Box<InlineWatchpointSet> copySharedPolyProtoWatchpoint() const { return m_polyProtoWatchpoint; } 72 80 const Box<InlineWatchpointSet>& sharedPolyProtoWatchpoint() const { return m_polyProtoWatchpoint; } 73 81 void setSharedPolyProtoWatchpoint(Box<InlineWatchpointSet>&& sharedPolyProtoWatchpoint) { m_polyProtoWatchpoint = WTFMove(sharedPolyProtoWatchpoint); } 74 82 bool hasSharedPolyProtoWatchpoint() const { return static_cast<bool>(m_polyProtoWatchpoint); } 83 84 static JSImmutableButterfly* cachedOwnKeysSentinel() { return bitwise_cast<JSImmutableButterfly*>(static_cast<uintptr_t>(1)); } 85 86 static ptrdiff_t offsetOfCachedOwnKeys() 87 { 88 return OBJECT_OFFSETOF(StructureRareData, m_cachedOwnKeys); 89 } 75 90 76 91 DECLARE_EXPORT_INFO; … … 87 102 WriteBarrier<Structure> m_previous; 88 103 WriteBarrier<JSString> m_objectToStringValue; 104 // FIXME: We should have some story for clearing these property names caches in GC. 105 // https://bugs.webkit.org/show_bug.cgi?id=192659 89 106 WriteBarrier<JSPropertyNameEnumerator> m_cachedPropertyNameEnumerator; 107 WriteBarrier<JSImmutableButterfly> m_cachedOwnKeys; 90 108 91 109 typedef HashMap<PropertyOffset, RefPtr<WatchpointSet>, WTF::IntHash<PropertyOffset>, WTF::UnsignedWithZeroKeyHashTraits<PropertyOffset>> PropertyWatchpointMap; -
trunk/Source/JavaScriptCore/runtime/StructureRareDataInlines.h
r239231 r239324 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(!isCompilationThread()); 63 auto* butterfly = m_cachedOwnKeys.unvalidatedGet(); 64 if (butterfly == cachedOwnKeysSentinel()) 65 return nullptr; 66 return butterfly; 67 } 68 69 inline JSImmutableButterfly* StructureRareData::cachedOwnKeysIgnoringSentinel() const 70 { 71 ASSERT(!isCompilationThread()); 72 return m_cachedOwnKeys.unvalidatedGet(); 73 } 74 75 inline JSImmutableButterfly* StructureRareData::cachedOwnKeysConcurrently() const 76 { 77 auto* butterfly = m_cachedOwnKeys.unvalidatedGet(); 78 if (butterfly == cachedOwnKeysSentinel()) 79 return nullptr; 80 return butterfly; 81 } 82 83 inline void StructureRareData::setCachedOwnKeys(VM& vm, JSImmutableButterfly* butterfly) 84 { 85 if (butterfly == cachedOwnKeysSentinel()) { 86 m_cachedOwnKeys.setWithoutWriteBarrier(butterfly); 87 return; 88 } 89 90 WTF::storeStoreFence(); 91 m_cachedOwnKeys.set(vm, this, butterfly); 92 } 93 53 94 } // namespace JSC -
trunk/Source/JavaScriptCore/runtime/VM.cpp
r239231 r239324 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())); … … 449 450 sentinelMapBucket.set(*this, JSMap::BucketType::createSentinel(*this)); 450 451 451 nativeStdFunctionCellStructure.set(*this, NativeStdFunctionCell::createStructure(*this, 0, jsNull()));452 452 smallStrings.initializeCommonStrings(*this); 453 453
Note: See TracChangeset
for help on using the changeset viewer.