summaryrefslogtreecommitdiff
path: root/deps/v8/src/assembler.h
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/assembler.h')
-rw-r--r--deps/v8/src/assembler.h373
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_