|
Lines 725-730
private:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec1
|
| 725 |
case ToIndexString: |
725 |
case ToIndexString: |
| 726 |
compileToIndexString(); |
726 |
compileToIndexString(); |
| 727 |
break; |
727 |
break; |
|
|
728 |
case CheckStructureImmediate: |
| 729 |
compileCheckStructureImmediate(); |
| 730 |
break; |
| 731 |
case MaterializeNewObject: |
| 732 |
compileMaterializeNewObject(); |
| 733 |
break; |
| 728 |
|
734 |
|
| 729 |
case PhantomLocal: |
735 |
case PhantomLocal: |
| 730 |
case SetArgument: |
736 |
case SetArgument: |
|
Lines 735-740
private:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec2
|
| 735 |
case AllocationProfileWatchpoint: |
741 |
case AllocationProfileWatchpoint: |
| 736 |
case MovHint: |
742 |
case MovHint: |
| 737 |
case ZombieHint: |
743 |
case ZombieHint: |
|
|
744 |
case PhantomNewObject: |
| 745 |
case PutByOffsetHint: |
| 746 |
case PutStructureHint: |
| 738 |
break; |
747 |
break; |
| 739 |
default: |
748 |
default: |
| 740 |
DFG_CRASH(m_graph, m_node, "Unrecognized node in FTL backend"); |
749 |
DFG_CRASH(m_graph, m_node, "Unrecognized node in FTL backend"); |
|
Lines 1704-1733
private:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec3
|
| 1704 |
|
1713 |
|
| 1705 |
LValue structureID = m_out.load32(cell, m_heaps.JSCell_structureID); |
1714 |
LValue structureID = m_out.load32(cell, m_heaps.JSCell_structureID); |
| 1706 |
|
1715 |
|
| 1707 |
if (m_node->structureSet().size() == 1) { |
1716 |
checkStructure(structureID, jsValueValue(cell), exitKind, node->structureSet()); |
| 1708 |
speculate( |
|
|
| 1709 |
exitKind, jsValueValue(cell), 0, |
| 1710 |
m_out.notEqual(structureID, weakStructure(m_node->structureSet()[0]))); |
| 1711 |
return; |
| 1712 |
} |
| 1713 |
|
| 1714 |
LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("CheckStructure continuation")); |
| 1715 |
|
| 1716 |
LBasicBlock lastNext = m_out.insertNewBlocksBefore(continuation); |
| 1717 |
for (unsigned i = 0; i < m_node->structureSet().size() - 1; ++i) { |
| 1718 |
LBasicBlock nextStructure = FTL_NEW_BLOCK(m_out, ("CheckStructure nextStructure")); |
| 1719 |
m_out.branch( |
| 1720 |
m_out.equal(structureID, weakStructure(m_node->structureSet()[i])), |
| 1721 |
unsure(continuation), unsure(nextStructure)); |
| 1722 |
m_out.appendTo(nextStructure); |
| 1723 |
} |
| 1724 |
|
| 1725 |
speculate( |
| 1726 |
exitKind, jsValueValue(cell), 0, |
| 1727 |
m_out.notEqual(structureID, weakStructure(m_node->structureSet().last()))); |
| 1728 |
|
| 1729 |
m_out.jump(continuation); |
| 1730 |
m_out.appendTo(continuation, lastNext); |
| 1731 |
} |
1717 |
} |
| 1732 |
|
1718 |
|
| 1733 |
void compileCheckCell() |
1719 |
void compileCheckCell() |
|
Lines 2649-2676
private:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec4
|
| 2649 |
|
2635 |
|
| 2650 |
void compileNewObject() |
2636 |
void compileNewObject() |
| 2651 |
{ |
2637 |
{ |
| 2652 |
Structure* structure = m_node->structure(); |
2638 |
setJSValue(allocateObject(m_node->structure())); |
| 2653 |
size_t allocationSize = JSFinalObject::allocationSize(structure->inlineCapacity()); |
|
|
| 2654 |
MarkedAllocator* allocator = &vm().heap.allocatorForObjectWithoutDestructor(allocationSize); |
| 2655 |
|
| 2656 |
LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("NewObject slow path")); |
| 2657 |
LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("NewObject continuation")); |
| 2658 |
|
| 2659 |
LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath); |
| 2660 |
|
| 2661 |
ValueFromBlock fastResult = m_out.anchor(allocateObject( |
| 2662 |
m_out.constIntPtr(allocator), structure, m_out.intPtrZero, slowPath)); |
| 2663 |
|
| 2664 |
m_out.jump(continuation); |
| 2665 |
|
| 2666 |
m_out.appendTo(slowPath, continuation); |
| 2667 |
|
| 2668 |
ValueFromBlock slowResult = m_out.anchor(vmCall( |
| 2669 |
m_out.operation(operationNewObject), m_callFrame, m_out.constIntPtr(structure))); |
| 2670 |
m_out.jump(continuation); |
| 2671 |
|
| 2672 |
m_out.appendTo(continuation, lastNext); |
| 2673 |
setJSValue(m_out.phi(m_out.intPtr, fastResult, slowResult)); |
| 2674 |
} |
2639 |
} |
| 2675 |
|
2640 |
|
| 2676 |
void compileNewArray() |
2641 |
void compileNewArray() |
|
Lines 3370-3376
private:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec5
|
| 3370 |
LBasicBlock lastNext = m_out.m_nextBlock; |
3335 |
LBasicBlock lastNext = m_out.m_nextBlock; |
| 3371 |
|
3336 |
|
| 3372 |
for (unsigned i = data.variants.size(); i--;) { |
3337 |
for (unsigned i = data.variants.size(); i--;) { |
| 3373 |
m_out.appendTo(blocks[i], i + 1 < data.variants.size() ? blocks[i + 1] : exit); |
3338 |
m_out.appendTo(blocks[i], i + 1 < data.variants.size() ? blocks[i + 1] : exit); |
| 3374 |
|
3339 |
|
| 3375 |
PutByIdVariant variant = data.variants[i]; |
3340 |
PutByIdVariant variant = data.variants[i]; |
| 3376 |
|
3341 |
|
|
Lines 3953-3964
private:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec6
|
| 3953 |
void compileInvalidationPoint() |
3918 |
void compileInvalidationPoint() |
| 3954 |
{ |
3919 |
{ |
| 3955 |
if (verboseCompilationEnabled()) |
3920 |
if (verboseCompilationEnabled()) |
| 3956 |
dataLog(" Invalidation point with availability: ", availability(), "\n"); |
3921 |
dataLog(" Invalidation point with availability: ", availabilityMap(), "\n"); |
| 3957 |
|
3922 |
|
| 3958 |
m_ftlState.jitCode->osrExit.append(OSRExit( |
3923 |
m_ftlState.jitCode->osrExit.append(OSRExit( |
| 3959 |
UncountableInvalidation, InvalidValueFormat, MethodOfGettingAValueProfile(), |
3924 |
UncountableInvalidation, InvalidValueFormat, MethodOfGettingAValueProfile(), |
| 3960 |
m_codeOriginForExitTarget, m_codeOriginForExitProfile, |
3925 |
m_codeOriginForExitTarget, m_codeOriginForExitProfile, |
| 3961 |
availability().numberOfArguments(), availability().numberOfLocals())); |
3926 |
availabilityMap().m_locals.numberOfArguments(), |
|
|
3927 |
availabilityMap().m_locals.numberOfLocals())); |
| 3962 |
m_ftlState.finalizer->osrExit.append(OSRExitCompilationInfo()); |
3928 |
m_ftlState.finalizer->osrExit.append(OSRExitCompilationInfo()); |
| 3963 |
|
3929 |
|
| 3964 |
OSRExit& exit = m_ftlState.jitCode->osrExit.last(); |
3930 |
OSRExit& exit = m_ftlState.jitCode->osrExit.last(); |
|
Lines 4360-4365
private:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec7
|
| 4360 |
LValue index = lowInt32(m_node->child1()); |
4326 |
LValue index = lowInt32(m_node->child1()); |
| 4361 |
setJSValue(vmCall(m_out.operation(operationToIndexString), m_callFrame, index)); |
4327 |
setJSValue(vmCall(m_out.operation(operationToIndexString), m_callFrame, index)); |
| 4362 |
} |
4328 |
} |
|
|
4329 |
|
| 4330 |
void compileCheckStructureImmediate() |
| 4331 |
{ |
| 4332 |
LValue structureID = lowCell(m_nde->child1()); |
| 4333 |
checkStructure(structureID, noValue(), BadCache, node->structureSet()); |
| 4334 |
} |
| 4335 |
|
| 4336 |
void compileMaterializeNewObject() |
| 4337 |
{ |
| 4338 |
ObjectMaterializationData& data = m_node->objectMaterializationData(); |
| 4339 |
|
| 4340 |
StructureSet set; |
| 4341 |
m_interpreter.phiChildren()->forAllTransitiveIncomingValues( |
| 4342 |
m_node, |
| 4343 |
[&] (Node* incoming) { |
| 4344 |
Structure* structure = incoming->dynamicCastConstant<Structure*>(); |
| 4345 |
DFG_ASSERT(m_graph, m_node, structure); |
| 4346 |
set.add(structure); |
| 4347 |
}); |
| 4348 |
|
| 4349 |
Vector<LBasicBlock, 1> blocks(set.size()); |
| 4350 |
for (unsigned i = set.size(); i--;) |
| 4351 |
blocks[i] = FTL_NEW_BLOCK(m_out, ("MaterializeNewObject case ", i)); |
| 4352 |
LBasicBlock dummyDefault = FTL_NEW_BLOCK(m_out, ("MaterializeNewObject default case")); |
| 4353 |
LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("MaterializeNewObject continuation")); |
| 4354 |
|
| 4355 |
Vector<SwitchCase, 1> cases(set.size()); |
| 4356 |
for (unsigned i = set.size(); i--;) |
| 4357 |
cases[i] = SwitchCase(weakStructure(set[i]), blocks[i], Weight(1)); |
| 4358 |
m_out.switchInstruction( |
| 4359 |
lowCell(m_graph.varArgChild(m_node, 0)), cases, dummyDefault, Weight(0)); |
| 4360 |
|
| 4361 |
LBasicBlock outerLastNext = m_out.nextBlock; |
| 4362 |
|
| 4363 |
for (unsigned i = set.size(); i--;) { |
| 4364 |
m_out.appendTo(blocks[i], i + 1 < set.size() ? blocks[i + 1] : dummyDefault); |
| 4365 |
|
| 4366 |
Structure* structure = set[i]; |
| 4367 |
|
| 4368 |
// Find a primordial structure. This is goofy. We don't actually care to find *the* |
| 4369 |
// primordial structure for *this* structure - only one that matches the important |
| 4370 |
// bits, like the inline size, the structure ID blob stuff, and the prototype. |
| 4371 |
Structure* primordialStructure = nullptr; |
| 4372 |
for (Structure* candidatePrimordialStructure : data.m_primordialStructures) { |
| 4373 |
if (candidatePrimordialStructure->canIseForAllocatonsOf(structure)) { |
| 4374 |
primordialStructure = candidatePrimordialStructure; |
| 4375 |
break; |
| 4376 |
} |
| 4377 |
} |
| 4378 |
DFG_ASSERT(m_graph, m_node, primordialStructure); |
| 4379 |
|
| 4380 |
LValue object; |
| 4381 |
LValue butterfly; |
| 4382 |
|
| 4383 |
if (structure->outOfLineCapacity()) { |
| 4384 |
size_t allocationSize = JSFinalObject::allocationSize(primordialStructure->inlineCapacity()); |
| 4385 |
MarkedAllocator* allocator = &vm().heap.allocatorForObjectWithoutDestructor(allocationSize); |
| 4386 |
|
| 4387 |
LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("MaterializeNewObject complex object allocation slow path")); |
| 4388 |
LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("MaterializeNewObject complex object allocation continuation")); |
| 4389 |
|
| 4390 |
LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath); |
| 4391 |
|
| 4392 |
ValueFromBlock fastResult = m_out.anchor(allocateObject( |
| 4393 |
m_out.constIntPtr(allocator), primordialStructure, m_out.intPtrZero, slowPath)); |
| 4394 |
|
| 4395 |
|
| 4396 |
|
| 4397 |
m_out.jump(continuation); |
| 4398 |
|
| 4399 |
m_out.appendTo( |
| 4400 |
} else { |
| 4401 |
// In the easy case where we can do a one-shot allocation, we simply allocate the |
| 4402 |
// object to directly have the desired structure. |
| 4403 |
object = allocateObject(structure); |
| 4404 |
butterfly = nullptr; // Don't have one, don't need one. |
| 4405 |
} |
| 4406 |
} |
| 4407 |
} |
| 4363 |
|
4408 |
|
| 4364 |
#if ENABLE(FTL_NATIVE_CALL_INLINING) |
4409 |
#if ENABLE(FTL_NATIVE_CALL_INLINING) |
| 4365 |
LValue getFunctionBySymbol(const CString symbol) |
4410 |
LValue getFunctionBySymbol(const CString symbol) |
|
Lines 4525-4530
private:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec8
|
| 4525 |
return m_out.booleanFalse; |
4570 |
return m_out.booleanFalse; |
| 4526 |
} |
4571 |
} |
| 4527 |
|
4572 |
|
|
|
4573 |
void checkStructure( |
| 4574 |
LValue structureID, const FormattedValue& formattedValue, ExitKind exitKind, |
| 4575 |
const StructureSet& set) |
| 4576 |
{ |
| 4577 |
if (set.size() == 1) { |
| 4578 |
speculate( |
| 4579 |
exitKind, formattedValue, 0, |
| 4580 |
m_out.notEqual(structureID, weakStructure(set[0]))); |
| 4581 |
return; |
| 4582 |
} |
| 4583 |
|
| 4584 |
LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("checkStructure continuation")); |
| 4585 |
|
| 4586 |
LBasicBlock lastNext = m_out.insertNewBlocksBefore(continuation); |
| 4587 |
for (unsigned i = 0; i < set.size() - 1; ++i) { |
| 4588 |
LBasicBlock nextStructure = FTL_NEW_BLOCK(m_out, ("checkStructure nextStructure")); |
| 4589 |
m_out.branch( |
| 4590 |
m_out.equal(structureID, weakStructure(set[i])), |
| 4591 |
unsure(continuation), unsure(nextStructure)); |
| 4592 |
m_out.appendTo(nextStructure); |
| 4593 |
} |
| 4594 |
|
| 4595 |
speculate( |
| 4596 |
exitKind, formattedValue, 0, |
| 4597 |
m_out.notEqual(structureID, weakStructure(set.last()))); |
| 4598 |
|
| 4599 |
m_out.jump(continuation); |
| 4600 |
m_out.appendTo(continuation, lastNext); |
| 4601 |
} |
| 4602 |
|
| 4528 |
LValue numberOrNotCellToInt32(Edge edge, LValue value) |
4603 |
LValue numberOrNotCellToInt32(Edge edge, LValue value) |
| 4529 |
{ |
4604 |
{ |
| 4530 |
LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("ValueToInt32 int case")); |
4605 |
LBasicBlock intCase = FTL_NEW_BLOCK(m_out, ("ValueToInt32 int case")); |
|
Lines 4624-4707
private:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec9
|
| 4624 |
m_callFrame, object); |
4699 |
m_callFrame, object); |
| 4625 |
} |
4700 |
} |
| 4626 |
|
4701 |
|
| 4627 |
LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("allocatePropertyStorage slow path")); |
4702 |
LValue result = allocatePropertyStorageWithSizeImpl(initialOutOfLineCapacity); |
| 4628 |
LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("allocatePropertyStorage continuation")); |
|
|
| 4629 |
|
| 4630 |
LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath); |
| 4631 |
|
| 4632 |
LValue endOfStorage = allocateBasicStorageAndGetEnd( |
| 4633 |
m_out.constIntPtr(initialOutOfLineCapacity * sizeof(JSValue)), slowPath); |
| 4634 |
|
| 4635 |
ValueFromBlock fastButterfly = m_out.anchor( |
| 4636 |
m_out.add(m_out.constIntPtr(sizeof(IndexingHeader)), endOfStorage)); |
| 4637 |
|
| 4638 |
m_out.jump(continuation); |
| 4639 |
|
| 4640 |
m_out.appendTo(slowPath, continuation); |
| 4641 |
|
| 4642 |
ValueFromBlock slowButterfly = m_out.anchor(vmCall( |
| 4643 |
m_out.operation(operationAllocatePropertyStorageWithInitialCapacity), m_callFrame)); |
| 4644 |
|
| 4645 |
m_out.jump(continuation); |
| 4646 |
|
| 4647 |
m_out.appendTo(continuation, lastNext); |
| 4648 |
|
| 4649 |
LValue result = m_out.phi(m_out.intPtr, fastButterfly, slowButterfly); |
| 4650 |
m_out.storePtr(result, object, m_heaps.JSObject_butterfly); |
4703 |
m_out.storePtr(result, object, m_heaps.JSObject_butterfly); |
| 4651 |
|
|
|
| 4652 |
return result; |
4704 |
return result; |
| 4653 |
} |
4705 |
} |
| 4654 |
|
4706 |
|
| 4655 |
LValue reallocatePropertyStorage( |
4707 |
LValue reallocatePropertyStorage( |
| 4656 |
LValue object, LValue oldStorage, Structure* previous, Structure* next) |
4708 |
LValue object, LValue oldStorage, Structure* previous, Structure* next) |
| 4657 |
{ |
4709 |
{ |
| 4658 |
size_t oldSize = previous->outOfLineCapacity() * sizeof(JSValue); |
4710 |
size_t oldSize = previous->outOfLineCapacity(); |
| 4659 |
size_t newSize = oldSize * outOfLineGrowthFactor; |
4711 |
size_t newSize = oldSize * outOfLineGrowthFactor; |
| 4660 |
|
4712 |
|
| 4661 |
ASSERT_UNUSED(next, newSize == next->outOfLineCapacity() * sizeof(JSValue)); |
4713 |
ASSERT_UNUSED(next, newSize == next->outOfLineCapacity()); |
| 4662 |
|
4714 |
|
| 4663 |
if (previous->couldHaveIndexingHeader()) { |
4715 |
if (previous->couldHaveIndexingHeader()) { |
| 4664 |
LValue newAllocSize = m_out.constInt64(newSize / sizeof(JSValue)); |
4716 |
LValue newAllocSize = m_out.constIntPtr(newSize); |
| 4665 |
return vmCall(m_out.operation(operationReallocateButterflyToGrowPropertyStorage), m_callFrame, object, newAllocSize); |
4717 |
return vmCall(m_out.operation(operationReallocateButterflyToGrowPropertyStorage), m_callFrame, object, newAllocSize); |
| 4666 |
} |
4718 |
} |
| 4667 |
|
4719 |
|
| 4668 |
LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("reallocatePropertyStorage slow path")); |
4720 |
LValue result = allocatePropertyStorageWithSizeImpl(newSize); |
| 4669 |
LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("reallocatePropertyStorage continuation")); |
4721 |
|
|
|
4722 |
ptrdiff_t headerSize = -sizeof(IndexingHeader) - sizeof(void*); |
| 4723 |
ptrdiff_t endStorage = headerSize - static_cast<ptrdiff_t>(oldSize * sizeof(JSValue)); |
| 4724 |
|
| 4725 |
for (ptrdiff_t offset = headerSize; offset > endStorage; offset -= sizeof(void*)) { |
| 4726 |
LValue loaded = |
| 4727 |
m_out.loadPtr(m_out.address(m_heaps.properties.atAnyNumber(), oldStorage, offset)); |
| 4728 |
m_out.storePtr(loaded, m_out.address(m_heaps.properties.atAnyNumber(), result, offset)); |
| 4729 |
} |
| 4730 |
|
| 4731 |
m_out.storePtr(result, m_out.address(object, m_heaps.JSObject_butterfly)); |
| 4732 |
|
| 4733 |
return result; |
| 4734 |
} |
| 4735 |
|
| 4736 |
LValue allocatePropertyStorageWithSizeImpl(size_t sizeInValues) |
| 4737 |
{ |
| 4738 |
LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("allocatePropertyStorageWithSizeImpl slow path")); |
| 4739 |
LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("allocatePropertyStorageWithSizeImpl continuation")); |
| 4740 |
|
| 4670 |
LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath); |
4741 |
LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath); |
| 4671 |
|
4742 |
|
| 4672 |
LValue endOfStorage = |
4743 |
LValue endOfStorage = allocateBasicStorageAndGetEnd( |
| 4673 |
allocateBasicStorageAndGetEnd(m_out.constIntPtr(newSize), slowPath); |
4744 |
m_out.constIntPtr(sizeInValues * sizeof(JSValue)), slowPath); |
| 4674 |
|
4745 |
|
| 4675 |
ValueFromBlock fastButterfly = m_out.anchor(m_out.add(m_out.constIntPtr(sizeof(IndexingHeader)), endOfStorage)); |
4746 |
ValueFromBlock fastButterfly = m_out.anchor( |
|
|
4747 |
m_out.add(m_out.constIntPtr(sizeof(IndexingHeader)), endOfStorage)); |
| 4676 |
|
4748 |
|
| 4677 |
m_out.jump(continuation); |
4749 |
m_out.jump(continuation); |
| 4678 |
|
4750 |
|
| 4679 |
m_out.appendTo(slowPath, continuation); |
4751 |
m_out.appendTo(slowPath, continuation); |
| 4680 |
|
4752 |
|
| 4681 |
LValue newAllocSize = m_out.constInt64(newSize / sizeof(JSValue)); |
4753 |
LValue slowButterflyValue; |
| 4682 |
|
4754 |
if (sizeInValues == initialOutOfLineCapacity) { |
| 4683 |
LValue storageLocation = vmCall(m_out.operation(operationAllocatePropertyStorage), m_callFrame, newAllocSize); |
4755 |
slowButterflyValue = vmCall( |
| 4684 |
|
4756 |
m_out.operation(operationAllocatePropertyStorageWithInitialCapacity), |
| 4685 |
ValueFromBlock slowButterfly = m_out.anchor(storageLocation); |
4757 |
m_callFrame); |
|
|
4758 |
} else { |
| 4759 |
slowButterflyValue = vmCall( |
| 4760 |
m_out.operation(operationAllocatePropertyStorage), |
| 4761 |
m_callFrame, m_out.constIntPtr(sizeInValues)); |
| 4762 |
} |
| 4763 |
ValueFromBlock slowButterfly = m_out.anchor(slowButterflyValue); |
| 4686 |
|
4764 |
|
| 4687 |
m_out.jump(continuation); |
4765 |
m_out.jump(continuation); |
| 4688 |
|
4766 |
|
| 4689 |
m_out.appendTo(continuation, lastNext); |
4767 |
m_out.appendTo(continuation, lastNext); |
| 4690 |
|
4768 |
|
| 4691 |
LValue result = m_out.phi(m_out.intPtr, fastButterfly, slowButterfly); |
4769 |
return m_out.phi(m_out.intPtr, fastButterfly, slowButterfly); |
| 4692 |
|
|
|
| 4693 |
ptrdiff_t headerSize = -sizeof(JSValue) - sizeof(void *); |
| 4694 |
ptrdiff_t endStorage = headerSize - static_cast<ptrdiff_t>(oldSize); |
| 4695 |
|
| 4696 |
for (ptrdiff_t offset = headerSize; offset > endStorage; offset -= sizeof(void*)) { |
| 4697 |
LValue loaded = |
| 4698 |
m_out.loadPtr(m_out.address(m_heaps.properties.atAnyNumber(), oldStorage, offset)); |
| 4699 |
m_out.storePtr(loaded, m_out.address(m_heaps.properties.atAnyNumber(), result, offset)); |
| 4700 |
} |
| 4701 |
|
| 4702 |
m_out.storePtr(result, m_out.address(object, m_heaps.JSObject_butterfly)); |
| 4703 |
|
| 4704 |
return result; |
| 4705 |
} |
4770 |
} |
| 4706 |
|
4771 |
|
| 4707 |
LValue getById(LValue base) |
4772 |
LValue getById(LValue base) |
|
Lines 4841-4847
private:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec10
|
| 4841 |
setBoolean(m_out.phi(m_out.boolean, fastResult, slowResult)); |
4906 |
setBoolean(m_out.phi(m_out.boolean, fastResult, slowResult)); |
| 4842 |
} |
4907 |
} |
| 4843 |
|
4908 |
|
| 4844 |
LValue allocateCell(LValue allocator, Structure* structure, LBasicBlock slowPath) |
4909 |
LValue allocateCell(LValue allocator, LBasicBlock slowPath) |
| 4845 |
{ |
4910 |
{ |
| 4846 |
LBasicBlock success = FTL_NEW_BLOCK(m_out, ("object allocation success")); |
4911 |
LBasicBlock success = FTL_NEW_BLOCK(m_out, ("object allocation success")); |
| 4847 |
|
4912 |
|
|
Lines 4856-4867
private:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec11
|
| 4856 |
m_out.loadPtr(result, m_heaps.JSCell_freeListNext), |
4921 |
m_out.loadPtr(result, m_heaps.JSCell_freeListNext), |
| 4857 |
allocator, m_heaps.MarkedAllocator_freeListHead); |
4922 |
allocator, m_heaps.MarkedAllocator_freeListHead); |
| 4858 |
|
4923 |
|
|
|
4924 |
return result; |
| 4925 |
} |
| 4926 |
|
| 4927 |
void storeStructure(LValue object, Structure* structure) |
| 4928 |
{ |
| 4859 |
m_out.store32(m_out.constInt32(structure->id()), result, m_heaps.JSCell_structureID); |
4929 |
m_out.store32(m_out.constInt32(structure->id()), result, m_heaps.JSCell_structureID); |
| 4860 |
|
|
|
| 4861 |
m_out.store32( |
4930 |
m_out.store32( |
| 4862 |
m_out.constInt32(structure->objectInitializationBlob()), |
4931 |
m_out.constInt32(structure->objectInitializationBlob()), |
| 4863 |
result, m_heaps.JSCell_usefulBytes); |
4932 |
result, m_heaps.JSCell_usefulBytes); |
| 4864 |
|
4933 |
} |
|
|
4934 |
|
| 4935 |
LValue allocateCell(LValue allocator, Structure* structure, LBasicBlock slowPath) |
| 4936 |
{ |
| 4937 |
LValue result = allocateCell(allocator, slowPath); |
| 4938 |
storeStructure(result, structure); |
| 4865 |
return result; |
4939 |
return result; |
| 4866 |
} |
4940 |
} |
| 4867 |
|
4941 |
|
|
Lines 4908-4913
private:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec12
|
| 4908 |
m_out.loadPtr(m_out.absolute(&allocator.m_currentPayloadEnd)), newRemaining); |
4982 |
m_out.loadPtr(m_out.absolute(&allocator.m_currentPayloadEnd)), newRemaining); |
| 4909 |
} |
4983 |
} |
| 4910 |
|
4984 |
|
|
|
4985 |
LValue allocateObject(Structure* structure) |
| 4986 |
{ |
| 4987 |
size_t allocationSize = JSFinalObject::allocationSize(structure->inlineCapacity()); |
| 4988 |
MarkedAllocator* allocator = &vm().heap.allocatorForObjectWithoutDestructor(allocationSize); |
| 4989 |
|
| 4990 |
LBasicBlock slowPath = FTL_NEW_BLOCK(m_out, ("allocateObject slow path")); |
| 4991 |
LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("allocateObject continuation")); |
| 4992 |
|
| 4993 |
LBasicBlock lastNext = m_out.insertNewBlocksBefore(slowPath); |
| 4994 |
|
| 4995 |
ValueFromBlock fastResult = m_out.anchor(allocateObject( |
| 4996 |
m_out.constIntPtr(allocator), structure, m_out.intPtrZero, slowPath)); |
| 4997 |
|
| 4998 |
m_out.jump(continuation); |
| 4999 |
|
| 5000 |
m_out.appendTo(slowPath, continuation); |
| 5001 |
|
| 5002 |
ValueFromBlock slowResult = m_out.anchor(vmCall( |
| 5003 |
m_out.operation(operationNewObject), m_callFrame, m_out.constIntPtr(structure))); |
| 5004 |
m_out.jump(continuation); |
| 5005 |
|
| 5006 |
m_out.appendTo(continuation, lastNext); |
| 5007 |
return m_out.phi(m_out.intPtr, fastResult, slowResult); |
| 5008 |
} |
| 5009 |
|
| 4911 |
struct ArrayValues { |
5010 |
struct ArrayValues { |
| 4912 |
ArrayValues() |
5011 |
ArrayValues() |
| 4913 |
: array(0) |
5012 |
: array(0) |
|
Lines 6344-6350
private:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec13
|
| 6344 |
ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition) |
6443 |
ExitKind kind, FormattedValue lowValue, Node* highValue, LValue failCondition) |
| 6345 |
{ |
6444 |
{ |
| 6346 |
if (verboseCompilationEnabled()) { |
6445 |
if (verboseCompilationEnabled()) { |
| 6347 |
dataLog(" OSR exit #", m_ftlState.jitCode->osrExit.size(), " with availability: ", availability(), "\n"); |
6446 |
dataLog(" OSR exit #", m_ftlState.jitCode->osrExit.size(), " with availability: ", availabilityMap(), "\n"); |
| 6348 |
if (!m_availableRecoveries.isEmpty()) |
6447 |
if (!m_availableRecoveries.isEmpty()) |
| 6349 |
dataLog(" Available recoveries: ", listDump(m_availableRecoveries), "\n"); |
6448 |
dataLog(" Available recoveries: ", listDump(m_availableRecoveries), "\n"); |
| 6350 |
} |
6449 |
} |
|
Lines 6354-6360
private:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec14
|
| 6354 |
m_ftlState.jitCode->osrExit.append(OSRExit( |
6453 |
m_ftlState.jitCode->osrExit.append(OSRExit( |
| 6355 |
kind, lowValue.format(), m_graph.methodOfGettingAValueProfileFor(highValue), |
6454 |
kind, lowValue.format(), m_graph.methodOfGettingAValueProfileFor(highValue), |
| 6356 |
m_codeOriginForExitTarget, m_codeOriginForExitProfile, |
6455 |
m_codeOriginForExitTarget, m_codeOriginForExitProfile, |
| 6357 |
availability().numberOfArguments(), availability().numberOfLocals())); |
6456 |
availabilityMap().m_locals.numberOfArguments(), |
|
|
6457 |
availabilityMap().m_locals.numberOfLocals())); |
| 6358 |
m_ftlState.finalizer->osrExit.append(OSRExitCompilationInfo()); |
6458 |
m_ftlState.finalizer->osrExit.append(OSRExitCompilationInfo()); |
| 6359 |
|
6459 |
|
| 6360 |
OSRExit& exit = m_ftlState.jitCode->osrExit.last(); |
6460 |
OSRExit& exit = m_ftlState.jitCode->osrExit.last(); |
|
Lines 6394-6449
private:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec15
|
| 6394 |
if (!!lowValue) |
6494 |
if (!!lowValue) |
| 6395 |
arguments.append(lowValue.value()); |
6495 |
arguments.append(lowValue.value()); |
| 6396 |
|
6496 |
|
|
|
6497 |
AvailabilityMap availabilityMap = availabilityMap(); |
| 6498 |
|
| 6397 |
for (unsigned i = 0; i < exit.m_values.size(); ++i) { |
6499 |
for (unsigned i = 0; i < exit.m_values.size(); ++i) { |
| 6398 |
int operand = exit.m_values.operandForIndex(i); |
6500 |
int operand = exit.m_values.operandForIndex(i); |
| 6399 |
bool isLive = m_graph.isLiveInBytecode(VirtualRegister(operand), codeOrigin); |
6501 |
if (!m_graph.isLiveInBytecode(VirtualRegister(operand), codeOrigin)) |
| 6400 |
if (!isLive) { |
6502 |
availabilityMap.m_locals[i] = Availability(); |
| 6401 |
exit.m_values[i] = ExitValue::dead(); |
6503 |
} |
| 6402 |
continue; |
6504 |
|
| 6403 |
} |
6505 |
availabilityMap.prune(); |
| 6404 |
|
6506 |
|
| 6405 |
Availability availability = this->availability()[i]; |
6507 |
HashMap<Node*, ExitTimeObjectMaterialization*> map; |
| 6406 |
FlushedAt flush = availability.flushedAt(); |
6508 |
availabilityMap.forEachAvailability( |
| 6407 |
switch (flush.format()) { |
6509 |
[&] (Availability availability) { |
| 6408 |
case DeadFlush: |
6510 |
if (!availability.shouldUseNode()) |
| 6409 |
case ConflictingFlush: |
6511 |
return; |
| 6410 |
if (availability.hasNode()) { |
|
|
| 6411 |
exit.m_values[i] = exitValueForNode(arguments, availability.node()); |
| 6412 |
break; |
| 6413 |
} |
| 6414 |
|
| 6415 |
if (Options::validateFTLOSRExitLiveness()) |
| 6416 |
DFG_CRASH(m_graph, m_node, toCString("Expected r", operand, " to be available but it wasn't.").data()); |
| 6417 |
|
| 6418 |
// This means that the DFG's DCE proved that the value is dead in bytecode |
| 6419 |
// even though the bytecode liveness analysis thinks it's live. This is |
| 6420 |
// acceptable since the DFG's DCE is by design more aggressive while still |
| 6421 |
// being sound. |
| 6422 |
exit.m_values[i] = ExitValue::dead(); |
| 6423 |
break; |
| 6424 |
|
| 6425 |
case FlushedJSValue: |
| 6426 |
case FlushedCell: |
| 6427 |
case FlushedBoolean: |
| 6428 |
exit.m_values[i] = ExitValue::inJSStack(flush.virtualRegister()); |
| 6429 |
break; |
| 6430 |
|
| 6431 |
case FlushedInt32: |
| 6432 |
exit.m_values[i] = ExitValue::inJSStackAsInt32(flush.virtualRegister()); |
| 6433 |
break; |
| 6434 |
|
| 6435 |
case FlushedInt52: |
| 6436 |
exit.m_values[i] = ExitValue::inJSStackAsInt52(flush.virtualRegister()); |
| 6437 |
break; |
| 6438 |
|
6512 |
|
| 6439 |
case FlushedDouble: |
6513 |
Node* node = availability.node(); |
| 6440 |
exit.m_values[i] = ExitValue::inJSStackAsDouble(flush.virtualRegister()); |
6514 |
if (!node->isPhantomObjectAllocation()) |
| 6441 |
break; |
6515 |
return; |
| 6442 |
|
6516 |
|
| 6443 |
case FlushedArguments: |
6517 |
auto result = map.add(node, nullptr); |
| 6444 |
exit.m_values[i] = ExitValue::argumentsObjectThatWasNotCreated(); |
6518 |
if (result.isNewEntry) |
| 6445 |
break; |
6519 |
result.iterator->value = exit.m_materializations.add(node->op()); |
|
|
6520 |
}); |
| 6521 |
|
| 6522 |
for (unsigned i = 0; i < exit.m_values.size(); ++i) { |
| 6523 |
int operand = exit.m_values.operandForIndex(i); |
| 6524 |
|
| 6525 |
Availability availability = this->availabilityMap().m_locals[i]; |
| 6526 |
|
| 6527 |
if (Options::validateFTLOSRExitLiveness()) { |
| 6528 |
DFG_ASSERT( |
| 6529 |
m_graph, m_node, |
| 6530 |
m_graph.isLiveInBytecode(VirtualRegister(operand), codeOrigin) |
| 6531 |
== availability.isDead()); |
| 6446 |
} |
6532 |
} |
|
|
6533 |
|
| 6534 |
exit.m_values[i] = exitValueForAvailability(arguments, map, availability); |
| 6535 |
} |
| 6536 |
|
| 6537 |
for (auto heapPair : availabilityMap.m_heap) { |
| 6538 |
Node* node = heapPair.key.base(); |
| 6539 |
ExitTimeObjectMaterialization* materialization = map.get(node); |
| 6540 |
materialization->add( |
| 6541 |
heapPair.key.baseless(), |
| 6542 |
exitValueForAvailability(arguments, map, heapPair.value)); |
| 6447 |
} |
6543 |
} |
| 6448 |
|
6544 |
|
| 6449 |
if (verboseCompilationEnabled()) |
6545 |
if (verboseCompilationEnabled()) |
|
Lines 6459-6471
private:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec16
|
| 6459 |
m_out.call(m_out.stackmapIntrinsic(), arguments); |
6555 |
m_out.call(m_out.stackmapIntrinsic(), arguments); |
| 6460 |
} |
6556 |
} |
| 6461 |
|
6557 |
|
| 6462 |
ExitValue exitValueForNode(ExitArgumentList& arguments, Node* node) |
6558 |
ExitValue exitValueForAvailability( |
|
|
6559 |
ExitArgumentList& arguments, const HashMap<Node*, ExitTimeObjectMaterialization*>& map, |
| 6560 |
Availability availability) |
| 6561 |
{ |
| 6562 |
FlushedAt flush = availability.flushedAt(); |
| 6563 |
switch (flush.format()) { |
| 6564 |
case DeadFlush: |
| 6565 |
case ConflictingFlush: |
| 6566 |
if (availability.hasNode()) |
| 6567 |
return exitValueForNode(arguments, map, availability.node()); |
| 6568 |
|
| 6569 |
// This means that the value is dead. It could be dead in bytecode or it could have |
| 6570 |
// been killed by our DCE, which can sometimes kill things even if they were live in |
| 6571 |
// bytecode. |
| 6572 |
return ExitValue::dead(); |
| 6573 |
|
| 6574 |
case FlushedJSValue: |
| 6575 |
case FlushedCell: |
| 6576 |
case FlushedBoolean: |
| 6577 |
return ExitValue::inJSStack(flush.virtualRegister()); |
| 6578 |
|
| 6579 |
case FlushedInt32: |
| 6580 |
return ExitValue::inJSStackAsInt32(flush.virtualRegister()); |
| 6581 |
|
| 6582 |
case FlushedInt52: |
| 6583 |
return ExitValue::inJSStackAsInt52(flush.virtualRegister()); |
| 6584 |
|
| 6585 |
case FlushedDouble: |
| 6586 |
return ExitValue::inJSStackAsDouble(flush.virtualRegister()); |
| 6587 |
|
| 6588 |
case FlushedArguments: |
| 6589 |
return ExitValue::argumentsObjectThatWasNotCreated(); |
| 6590 |
} |
| 6591 |
|
| 6592 |
DFG_CRASH(m_graph, m_node, "Invalid flush format"); |
| 6593 |
} |
| 6594 |
|
| 6595 |
ExitValue exitValueForNode( |
| 6596 |
ExitArgumentList& arguments, const HashMap<Node*, ExitTimeObjectMaterialization*>& map, |
| 6597 |
Node* node) |
| 6463 |
{ |
6598 |
{ |
| 6464 |
ASSERT(node->shouldGenerate()); |
6599 |
ASSERT(node->shouldGenerate()); |
| 6465 |
ASSERT(node->hasResult()); |
6600 |
ASSERT(node->hasResult()); |
| 6466 |
|
6601 |
|
| 6467 |
if (node) { |
6602 |
if (node) { |
| 6468 |
switch (node->op()) { |
6603 |
switch (node->op()) { |
|
|
6604 |
case BottomValue: |
| 6605 |
// This might arise in object materializations. I actually doubt that it would, |
| 6606 |
// but it seems worthwhile to be conservative. |
| 6607 |
return ExitValue::dead(); |
| 6608 |
|
| 6469 |
case JSConstant: |
6609 |
case JSConstant: |
| 6470 |
case Int52Constant: |
6610 |
case Int52Constant: |
| 6471 |
case DoubleConstant: |
6611 |
case DoubleConstant: |
|
Lines 6474-6479
private:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec17
|
| 6474 |
case PhantomArguments: |
6614 |
case PhantomArguments: |
| 6475 |
return ExitValue::argumentsObjectThatWasNotCreated(); |
6615 |
return ExitValue::argumentsObjectThatWasNotCreated(); |
| 6476 |
|
6616 |
|
|
|
6617 |
case PhantomNewObject: |
| 6618 |
return ExitValue::materializeNewObject(map.get(node)); |
| 6619 |
|
| 6477 |
default: |
6620 |
default: |
| 6478 |
break; |
6621 |
break; |
| 6479 |
} |
6622 |
} |
|
Lines 6721-6727
private:
Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp_sec18
|
| 6721 |
m_out.unreachable(); |
6864 |
m_out.unreachable(); |
| 6722 |
} |
6865 |
} |
| 6723 |
|
6866 |
|
| 6724 |
Operands<Availability>& availability() { return m_availabilityCalculator.m_availability; } |
6867 |
AvailabilityMap& availabilityMap() { return m_availabilityCalculator.m_availability; } |
| 6725 |
|
6868 |
|
| 6726 |
VM& vm() { return m_graph.m_vm; } |
6869 |
VM& vm() { return m_graph.m_vm; } |
| 6727 |
CodeBlock* codeBlock() { return m_graph.m_codeBlock; } |
6870 |
CodeBlock* codeBlock() { return m_graph.m_codeBlock; } |