Index: src/a64/assembler-a64.h |
diff --git a/src/a64/assembler-a64.h b/src/a64/assembler-a64.h |
index a2c93df2ae274bf540e1c41f25c9b09e9d70f6f4..09a8a72014d9c7885266576e35094c6b60926e23 100644 |
--- a/src/a64/assembler-a64.h |
+++ b/src/a64/assembler-a64.h |
@@ -730,7 +730,7 @@ class Assembler : public AssemblerBase { |
void bind(Label* label); |
- // RelocInfo and constant pool ---------------------------------------------- |
+ // RelocInfo and pools ------------------------------------------------------ |
// Record relocation information for current pc_. |
void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); |
@@ -841,6 +841,28 @@ class Assembler : public AssemblerBase { |
void ConstantPoolMarker(uint32_t size); |
void ConstantPoolGuard(); |
+ // Prevent veneer pool emission until EndBlockVeneerPool is called. |
+ // Call to this function can be nested but must be followed by an equal |
+ // number of call to EndBlockConstpool. |
+ void StartBlockVeneerPool(); |
+ |
+ // Resume constant pool emission. Need to be called as many time as |
+ // StartBlockVeneerPool to have an effect. |
+ void EndBlockVeneerPool(); |
+ |
+ bool is_veneer_pool_blocked() const { |
+ return veneer_pool_blocked_nesting_ > 0; |
+ } |
+ |
+ // Block/resume emission of constant pools and veneer pools. |
+ void StartBlockPools() { |
+ StartBlockConstPool(); |
+ StartBlockVeneerPool(); |
+ } |
+ void EndBlockPools() { |
+ EndBlockConstPool(); |
+ EndBlockVeneerPool(); |
+ } |
// Debugging ---------------------------------------------------------------- |
PositionsRecorder* positions_recorder() { return &positions_recorder_; } |
@@ -1718,6 +1740,44 @@ class Assembler : public AssemblerBase { |
// Check if is time to emit a constant pool. |
void CheckConstPool(bool force_emit, bool require_jump); |
+ |
+ // Returns true if we should emit a veneer as soon as possible for a branch |
+ // which can at most reach to specified pc. |
+ bool ShouldEmitVeneer(int max_reachable_pc, |
+ int margin = kVeneerDistanceMargin); |
+ bool ShouldEmitVeneers(int margin = kVeneerDistanceMargin) { |
+ return ShouldEmitVeneer(unresolved_branches_first_limit(), margin); |
+ } |
+ |
+ // The maximum code size generated for a veneer. Currently one branch |
+ // instruction. This is for code size checking purposes, and can be extended |
+ // in the future for example if we decide to add nops between the veneers. |
+ static const int kMaxVeneerCodeSize = 1 * kInstructionSize; |
+ |
+ // Emits veneers for branches that are approaching their maximum range. |
+ // If need_protection is true, the veneers are protected by a branch jumping |
+ // over the code. |
+ void EmitVeneers(bool need_protection, int margin = kVeneerDistanceMargin); |
+ void EmitVeneersGuard(); |
+ // Checks whether veneers need to be emitted at this point. |
+ void CheckVeneerPool(bool require_jump, int margin = kVeneerDistanceMargin); |
+ |
+ |
+ class BlockPoolsScope { |
+ public: |
+ explicit BlockPoolsScope(Assembler* assem) : assem_(assem) { |
+ assem_->StartBlockPools(); |
+ } |
+ ~BlockPoolsScope() { |
+ assem_->EndBlockPools(); |
+ } |
+ |
+ private: |
+ Assembler* assem_; |
+ |
+ DISALLOW_IMPLICIT_CONSTRUCTORS(BlockPoolsScope); |
+ }; |
+ |
// Available for constrained code generation scopes. Prefer |
// MacroAssembler::Mov() when possible. |
inline void LoadRelocated(const CPURegister& rt, const Operand& operand); |
@@ -1903,8 +1963,8 @@ class Assembler : public AssemblerBase { |
void GrowBuffer(); |
void CheckBuffer(); |
- // Pc offset of the next buffer check. |
- int next_buffer_check_; |
+ // Pc offset of the next constant pool check. |
+ int next_constant_pool_check_; |
// Constant pool generation |
// Pools are emitted in the instruction stream, preferably after unconditional |
@@ -1920,15 +1980,16 @@ class Assembler : public AssemblerBase { |
// expensive. By default we only check again once a number of instructions |
// has been generated. That also means that the sizing of the buffers is not |
// an exact science, and that we rely on some slop to not overrun buffers. |
- static const int kCheckPoolIntervalInst = 128; |
- static const int kCheckPoolInterval = |
- kCheckPoolIntervalInst * kInstructionSize; |
+ static const int kCheckConstPoolIntervalInst = 128; |
+ static const int kCheckConstPoolInterval = |
+ kCheckConstPoolIntervalInst * kInstructionSize; |
// Constants in pools are accessed via pc relative addressing, which can |
// reach +/-4KB thereby defining a maximum distance between the instruction |
// and the accessed constant. |
- static const int kMaxDistToPool = 4 * KB; |
- static const int kMaxNumPendingRelocInfo = kMaxDistToPool / kInstructionSize; |
+ static const int kMaxDistToConstPool = 4 * KB; |
+ static const int kMaxNumPendingRelocInfo = |
+ kMaxDistToConstPool / kInstructionSize; |
// Average distance beetween a constant pool and the first instruction |
@@ -1936,7 +1997,8 @@ class Assembler : public AssemblerBase { |
// pollution. |
// In practice the distance will be smaller since constant pool emission is |
// forced after function return and sometimes after unconditional branches. |
- static const int kAvgDistToPool = kMaxDistToPool - kCheckPoolInterval; |
+ static const int kAvgDistToConstPool = |
+ kMaxDistToConstPool - kCheckConstPoolInterval; |
// Emission of the constant pool may be blocked in some code sequences. |
int const_pool_blocked_nesting_; // Block emission if this is not zero. |
@@ -1946,6 +2008,9 @@ class Assembler : public AssemblerBase { |
// since the previous constant pool was emitted. |
int first_const_pool_use_; |
+ // Emission of the veneer pools may be blocked in some code sequences. |
+ int veneer_pool_blocked_nesting_; // Block emission if this is not zero. |
+ |
// Relocation info generation |
// Each relocation is encoded as a variable size value |
static const int kMaxRelocSize = RelocInfoWriter::kMaxSize; |
@@ -2013,6 +2078,25 @@ class Assembler : public AssemblerBase { |
// pc_offset() for convenience. |
std::multimap<int, FarBranchInfo> unresolved_branches_; |
+ // We generate a veneer for a branch if we reach within this distance of the |
+ // limit of the range. |
+ static const int kVeneerDistanceMargin = 1 * KB; |
+ // The factor of 2 is a finger in the air guess. With a default margin of |
+ // 1KB, that leaves us an addional 256 instructions to avoid generating a |
+ // protective branch. |
+ static const int kVeneerNoProtectionFactor = 2; |
+ static const int kVeneerDistanceCheckMargin = |
+ kVeneerNoProtectionFactor * kVeneerDistanceMargin; |
+ int unresolved_branches_first_limit() const { |
+ ASSERT(!unresolved_branches_.empty()); |
+ return unresolved_branches_.begin()->first; |
+ } |
+ // This is similar to next_constant_pool_check_ and helps reduce the overhead |
+ // of checking for veneer pools. |
+ // It is maintained to the closest unresolved branch limit minus the maximum |
+ // veneer margin (or kMaxInt if there are no unresolved branches). |
+ int next_veneer_pool_check_; |
+ |
private: |
// If a veneer is emitted for a branch instruction, that instruction must be |
// removed from the associated label's link chain so that the assembler does |
@@ -2021,14 +2105,6 @@ class Assembler : public AssemblerBase { |
void DeleteUnresolvedBranchInfoForLabel(Label* label); |
private: |
- // TODO(jbramley): VIXL uses next_literal_pool_check_ and |
- // literal_pool_monitor_ to determine when to consider emitting a literal |
- // pool. V8 doesn't use them, so they should either not be here at all, or |
- // should replace or be merged with next_buffer_check_ and |
- // const_pool_blocked_nesting_. |
- Instruction* next_literal_pool_check_; |
- unsigned literal_pool_monitor_; |
- |
PositionsRecorder positions_recorder_; |
friend class PositionsRecorder; |
friend class EnsureSpace; |