| Index: src/arm64/assembler-arm64.h
|
| diff --git a/src/arm64/assembler-arm64.h b/src/arm64/assembler-arm64.h
|
| index c0ad4d053b184141221b70363592a6ee104dde01..b2e44a865fccbc84b7917fa3870f74e2bc700ae1 100644
|
| --- a/src/arm64/assembler-arm64.h
|
| +++ b/src/arm64/assembler-arm64.h
|
| @@ -6,6 +6,7 @@
|
| #define V8_ARM64_ASSEMBLER_ARM64_H_
|
|
|
| #include <list>
|
| +#include <vector>
|
| #include <map>
|
|
|
| #include "src/cpu.h"
|
| @@ -740,6 +741,55 @@ class MemOperand {
|
| };
|
|
|
|
|
| +class ConstPool {
|
| + public:
|
| + explicit ConstPool(Assembler* assm)
|
| + : assm_(assm),
|
| + first_use_(-1),
|
| + shared_entries_count(0) {}
|
| + void RecordEntry(intptr_t data, RelocInfo::Mode mode);
|
| + int EntryCount() const {
|
| + return shared_entries_count + unique_entries_.size();
|
| + }
|
| + bool IsEmpty() const {
|
| + return shared_entries_.empty() && unique_entries_.empty();
|
| + }
|
| + // Distance in bytes between the current pc and the first instruction
|
| + // using the pool. If there are no pending entries return kMaxInt.
|
| + int DistanceToFirstUse();
|
| + // Offset after which instructions using the pool will be out of range.
|
| + int MaxPcOffset();
|
| + // Maximum size the constant pool can be with current entries. It always
|
| + // includes alignment padding and branch over.
|
| + int WorstCaseSize();
|
| + // Size in bytes of the literal pool *if* it is emitted at the current
|
| + // pc. The size will include the branch over the pool if it was requested.
|
| + int SizeIfEmittedAtCurrentPc(bool require_jump);
|
| + // Emit the literal pool at the current pc with a branch over the pool if
|
| + // requested.
|
| + void Emit(bool require_jump);
|
| + // Discard any pending pool entries.
|
| + void Clear();
|
| +
|
| + private:
|
| + bool CanBeShared(RelocInfo::Mode mode);
|
| + void EmitMarker();
|
| + void EmitGuard();
|
| + void EmitEntries();
|
| +
|
| + Assembler* assm_;
|
| + // Keep track of the first instruction requiring a constant pool entry
|
| + // since the previous constant pool was emitted.
|
| + int first_use_;
|
| + // values, pc offset(s) of entries which can be shared.
|
| + std::multimap<uint64_t, int> shared_entries_;
|
| + // Number of distinct literal in shared entries.
|
| + int shared_entries_count;
|
| + // values, pc offset of entries which cannot be shared.
|
| + std::vector<std::pair<uint64_t, int> > unique_entries_;
|
| +};
|
| +
|
| +
|
| // -----------------------------------------------------------------------------
|
| // Assembler.
|
|
|
| @@ -763,7 +813,7 @@ class Assembler : public AssemblerBase {
|
| virtual ~Assembler();
|
|
|
| virtual void AbortedCodeGeneration() {
|
| - num_pending_reloc_info_ = 0;
|
| + constpool_.Clear();
|
| }
|
|
|
| // System functions ---------------------------------------------------------
|
| @@ -912,9 +962,7 @@ class Assembler : public AssemblerBase {
|
| static bool IsConstantPoolAt(Instruction* instr);
|
| static int ConstantPoolSizeAt(Instruction* instr);
|
| // See Assembler::CheckConstPool for more info.
|
| - void ConstantPoolMarker(uint32_t size);
|
| void EmitPoolGuard();
|
| - void ConstantPoolGuard();
|
|
|
| // Prevent veneer pool emission until EndBlockVeneerPool is called.
|
| // Call to this function can be nested but must be followed by an equal
|
| @@ -1695,7 +1743,9 @@ class Assembler : public AssemblerBase {
|
|
|
| // Code generation helpers --------------------------------------------------
|
|
|
| - unsigned num_pending_reloc_info() const { return num_pending_reloc_info_; }
|
| + bool IsConstPoolEmpty() const { return constpool_.IsEmpty(); }
|
| +
|
| + Instruction* pc() const { return Instruction::Cast(pc_); }
|
|
|
| Instruction* InstructionAt(int offset) const {
|
| return reinterpret_cast<Instruction*>(buffer_ + offset);
|
| @@ -2019,6 +2069,11 @@ class Assembler : public AssemblerBase {
|
| // instructions.
|
| void BlockConstPoolFor(int instructions);
|
|
|
| + // Set how far from current pc the next constant pool check will be.
|
| + void SetNextConstPoolCheckIn(int instructions) {
|
| + next_constant_pool_check_ = pc_offset() + instructions * kInstructionSize;
|
| + }
|
| +
|
| // Emit the instruction at pc_.
|
| void Emit(Instr instruction) {
|
| STATIC_ASSERT(sizeof(*pc_) == 1);
|
| @@ -2050,12 +2105,13 @@ class Assembler : public AssemblerBase {
|
| int next_constant_pool_check_;
|
|
|
| // Constant pool generation
|
| - // Pools are emitted in the instruction stream, preferably after unconditional
|
| - // jumps or after returns from functions (in dead code locations).
|
| - // If a long code sequence does not contain unconditional jumps, it is
|
| - // necessary to emit the constant pool before the pool gets too far from the
|
| - // location it is accessed from. In this case, we emit a jump over the emitted
|
| - // constant pool.
|
| + // Pools are emitted in the instruction stream. They are emitted when:
|
| + // * the distance to the first use is above a pre-defined distance or
|
| + // * the numbers of entries in the pool is above a pre-defined size or
|
| + // * code generation is finished
|
| + // If a pool needs to be emitted before code generation is finished a branch
|
| + // over the emitted pool will be inserted.
|
| +
|
| // Constants in the pool may be addresses of functions that gets relocated;
|
| // if so, a relocation info entry is associated to the constant pool entry.
|
|
|
| @@ -2063,34 +2119,22 @@ 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 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 kMaxDistToConstPool = 4 * KB;
|
| - static const int kMaxNumPendingRelocInfo =
|
| - kMaxDistToConstPool / kInstructionSize;
|
| -
|
| -
|
| - // Average distance beetween a constant pool and the first instruction
|
| - // accessing the constant pool. Longer distance should result in less I-cache
|
| - // 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 kAvgDistToConstPool =
|
| - kMaxDistToConstPool - kCheckConstPoolInterval;
|
| + static const int kCheckConstPoolInterval = 128;
|
| +
|
| + // Distance to first use after a which a pool will be emitted. Pool entries
|
| + // are accessed with pc relative load therefore this cannot be more than
|
| + // 1 * MB. Since constant pool emission checks are interval based this value
|
| + // is an approximation.
|
| + static const int kApproxMaxDistToConstPool = 64 * KB;
|
| +
|
| + // Number of pool entries after which a pool will be emitted. Since constant
|
| + // pool emission checks are interval based this value is an approximation.
|
| + static const int kApproxMaxPoolEntryCount = 512;
|
|
|
| // Emission of the constant pool may be blocked in some code sequences.
|
| int const_pool_blocked_nesting_; // Block emission if this is not zero.
|
| int no_const_pool_before_; // Block emission before this pc offset.
|
|
|
| - // Keep track of the first instruction requiring a constant pool entry
|
| - // 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.
|
|
|
| @@ -2106,10 +2150,8 @@ class Assembler : public AssemblerBase {
|
| // If every instruction in a long sequence is accessing the pool, we need one
|
| // pending relocation entry per instruction.
|
|
|
| - // the buffer of pending relocation info
|
| - RelocInfo pending_reloc_info_[kMaxNumPendingRelocInfo];
|
| - // number of pending reloc info entries in the buffer
|
| - int num_pending_reloc_info_;
|
| + // The pending constant pool.
|
| + ConstPool constpool_;
|
|
|
| // Relocation for a type-recording IC has the AST id added to it. This
|
| // member variable is a way to pass the information from the call site to
|
| @@ -2196,6 +2238,7 @@ class Assembler : public AssemblerBase {
|
| PositionsRecorder positions_recorder_;
|
| friend class PositionsRecorder;
|
| friend class EnsureSpace;
|
| + friend class ConstPool;
|
| };
|
|
|
| class PatchingAssembler : public Assembler {
|
| @@ -2228,7 +2271,7 @@ class PatchingAssembler : public Assembler {
|
| // Verify we have generated the number of instruction we expected.
|
| ASSERT((pc_offset() + kGap) == buffer_size_);
|
| // Verify no relocation information has been emitted.
|
| - ASSERT(num_pending_reloc_info() == 0);
|
| + ASSERT(IsConstPoolEmpty());
|
| // Flush the Instruction cache.
|
| size_t length = buffer_size_ - kGap;
|
| CPU::FlushICache(buffer_, length);
|
|
|