diff options
Diffstat (limited to 'deps/v8/src/assembler.h')
-rw-r--r-- | deps/v8/src/assembler.h | 373 |
1 files changed, 47 insertions, 326 deletions
diff --git a/deps/v8/src/assembler.h b/deps/v8/src/assembler.h index a2a1c73191..69ab58cdb4 100644 --- a/deps/v8/src/assembler.h +++ b/deps/v8/src/assembler.h @@ -36,20 +36,15 @@ #define V8_ASSEMBLER_H_ #include <forward_list> -#include <iosfwd> -#include <map> -#include "src/allocation.h" -#include "src/code-reference.h" -#include "src/contexts.h" +#include "src/code-comments.h" +#include "src/cpu-features.h" #include "src/deoptimize-reason.h" -#include "src/double.h" #include "src/external-reference.h" #include "src/flags.h" #include "src/globals.h" -#include "src/label.h" +#include "src/handles.h" #include "src/objects.h" -#include "src/register-configuration.h" #include "src/reglist.h" #include "src/reloc-info.h" @@ -97,10 +92,9 @@ class JumpOptimizationInfo { class HeapObjectRequest { public: explicit HeapObjectRequest(double heap_number, int offset = -1); - explicit HeapObjectRequest(CodeStub* code_stub, int offset = -1); explicit HeapObjectRequest(const StringConstantBase* string, int offset = -1); - enum Kind { kHeapNumber, kCodeStub, kStringConstant }; + enum Kind { kHeapNumber, kStringConstant }; Kind kind() const { return kind_; } double heap_number() const { @@ -108,11 +102,6 @@ class HeapObjectRequest { return value_.heap_number; } - CodeStub* code_stub() const { - DCHECK_EQ(kind(), kCodeStub); - return value_.code_stub; - } - const StringConstantBase* string() const { DCHECK_EQ(kind(), kStringConstant); return value_.string; @@ -134,7 +123,6 @@ class HeapObjectRequest { union { double heap_number; - CodeStub* code_stub; const StringConstantBase* string; } value_; @@ -186,9 +174,32 @@ struct V8_EXPORT_PRIVATE AssemblerOptions { Isolate* isolate, bool explicitly_support_serialization = false); }; +class AssemblerBuffer { + public: + virtual ~AssemblerBuffer() = default; + virtual byte* start() const = 0; + virtual int size() const = 0; + // Return a grown copy of this buffer. The contained data is uninitialized. + // The data in {this} will still be read afterwards (until {this} is + // destructed), but not written. + virtual std::unique_ptr<AssemblerBuffer> Grow(int new_size) + V8_WARN_UNUSED_RESULT = 0; +}; + +// Allocate an AssemblerBuffer which uses an existing buffer. This buffer cannot +// grow, so it must be large enough for all code emitted by the Assembler. +V8_EXPORT_PRIVATE +std::unique_ptr<AssemblerBuffer> ExternalAssemblerBuffer(void* buffer, + int size); + +// Allocate a new growable AssemblerBuffer with a given initial size. +V8_EXPORT_PRIVATE +std::unique_ptr<AssemblerBuffer> NewAssemblerBuffer(int size); + class V8_EXPORT_PRIVATE AssemblerBase : public Malloced { public: - AssemblerBase(const AssemblerOptions& options, void* buffer, int buffer_size); + AssemblerBase(const AssemblerOptions& options, + std::unique_ptr<AssemblerBuffer>); virtual ~AssemblerBase(); const AssemblerOptions& options() const { return options_; } @@ -228,11 +239,13 @@ class V8_EXPORT_PRIVATE AssemblerBase : public Malloced { jump_optimization_info_ = jump_opt; } + void FinalizeJumpOptimizationInfo() {} + // Overwrite a host NaN with a quiet target NaN. Used by mksnapshot for // cross-snapshotting. - static void QuietNaN(HeapObject* nan) { } + static void QuietNaN(HeapObject nan) {} - int pc_offset() const { return static_cast<int>(pc_ - buffer_); } + int pc_offset() const { return static_cast<int>(pc_ - buffer_start_); } // This function is called when code generation is aborted, so that // the assembler could clean up internal data structures. @@ -241,6 +254,14 @@ class V8_EXPORT_PRIVATE AssemblerBase : public Malloced { // Debugging void Print(Isolate* isolate); + // Record an inline code comment that can be used by a disassembler. + // Use --code-comments to enable. + void RecordComment(const char* msg) { + if (FLAG_code_comments) { + code_comments_writer_.Add(pc_offset(), std::string(msg)); + } + } + static const int kMinimalBufferSize = 4*KB; static void FlushICache(void* start, size_t size); @@ -248,9 +269,6 @@ class V8_EXPORT_PRIVATE AssemblerBase : public Malloced { return FlushICache(reinterpret_cast<void*>(start), size); } - // Used to print the name of some special registers. - static const char* GetSpecialRegisterName(int code) { return "UNKNOWN"; } - protected: // Add 'target' to the {code_targets_} vector, if necessary, and return the // offset at which it is stored. @@ -259,15 +277,12 @@ class V8_EXPORT_PRIVATE AssemblerBase : public Malloced { // Update to the code target at {code_target_index} to {target}. void UpdateCodeTarget(intptr_t code_target_index, Handle<Code> target); // Reserves space in the code target vector. - void ReserveCodeTargetSpace(size_t num_of_code_targets) { - code_targets_.reserve(num_of_code_targets); - } + void ReserveCodeTargetSpace(size_t num_of_code_targets); - // The buffer into which code and relocation info are generated. It could - // either be owned by the assembler or be provided externally. - byte* buffer_; - int buffer_size_; - bool own_buffer_; + // The buffer into which code and relocation info are generated. + std::unique_ptr<AssemblerBuffer> buffer_; + // Cached from {buffer_->start()}, for faster access. + byte* buffer_start_; std::forward_list<HeapObjectRequest> heap_object_requests_; // The program counter, which points into the buffer above and moves forward. // TODO(jkummerow): This should probably have type {Address}. @@ -299,6 +314,8 @@ class V8_EXPORT_PRIVATE AssemblerBase : public Malloced { return true; } + CodeCommentsWriter code_comments_writer_; + private: // Before we copy code into the code space, we sometimes cannot encode // call/jump code targets as we normally would, as the difference between the @@ -380,302 +397,6 @@ class CpuFeatureScope { #endif }; -// CpuFeatures keeps track of which features are supported by the target CPU. -// Supported features must be enabled by a CpuFeatureScope before use. -// Example: -// if (assembler->IsSupported(SSE3)) { -// CpuFeatureScope fscope(assembler, SSE3); -// // Generate code containing SSE3 instructions. -// } else { -// // Generate alternative code. -// } -class CpuFeatures : public AllStatic { - public: - static void Probe(bool cross_compile) { - STATIC_ASSERT(NUMBER_OF_CPU_FEATURES <= kBitsPerInt); - if (initialized_) return; - initialized_ = true; - ProbeImpl(cross_compile); - } - - static unsigned SupportedFeatures() { - Probe(false); - return supported_; - } - - static bool IsSupported(CpuFeature f) { - return (supported_ & (1u << f)) != 0; - } - - static inline bool SupportsOptimizer(); - - static inline bool SupportsWasmSimd128(); - - static inline unsigned icache_line_size() { - DCHECK_NE(icache_line_size_, 0); - return icache_line_size_; - } - - static inline unsigned dcache_line_size() { - DCHECK_NE(dcache_line_size_, 0); - return dcache_line_size_; - } - - static void PrintTarget(); - static void PrintFeatures(); - - private: - friend class ExternalReference; - friend class AssemblerBase; - // Flush instruction cache. - static void FlushICache(void* start, size_t size); - - // Platform-dependent implementation. - static void ProbeImpl(bool cross_compile); - - static unsigned supported_; - static unsigned icache_line_size_; - static unsigned dcache_line_size_; - static bool initialized_; - DISALLOW_COPY_AND_ASSIGN(CpuFeatures); -}; - -// ----------------------------------------------------------------------------- -// Utility functions - -// Computes pow(x, y) with the special cases in the spec for Math.pow. -double power_helper(double x, double y); -double power_double_int(double x, int y); -double power_double_double(double x, double y); - - -// ----------------------------------------------------------------------------- -// Constant pool support - -class ConstantPoolEntry { - public: - ConstantPoolEntry() = default; - ConstantPoolEntry(int position, intptr_t value, bool sharing_ok, - RelocInfo::Mode rmode = RelocInfo::NONE) - : position_(position), - merged_index_(sharing_ok ? SHARING_ALLOWED : SHARING_PROHIBITED), - value_(value), - rmode_(rmode) {} - ConstantPoolEntry(int position, Double value, - RelocInfo::Mode rmode = RelocInfo::NONE) - : position_(position), - merged_index_(SHARING_ALLOWED), - value64_(value.AsUint64()), - rmode_(rmode) {} - - int position() const { return position_; } - bool sharing_ok() const { return merged_index_ != SHARING_PROHIBITED; } - bool is_merged() const { return merged_index_ >= 0; } - int merged_index() const { - DCHECK(is_merged()); - return merged_index_; - } - void set_merged_index(int index) { - DCHECK(sharing_ok()); - merged_index_ = index; - DCHECK(is_merged()); - } - int offset() const { - DCHECK_GE(merged_index_, 0); - return merged_index_; - } - void set_offset(int offset) { - DCHECK_GE(offset, 0); - merged_index_ = offset; - } - intptr_t value() const { return value_; } - uint64_t value64() const { return value64_; } - RelocInfo::Mode rmode() const { return rmode_; } - - enum Type { INTPTR, DOUBLE, NUMBER_OF_TYPES }; - - static int size(Type type) { - return (type == INTPTR) ? kPointerSize : kDoubleSize; - } - - enum Access { REGULAR, OVERFLOWED }; - - private: - int position_; - int merged_index_; - union { - intptr_t value_; - uint64_t value64_; - }; - // TODO(leszeks): The way we use this, it could probably be packed into - // merged_index_ if size is a concern. - RelocInfo::Mode rmode_; - enum { SHARING_PROHIBITED = -2, SHARING_ALLOWED = -1 }; -}; - - -// ----------------------------------------------------------------------------- -// Embedded constant pool support - -class ConstantPoolBuilder { - public: - ConstantPoolBuilder(int ptr_reach_bits, int double_reach_bits); - - // Add pointer-sized constant to the embedded constant pool - ConstantPoolEntry::Access AddEntry(int position, intptr_t value, - bool sharing_ok) { - ConstantPoolEntry entry(position, value, sharing_ok); - return AddEntry(entry, ConstantPoolEntry::INTPTR); - } - - // Add double constant to the embedded constant pool - ConstantPoolEntry::Access AddEntry(int position, Double value) { - ConstantPoolEntry entry(position, value); - return AddEntry(entry, ConstantPoolEntry::DOUBLE); - } - - // Add double constant to the embedded constant pool - ConstantPoolEntry::Access AddEntry(int position, double value) { - return AddEntry(position, Double(value)); - } - - // Previews the access type required for the next new entry to be added. - ConstantPoolEntry::Access NextAccess(ConstantPoolEntry::Type type) const; - - bool IsEmpty() { - return info_[ConstantPoolEntry::INTPTR].entries.empty() && - info_[ConstantPoolEntry::INTPTR].shared_entries.empty() && - info_[ConstantPoolEntry::DOUBLE].entries.empty() && - info_[ConstantPoolEntry::DOUBLE].shared_entries.empty(); - } - - // Emit the constant pool. Invoke only after all entries have been - // added and all instructions have been emitted. - // Returns position of the emitted pool (zero implies no constant pool). - int Emit(Assembler* assm); - - // Returns the label associated with the start of the constant pool. - // Linking to this label in the function prologue may provide an - // efficient means of constant pool pointer register initialization - // on some architectures. - inline Label* EmittedPosition() { return &emitted_label_; } - - private: - ConstantPoolEntry::Access AddEntry(ConstantPoolEntry& entry, - ConstantPoolEntry::Type type); - void EmitSharedEntries(Assembler* assm, ConstantPoolEntry::Type type); - void EmitGroup(Assembler* assm, ConstantPoolEntry::Access access, - ConstantPoolEntry::Type type); - - struct PerTypeEntryInfo { - PerTypeEntryInfo() : regular_count(0), overflow_start(-1) {} - bool overflow() const { - return (overflow_start >= 0 && - overflow_start < static_cast<int>(entries.size())); - } - int regular_reach_bits; - int regular_count; - int overflow_start; - std::vector<ConstantPoolEntry> entries; - std::vector<ConstantPoolEntry> shared_entries; - }; - - Label emitted_label_; // Records pc_offset of emitted pool - PerTypeEntryInfo info_[ConstantPoolEntry::NUMBER_OF_TYPES]; -}; - -// Base type for CPU Registers. -// -// 1) We would prefer to use an enum for registers, but enum values are -// assignment-compatible with int, which has caused code-generation bugs. -// -// 2) By not using an enum, we are possibly preventing the compiler from -// doing certain constant folds, which may significantly reduce the -// code generated for some assembly instructions (because they boil down -// to a few constants). If this is a problem, we could change the code -// such that we use an enum in optimized mode, and the class in debug -// mode. This way we get the compile-time error checking in debug mode -// and best performance in optimized code. -template <typename SubType, int kAfterLastRegister> -class RegisterBase { - // Internal enum class; used for calling constexpr methods, where we need to - // pass an integral type as template parameter. - enum class RegisterCode : int { kFirst = 0, kAfterLast = kAfterLastRegister }; - - public: - static constexpr int kCode_no_reg = -1; - static constexpr int kNumRegisters = kAfterLastRegister; - - static constexpr SubType no_reg() { return SubType{kCode_no_reg}; } - - template <int code> - static constexpr SubType from_code() { - static_assert(code >= 0 && code < kNumRegisters, "must be valid reg code"); - return SubType{code}; - } - - constexpr operator RegisterCode() const { - return static_cast<RegisterCode>(reg_code_); - } - - template <RegisterCode reg_code> - static constexpr int code() { - static_assert( - reg_code >= RegisterCode::kFirst && reg_code < RegisterCode::kAfterLast, - "must be valid reg"); - return static_cast<int>(reg_code); - } - - template <RegisterCode reg_code> - static constexpr RegList bit() { - return RegList{1} << code<reg_code>(); - } - - static SubType from_code(int code) { - DCHECK_LE(0, code); - DCHECK_GT(kNumRegisters, code); - return SubType{code}; - } - - // Constexpr version (pass registers as template parameters). - template <RegisterCode... reg_codes> - static constexpr RegList ListOf() { - return CombineRegLists(RegisterBase::bit<reg_codes>()...); - } - - // Non-constexpr version (pass registers as method parameters). - template <typename... Register> - static RegList ListOf(Register... regs) { - return CombineRegLists(regs.bit()...); - } - - bool is_valid() const { return reg_code_ != kCode_no_reg; } - - int code() const { - DCHECK(is_valid()); - return reg_code_; - } - - RegList bit() const { return RegList{1} << code(); } - - inline constexpr bool operator==(SubType other) const { - return reg_code_ == other.reg_code_; - } - inline constexpr bool operator!=(SubType other) const { - return reg_code_ != other.reg_code_; - } - - protected: - explicit constexpr RegisterBase(int code) : reg_code_(code) {} - int reg_code_; -}; - -template <typename SubType, int kAfterLastRegister> -inline std::ostream& operator<<(std::ostream& os, - RegisterBase<SubType, kAfterLastRegister> reg) { - return reg.is_valid() ? os << "r" << reg.code() : os << "<invalid reg>"; -} - } // namespace internal } // namespace v8 #endif // V8_ASSEMBLER_H_ |